123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334 |
- /*!
- * Vuetify v3.3.11
- * Forged by John Leider
- * Released under the MIT License.
- */
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) :
- typeof define === 'function' && define.amd ? define(['exports', 'vue'], factory) :
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Vuetify = {}, global.Vue));
- })(this, (function (exports, vue) { 'use strict';
- // Types
- // eslint-disable-line vue/prefer-import-from-vue
- /**
- * Creates a factory function for props definitions.
- * This is used to define props in a composable then override
- * default values in an implementing component.
- *
- * @example Simplified signature
- * (props: Props) => (defaults?: Record<keyof props, any>) => Props
- *
- * @example Usage
- * const makeProps = propsFactory({
- * foo: String,
- * })
- *
- * defineComponent({
- * props: {
- * ...makeProps({
- * foo: 'a',
- * }),
- * },
- * setup (props) {
- * // would be "string | undefined", now "string" because a default has been provided
- * props.foo
- * },
- * }
- */
- function propsFactory(props, source) {
- return defaults => {
- return Object.keys(props).reduce((obj, prop) => {
- const isObjectDefinition = typeof props[prop] === 'object' && props[prop] != null && !Array.isArray(props[prop]);
- const definition = isObjectDefinition ? props[prop] : {
- type: props[prop]
- };
- if (defaults && prop in defaults) {
- obj[prop] = {
- ...definition,
- default: defaults[prop]
- };
- } else {
- obj[prop] = definition;
- }
- if (source && !obj[prop].source) {
- obj[prop].source = source;
- }
- return obj;
- }, {});
- };
- }
- // Utilities
- // Types
- // Composables
- const makeComponentProps = propsFactory({
- class: [String, Array],
- style: {
- type: [String, Array, Object],
- default: null
- }
- }, 'component');
- const IN_BROWSER = typeof window !== 'undefined';
- const SUPPORTS_INTERSECTION = IN_BROWSER && 'IntersectionObserver' in window;
- const SUPPORTS_TOUCH = IN_BROWSER && ('ontouchstart' in window || window.navigator.maxTouchPoints > 0);
- function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
- function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
- function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
- function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
- function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
- function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
- function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
- // Types
- function getNestedValue(obj, path, fallback) {
- const last = path.length - 1;
- if (last < 0) return obj === undefined ? fallback : obj;
- for (let i = 0; i < last; i++) {
- if (obj == null) {
- return fallback;
- }
- obj = obj[path[i]];
- }
- if (obj == null) return fallback;
- return obj[path[last]] === undefined ? fallback : obj[path[last]];
- }
- function deepEqual(a, b) {
- if (a === b) return true;
- if (a instanceof Date && b instanceof Date && a.getTime() !== b.getTime()) {
- // If the values are Date, compare them as timestamps
- return false;
- }
- if (a !== Object(a) || b !== Object(b)) {
- // If the values aren't objects, they were already checked for equality
- return false;
- }
- const props = Object.keys(a);
- if (props.length !== Object.keys(b).length) {
- // Different number of props, don't bother to check
- return false;
- }
- return props.every(p => deepEqual(a[p], b[p]));
- }
- function getObjectValueByPath(obj, path, fallback) {
- // credit: http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key#comment55278413_6491621
- if (obj == null || !path || typeof path !== 'string') return fallback;
- if (obj[path] !== undefined) return obj[path];
- path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
- path = path.replace(/^\./, ''); // strip a leading dot
- return getNestedValue(obj, path.split('.'), fallback);
- }
- function getPropertyFromItem(item, property, fallback) {
- if (property == null) return item === undefined ? fallback : item;
- if (item !== Object(item)) {
- if (typeof property !== 'function') return fallback;
- const value = property(item, fallback);
- return typeof value === 'undefined' ? fallback : value;
- }
- if (typeof property === 'string') return getObjectValueByPath(item, property, fallback);
- if (Array.isArray(property)) return getNestedValue(item, property, fallback);
- if (typeof property !== 'function') return fallback;
- const value = property(item, fallback);
- return typeof value === 'undefined' ? fallback : value;
- }
- function createRange(length) {
- let start = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
- return Array.from({
- length
- }, (v, k) => start + k);
- }
- function convertToUnit(str) {
- let unit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'px';
- if (str == null || str === '') {
- return undefined;
- } else if (isNaN(+str)) {
- return String(str);
- } else if (!isFinite(+str)) {
- return undefined;
- } else {
- return `${Number(str)}${unit}`;
- }
- }
- function isObject(obj) {
- return obj !== null && typeof obj === 'object' && !Array.isArray(obj);
- }
- function refElement(obj) {
- return obj && '$el' in obj ? obj.$el : obj;
- }
- // KeyboardEvent.keyCode aliases
- const keyCodes = Object.freeze({
- enter: 13,
- tab: 9,
- delete: 46,
- esc: 27,
- space: 32,
- up: 38,
- down: 40,
- left: 37,
- right: 39,
- end: 35,
- home: 36,
- del: 46,
- backspace: 8,
- insert: 45,
- pageup: 33,
- pagedown: 34,
- shift: 16
- });
- const keyValues = Object.freeze({
- enter: 'Enter',
- tab: 'Tab',
- delete: 'Delete',
- esc: 'Escape',
- space: 'Space',
- up: 'ArrowUp',
- down: 'ArrowDown',
- left: 'ArrowLeft',
- right: 'ArrowRight',
- end: 'End',
- home: 'Home',
- del: 'Delete',
- backspace: 'Backspace',
- insert: 'Insert',
- pageup: 'PageUp',
- pagedown: 'PageDown',
- shift: 'Shift'
- });
- function keys(o) {
- return Object.keys(o);
- }
- function has(obj, key) {
- return key.every(k => obj.hasOwnProperty(k));
- }
- function pick(obj, paths, exclude) {
- const found = Object.create(null);
- const rest = Object.create(null);
- for (const key in obj) {
- if (paths.some(path => path instanceof RegExp ? path.test(key) : path === key) && !exclude?.some(path => path === key)) {
- found[key] = obj[key];
- } else {
- rest[key] = obj[key];
- }
- }
- return [found, rest];
- }
- function omit(obj, exclude) {
- const clone = {
- ...obj
- };
- exclude.forEach(prop => delete clone[prop]);
- return clone;
- }
- /**
- * Filter attributes that should be applied to
- * the root element of a an input component. Remaining
- * attributes should be passed to the <input> element inside.
- */
- function filterInputAttrs(attrs) {
- return pick(attrs, ['class', 'style', 'id', /^data-/]);
- }
- function wrapInArray(v) {
- return v == null ? [] : Array.isArray(v) ? v : [v];
- }
- function clamp(value) {
- let min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
- let max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
- return Math.max(min, Math.min(max, value));
- }
- function getDecimals(value) {
- const trimmedStr = value.toString().trim();
- return trimmedStr.includes('.') ? trimmedStr.length - trimmedStr.indexOf('.') - 1 : 0;
- }
- function padEnd(str, length) {
- let char = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '0';
- return str + char.repeat(Math.max(0, length - str.length));
- }
- function chunk(str) {
- let size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
- const chunked = [];
- let index = 0;
- while (index < str.length) {
- chunked.push(str.substr(index, size));
- index += size;
- }
- return chunked;
- }
- function humanReadableFileSize(bytes) {
- let base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;
- if (bytes < base) {
- return `${bytes} B`;
- }
- const prefix = base === 1024 ? ['Ki', 'Mi', 'Gi'] : ['k', 'M', 'G'];
- let unit = -1;
- while (Math.abs(bytes) >= base && unit < prefix.length - 1) {
- bytes /= base;
- ++unit;
- }
- return `${bytes.toFixed(1)} ${prefix[unit]}B`;
- }
- function mergeDeep() {
- let source = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
- let arrayFn = arguments.length > 2 ? arguments[2] : undefined;
- const out = {};
- for (const key in source) {
- out[key] = source[key];
- }
- for (const key in target) {
- const sourceProperty = source[key];
- const targetProperty = target[key];
- // Only continue deep merging if
- // both properties are objects
- if (isObject(sourceProperty) && isObject(targetProperty)) {
- out[key] = mergeDeep(sourceProperty, targetProperty, arrayFn);
- continue;
- }
- if (Array.isArray(sourceProperty) && Array.isArray(targetProperty) && arrayFn) {
- out[key] = arrayFn(sourceProperty, targetProperty);
- continue;
- }
- out[key] = targetProperty;
- }
- return out;
- }
- function flattenFragments(nodes) {
- return nodes.map(node => {
- if (node.type === vue.Fragment) {
- return flattenFragments(node.children);
- } else {
- return node;
- }
- }).flat();
- }
- function toKebabCase() {
- let str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
- if (toKebabCase.cache.has(str)) return toKebabCase.cache.get(str);
- const kebab = str.replace(/[^a-z]/gi, '-').replace(/\B([A-Z])/g, '-$1').toLowerCase();
- toKebabCase.cache.set(str, kebab);
- return kebab;
- }
- toKebabCase.cache = new Map();
- function findChildrenWithProvide(key, vnode) {
- if (!vnode || typeof vnode !== 'object') return [];
- if (Array.isArray(vnode)) {
- return vnode.map(child => findChildrenWithProvide(key, child)).flat(1);
- } else if (Array.isArray(vnode.children)) {
- return vnode.children.map(child => findChildrenWithProvide(key, child)).flat(1);
- } else if (vnode.component) {
- if (Object.getOwnPropertySymbols(vnode.component.provides).includes(key)) {
- return [vnode.component];
- } else if (vnode.component.subTree) {
- return findChildrenWithProvide(key, vnode.component.subTree).flat(1);
- }
- }
- return [];
- }
- var _arr = /*#__PURE__*/new WeakMap();
- var _pointer = /*#__PURE__*/new WeakMap();
- class CircularBuffer {
- constructor(size) {
- _classPrivateFieldInitSpec(this, _arr, {
- writable: true,
- value: []
- });
- _classPrivateFieldInitSpec(this, _pointer, {
- writable: true,
- value: 0
- });
- this.size = size;
- }
- push(val) {
- _classPrivateFieldGet(this, _arr)[_classPrivateFieldGet(this, _pointer)] = val;
- _classPrivateFieldSet(this, _pointer, (_classPrivateFieldGet(this, _pointer) + 1) % this.size);
- }
- values() {
- return _classPrivateFieldGet(this, _arr).slice(_classPrivateFieldGet(this, _pointer)).concat(_classPrivateFieldGet(this, _arr).slice(0, _classPrivateFieldGet(this, _pointer)));
- }
- }
- function getEventCoordinates(e) {
- if ('touches' in e) {
- return {
- clientX: e.touches[0].clientX,
- clientY: e.touches[0].clientY
- };
- }
- return {
- clientX: e.clientX,
- clientY: e.clientY
- };
- }
- // Only allow a single return type
- function destructComputed(getter) {
- const refs = vue.reactive({});
- const base = vue.computed(getter);
- vue.watchEffect(() => {
- for (const key in base.value) {
- refs[key] = base.value[key];
- }
- }, {
- flush: 'sync'
- });
- return vue.toRefs(refs);
- }
- /** Array.includes but value can be any type */
- function includes(arr, val) {
- return arr.includes(val);
- }
- const onRE = /^on[^a-z]/;
- const isOn = key => onRE.test(key);
- function eventName(propName) {
- return propName[2].toLowerCase() + propName.slice(3);
- }
- const EventProp = () => [Function, Array];
- function hasEvent(props, name) {
- name = 'on' + vue.capitalize(name);
- return !!(props[name] || props[`${name}Once`] || props[`${name}Capture`] || props[`${name}OnceCapture`] || props[`${name}CaptureOnce`]);
- }
- function callEvent(handler) {
- for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
- args[_key2 - 1] = arguments[_key2];
- }
- if (Array.isArray(handler)) {
- for (const h of handler) {
- h(...args);
- }
- } else if (typeof handler === 'function') {
- handler(...args);
- }
- }
- function focusableChildren(el) {
- let filterByTabIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
- const targets = ['button', '[href]', 'input:not([type="hidden"])', 'select', 'textarea', '[tabindex]'].map(s => `${s}${filterByTabIndex ? ':not([tabindex="-1"])' : ''}:not([disabled])`).join(', ');
- return [...el.querySelectorAll(targets)];
- }
- function getNextElement(elements, location, condition) {
- let _el;
- let idx = elements.indexOf(document.activeElement);
- const inc = location === 'next' ? 1 : -1;
- do {
- idx += inc;
- _el = elements[idx];
- } while ((!_el || _el.offsetParent == null || !(condition?.(_el) ?? true)) && idx < elements.length && idx >= 0);
- return _el;
- }
- function focusChild(el, location) {
- const focusable = focusableChildren(el);
- if (!location) {
- if (el === document.activeElement || !el.contains(document.activeElement)) {
- focusable[0]?.focus();
- }
- } else if (location === 'first') {
- focusable[0]?.focus();
- } else if (location === 'last') {
- focusable.at(-1)?.focus();
- } else if (typeof location === 'number') {
- focusable[location]?.focus();
- } else {
- const _el = getNextElement(focusable, location);
- if (_el) _el.focus();else focusChild(el, location === 'next' ? 'first' : 'last');
- }
- }
- function noop() {}
- /** Returns null if the selector is not supported or we can't check */
- function matchesSelector(el, selector) {
- const supportsSelector = IN_BROWSER && typeof CSS !== 'undefined' && typeof CSS.supports !== 'undefined' && CSS.supports(`selector(${selector})`);
- if (!supportsSelector) return null;
- try {
- return !!el && el.matches(selector);
- } catch (err) {
- return null;
- }
- }
- // Utilities
- const block = ['top', 'bottom'];
- const inline = ['start', 'end', 'left', 'right'];
- /** Parse a raw anchor string into an object */
- function parseAnchor(anchor, isRtl) {
- let [side, align] = anchor.split(' ');
- if (!align) {
- align = includes(block, side) ? 'start' : includes(inline, side) ? 'top' : 'center';
- }
- return {
- side: toPhysical(side, isRtl),
- align: toPhysical(align, isRtl)
- };
- }
- function toPhysical(str, isRtl) {
- if (str === 'start') return isRtl ? 'right' : 'left';
- if (str === 'end') return isRtl ? 'left' : 'right';
- return str;
- }
- function flipSide(anchor) {
- return {
- side: {
- center: 'center',
- top: 'bottom',
- bottom: 'top',
- left: 'right',
- right: 'left'
- }[anchor.side],
- align: anchor.align
- };
- }
- function flipAlign(anchor) {
- return {
- side: anchor.side,
- align: {
- center: 'center',
- top: 'bottom',
- bottom: 'top',
- left: 'right',
- right: 'left'
- }[anchor.align]
- };
- }
- function flipCorner(anchor) {
- return {
- side: anchor.align,
- align: anchor.side
- };
- }
- function getAxis(anchor) {
- return includes(block, anchor.side) ? 'y' : 'x';
- }
- class Box {
- constructor(_ref) {
- let {
- x,
- y,
- width,
- height
- } = _ref;
- this.x = x;
- this.y = y;
- this.width = width;
- this.height = height;
- }
- get top() {
- return this.y;
- }
- get bottom() {
- return this.y + this.height;
- }
- get left() {
- return this.x;
- }
- get right() {
- return this.x + this.width;
- }
- }
- function getOverflow(a, b) {
- return {
- x: {
- before: Math.max(0, b.left - a.left),
- after: Math.max(0, a.right - b.right)
- },
- y: {
- before: Math.max(0, b.top - a.top),
- after: Math.max(0, a.bottom - b.bottom)
- }
- };
- }
- // Utilities
- /** @see https://stackoverflow.com/a/57876601/2074736 */
- function nullifyTransforms(el) {
- const rect = el.getBoundingClientRect();
- const style = getComputedStyle(el);
- const tx = style.transform;
- if (tx) {
- let ta, sx, sy, dx, dy;
- if (tx.startsWith('matrix3d(')) {
- ta = tx.slice(9, -1).split(/, /);
- sx = +ta[0];
- sy = +ta[5];
- dx = +ta[12];
- dy = +ta[13];
- } else if (tx.startsWith('matrix(')) {
- ta = tx.slice(7, -1).split(/, /);
- sx = +ta[0];
- sy = +ta[3];
- dx = +ta[4];
- dy = +ta[5];
- } else {
- return new Box(rect);
- }
- const to = style.transformOrigin;
- const x = rect.x - dx - (1 - sx) * parseFloat(to);
- const y = rect.y - dy - (1 - sy) * parseFloat(to.slice(to.indexOf(' ') + 1));
- const w = sx ? rect.width / sx : el.offsetWidth + 1;
- const h = sy ? rect.height / sy : el.offsetHeight + 1;
- return new Box({
- x,
- y,
- width: w,
- height: h
- });
- } else {
- return new Box(rect);
- }
- }
- function animate(el, keyframes, options) {
- if (typeof el.animate === 'undefined') return {
- finished: Promise.resolve()
- };
- let animation;
- try {
- animation = el.animate(keyframes, options);
- } catch (err) {
- return {
- finished: Promise.resolve()
- };
- }
- if (typeof animation.finished === 'undefined') {
- animation.finished = new Promise(resolve => {
- animation.onfinish = () => {
- resolve(animation);
- };
- });
- }
- return animation;
- }
- // Utilities
- const handlers = new WeakMap();
- function bindProps(el, props) {
- Object.keys(props).forEach(k => {
- if (isOn(k)) {
- const name = eventName(k);
- const handler = handlers.get(el);
- if (props[k] == null) {
- handler?.forEach(v => {
- const [n, fn] = v;
- if (n === name) {
- el.removeEventListener(name, fn);
- handler.delete(v);
- }
- });
- } else if (!handler || ![...handler]?.some(v => v[0] === name && v[1] === props[k])) {
- el.addEventListener(name, props[k]);
- const _handler = handler || new Set();
- _handler.add([name, props[k]]);
- if (!handlers.has(el)) handlers.set(el, _handler);
- }
- } else {
- if (props[k] == null) {
- el.removeAttribute(k);
- } else {
- el.setAttribute(k, props[k]);
- }
- }
- });
- }
- function unbindProps(el, props) {
- Object.keys(props).forEach(k => {
- if (isOn(k)) {
- const name = eventName(k);
- const handler = handlers.get(el);
- handler?.forEach(v => {
- const [n, fn] = v;
- if (n === name) {
- el.removeEventListener(name, fn);
- handler.delete(v);
- }
- });
- } else {
- el.removeAttribute(k);
- }
- });
- }
- /* eslint-disable no-console */
- function consoleWarn(message) {
- vue.warn(`Vuetify: ${message}`);
- }
- function consoleError(message) {
- vue.warn(`Vuetify error: ${message}`);
- }
- function deprecate(original, replacement) {
- replacement = Array.isArray(replacement) ? replacement.slice(0, -1).map(s => `'${s}'`).join(', ') + ` or '${replacement.at(-1)}'` : `'${replacement}'`;
- vue.warn(`[Vuetify UPGRADE] '${original}' is deprecated, use ${replacement} instead.`);
- }
- // Types
- const delta = 0.20689655172413793; // 6÷29
- const cielabForwardTransform = t => t > delta ** 3 ? Math.cbrt(t) : t / (3 * delta ** 2) + 4 / 29;
- const cielabReverseTransform = t => t > delta ? t ** 3 : 3 * delta ** 2 * (t - 4 / 29);
- function fromXYZ$1(xyz) {
- const transform = cielabForwardTransform;
- const transformedY = transform(xyz[1]);
- return [116 * transformedY - 16, 500 * (transform(xyz[0] / 0.95047) - transformedY), 200 * (transformedY - transform(xyz[2] / 1.08883))];
- }
- function toXYZ$1(lab) {
- const transform = cielabReverseTransform;
- const Ln = (lab[0] + 16) / 116;
- return [transform(Ln + lab[1] / 500) * 0.95047, transform(Ln), transform(Ln - lab[2] / 200) * 1.08883];
- }
- // Utilities
- // Types
- // For converting XYZ to sRGB
- const srgbForwardMatrix = [[3.2406, -1.5372, -0.4986], [-0.9689, 1.8758, 0.0415], [0.0557, -0.2040, 1.0570]];
- // Forward gamma adjust
- const srgbForwardTransform = C => C <= 0.0031308 ? C * 12.92 : 1.055 * C ** (1 / 2.4) - 0.055;
- // For converting sRGB to XYZ
- const srgbReverseMatrix = [[0.4124, 0.3576, 0.1805], [0.2126, 0.7152, 0.0722], [0.0193, 0.1192, 0.9505]];
- // Reverse gamma adjust
- const srgbReverseTransform = C => C <= 0.04045 ? C / 12.92 : ((C + 0.055) / 1.055) ** 2.4;
- function fromXYZ(xyz) {
- const rgb = Array(3);
- const transform = srgbForwardTransform;
- const matrix = srgbForwardMatrix;
- // Matrix transform, then gamma adjustment
- for (let i = 0; i < 3; ++i) {
- // Rescale back to [0, 255]
- rgb[i] = Math.round(clamp(transform(matrix[i][0] * xyz[0] + matrix[i][1] * xyz[1] + matrix[i][2] * xyz[2])) * 255);
- }
- return {
- r: rgb[0],
- g: rgb[1],
- b: rgb[2]
- };
- }
- function toXYZ(_ref) {
- let {
- r,
- g,
- b
- } = _ref;
- const xyz = [0, 0, 0];
- const transform = srgbReverseTransform;
- const matrix = srgbReverseMatrix;
- // Rescale from [0, 255] to [0, 1] then adjust sRGB gamma to linear RGB
- r = transform(r / 255);
- g = transform(g / 255);
- b = transform(b / 255);
- // Matrix color space transform
- for (let i = 0; i < 3; ++i) {
- xyz[i] = matrix[i][0] * r + matrix[i][1] * g + matrix[i][2] * b;
- }
- return xyz;
- }
- // Utilities
- // Types
- function isCssColor(color) {
- return !!color && /^(#|var\(--|(rgb|hsl)a?\()/.test(color);
- }
- const cssColorRe = /^(?<fn>(?:rgb|hsl)a?)\((?<values>.+)\)/;
- const mappers = {
- rgb: (r, g, b, a) => ({
- r,
- g,
- b,
- a
- }),
- rgba: (r, g, b, a) => ({
- r,
- g,
- b,
- a
- }),
- hsl: (h, s, l, a) => HSLtoRGB({
- h,
- s,
- l,
- a
- }),
- hsla: (h, s, l, a) => HSLtoRGB({
- h,
- s,
- l,
- a
- }),
- hsv: (h, s, v, a) => HSVtoRGB({
- h,
- s,
- v,
- a
- }),
- hsva: (h, s, v, a) => HSVtoRGB({
- h,
- s,
- v,
- a
- })
- };
- function parseColor(color) {
- if (typeof color === 'number') {
- if (isNaN(color) || color < 0 || color > 0xFFFFFF) {
- // int can't have opacity
- consoleWarn(`'${color}' is not a valid hex color`);
- }
- return {
- r: (color & 0xFF0000) >> 16,
- g: (color & 0xFF00) >> 8,
- b: color & 0xFF
- };
- } else if (typeof color === 'string' && cssColorRe.test(color)) {
- const {
- groups
- } = color.match(cssColorRe);
- const {
- fn,
- values
- } = groups;
- const realValues = values.split(/,\s*/).map(v => {
- if (v.endsWith('%') && ['hsl', 'hsla', 'hsv', 'hsva'].includes(fn)) {
- return parseFloat(v) / 100;
- } else {
- return parseFloat(v);
- }
- });
- return mappers[fn](...realValues);
- } else if (typeof color === 'string') {
- let hex = color.startsWith('#') ? color.slice(1) : color;
- if ([3, 4].includes(hex.length)) {
- hex = hex.split('').map(char => char + char).join('');
- } else if (![6, 8].includes(hex.length)) {
- consoleWarn(`'${color}' is not a valid hex(a) color`);
- }
- const int = parseInt(hex, 16);
- if (isNaN(int) || int < 0 || int > 0xFFFFFFFF) {
- consoleWarn(`'${color}' is not a valid hex(a) color`);
- }
- return HexToRGB(hex);
- } else if (typeof color === 'object') {
- if (has(color, ['r', 'g', 'b'])) {
- return color;
- } else if (has(color, ['h', 's', 'l'])) {
- return HSVtoRGB(HSLtoHSV(color));
- } else if (has(color, ['h', 's', 'v'])) {
- return HSVtoRGB(color);
- }
- }
- throw new TypeError(`Invalid color: ${color == null ? color : String(color) || color.constructor.name}\nExpected #hex, #hexa, rgb(), rgba(), hsl(), hsla(), object or number`);
- }
- /** Converts HSVA to RGBA. Based on formula from https://en.wikipedia.org/wiki/HSL_and_HSV */
- function HSVtoRGB(hsva) {
- const {
- h,
- s,
- v,
- a
- } = hsva;
- const f = n => {
- const k = (n + h / 60) % 6;
- return v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);
- };
- const rgb = [f(5), f(3), f(1)].map(v => Math.round(v * 255));
- return {
- r: rgb[0],
- g: rgb[1],
- b: rgb[2],
- a
- };
- }
- function HSLtoRGB(hsla) {
- return HSVtoRGB(HSLtoHSV(hsla));
- }
- /** Converts RGBA to HSVA. Based on formula from https://en.wikipedia.org/wiki/HSL_and_HSV */
- function RGBtoHSV(rgba) {
- if (!rgba) return {
- h: 0,
- s: 1,
- v: 1,
- a: 1
- };
- const r = rgba.r / 255;
- const g = rgba.g / 255;
- const b = rgba.b / 255;
- const max = Math.max(r, g, b);
- const min = Math.min(r, g, b);
- let h = 0;
- if (max !== min) {
- if (max === r) {
- h = 60 * (0 + (g - b) / (max - min));
- } else if (max === g) {
- h = 60 * (2 + (b - r) / (max - min));
- } else if (max === b) {
- h = 60 * (4 + (r - g) / (max - min));
- }
- }
- if (h < 0) h = h + 360;
- const s = max === 0 ? 0 : (max - min) / max;
- const hsv = [h, s, max];
- return {
- h: hsv[0],
- s: hsv[1],
- v: hsv[2],
- a: rgba.a
- };
- }
- function HSVtoHSL(hsva) {
- const {
- h,
- s,
- v,
- a
- } = hsva;
- const l = v - v * s / 2;
- const sprime = l === 1 || l === 0 ? 0 : (v - l) / Math.min(l, 1 - l);
- return {
- h,
- s: sprime,
- l,
- a
- };
- }
- function HSLtoHSV(hsl) {
- const {
- h,
- s,
- l,
- a
- } = hsl;
- const v = l + s * Math.min(l, 1 - l);
- const sprime = v === 0 ? 0 : 2 - 2 * l / v;
- return {
- h,
- s: sprime,
- v,
- a
- };
- }
- function RGBtoCSS(_ref) {
- let {
- r,
- g,
- b,
- a
- } = _ref;
- return a === undefined ? `rgb(${r}, ${g}, ${b})` : `rgba(${r}, ${g}, ${b}, ${a})`;
- }
- function HSVtoCSS(hsva) {
- return RGBtoCSS(HSVtoRGB(hsva));
- }
- function toHex(v) {
- const h = Math.round(v).toString(16);
- return ('00'.substr(0, 2 - h.length) + h).toUpperCase();
- }
- function RGBtoHex(_ref2) {
- let {
- r,
- g,
- b,
- a
- } = _ref2;
- return `#${[toHex(r), toHex(g), toHex(b), a !== undefined ? toHex(Math.round(a * 255)) : ''].join('')}`;
- }
- function HexToRGB(hex) {
- hex = parseHex(hex);
- let [r, g, b, a] = chunk(hex, 2).map(c => parseInt(c, 16));
- a = a === undefined ? a : a / 255;
- return {
- r,
- g,
- b,
- a
- };
- }
- function HexToHSV(hex) {
- const rgb = HexToRGB(hex);
- return RGBtoHSV(rgb);
- }
- function HSVtoHex(hsva) {
- return RGBtoHex(HSVtoRGB(hsva));
- }
- function parseHex(hex) {
- if (hex.startsWith('#')) {
- hex = hex.slice(1);
- }
- hex = hex.replace(/([^0-9a-f])/gi, 'F');
- if (hex.length === 3 || hex.length === 4) {
- hex = hex.split('').map(x => x + x).join('');
- }
- if (hex.length !== 6) {
- hex = padEnd(padEnd(hex, 6), 8, 'F');
- }
- return hex;
- }
- function lighten(value, amount) {
- const lab = fromXYZ$1(toXYZ(value));
- lab[0] = lab[0] + amount * 10;
- return fromXYZ(toXYZ$1(lab));
- }
- function darken(value, amount) {
- const lab = fromXYZ$1(toXYZ(value));
- lab[0] = lab[0] - amount * 10;
- return fromXYZ(toXYZ$1(lab));
- }
- /**
- * Calculate the relative luminance of a given color
- * @see https://www.w3.org/TR/WCAG20/#relativeluminancedef
- */
- function getLuma(color) {
- const rgb = parseColor(color);
- return toXYZ(rgb)[1];
- }
- /**
- * Returns the contrast ratio (1-21) between two colors.
- * @see https://www.w3.org/TR/WCAG20/#contrast-ratiodef
- */
- function getContrast(first, second) {
- const l1 = getLuma(first);
- const l2 = getLuma(second);
- const light = Math.max(l1, l2);
- const dark = Math.min(l1, l2);
- return (light + 0.05) / (dark + 0.05);
- }
- // Utilities
- // Types
- function useToggleScope(source, fn) {
- let scope;
- function start() {
- scope = vue.effectScope();
- scope.run(() => fn.length ? fn(() => {
- scope?.stop();
- start();
- }) : fn());
- }
- vue.watch(source, active => {
- if (active && !scope) {
- start();
- } else if (!active) {
- scope?.stop();
- scope = undefined;
- }
- }, {
- immediate: true
- });
- vue.onScopeDispose(() => {
- scope?.stop();
- });
- }
- // Composables
- // Types
- const DefaultsSymbol = Symbol.for('vuetify:defaults');
- function createDefaults(options) {
- return vue.ref(options);
- }
- function injectDefaults() {
- const defaults = vue.inject(DefaultsSymbol);
- if (!defaults) throw new Error('[Vuetify] Could not find defaults instance');
- return defaults;
- }
- function provideDefaults(defaults, options) {
- const injectedDefaults = injectDefaults();
- const providedDefaults = vue.ref(defaults);
- const newDefaults = vue.computed(() => {
- const disabled = vue.unref(options?.disabled);
- if (disabled) return injectedDefaults.value;
- const scoped = vue.unref(options?.scoped);
- const reset = vue.unref(options?.reset);
- const root = vue.unref(options?.root);
- let properties = mergeDeep(providedDefaults.value, {
- prev: injectedDefaults.value
- });
- if (scoped) return properties;
- if (reset || root) {
- const len = Number(reset || Infinity);
- for (let i = 0; i <= len; i++) {
- if (!properties || !('prev' in properties)) {
- break;
- }
- properties = properties.prev;
- }
- if (properties && typeof root === 'string' && root in properties) {
- properties = mergeDeep(mergeDeep(properties, {
- prev: properties
- }), properties[root]);
- }
- return properties;
- }
- return properties.prev ? mergeDeep(properties.prev, properties) : properties;
- });
- vue.provide(DefaultsSymbol, newDefaults);
- return newDefaults;
- }
- function propIsDefined(vnode, prop) {
- return typeof vnode.props?.[prop] !== 'undefined' || typeof vnode.props?.[toKebabCase(prop)] !== 'undefined';
- }
- function internalUseDefaults() {
- let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- let name = arguments.length > 1 ? arguments[1] : undefined;
- let defaults = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : injectDefaults();
- const vm = getCurrentInstance('useDefaults');
- name = name ?? vm.type.name ?? vm.type.__name;
- if (!name) {
- throw new Error('[Vuetify] Could not determine component name');
- }
- const componentDefaults = vue.computed(() => defaults.value?.[props._as ?? name]);
- const _props = new Proxy(props, {
- get(target, prop) {
- const propValue = Reflect.get(target, prop);
- if (prop === 'class' || prop === 'style') {
- return [componentDefaults.value?.[prop], propValue].filter(v => v != null);
- } else if (typeof prop === 'string' && !propIsDefined(vm.vnode, prop)) {
- return componentDefaults.value?.[prop] ?? defaults.value?.global?.[prop] ?? propValue;
- }
- return propValue;
- }
- });
- const _subcomponentDefaults = vue.shallowRef();
- vue.watchEffect(() => {
- if (componentDefaults.value) {
- const subComponents = Object.entries(componentDefaults.value).filter(_ref => {
- let [key] = _ref;
- return key.startsWith(key[0].toUpperCase());
- });
- if (subComponents.length) _subcomponentDefaults.value = Object.fromEntries(subComponents);
- }
- });
- function provideSubDefaults() {
- // If subcomponent defaults are provided, override any
- // subcomponents provided by the component's setup function.
- // This uses injectSelf so must be done after the original setup to work.
- useToggleScope(_subcomponentDefaults, () => {
- provideDefaults(mergeDeep(injectSelf(DefaultsSymbol)?.value ?? {}, _subcomponentDefaults.value));
- });
- }
- return {
- props: _props,
- provideSubDefaults
- };
- }
- function useDefaults() {
- let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- let name = arguments.length > 1 ? arguments[1] : undefined;
- const {
- props: _props,
- provideSubDefaults
- } = internalUseDefaults(props, name);
- provideSubDefaults();
- return _props;
- }
- // Composables
- // Types
- // Implementation
- function defineComponent(options) {
- options._setup = options._setup ?? options.setup;
- if (!options.name) {
- consoleWarn('The component is missing an explicit name, unable to generate default prop value');
- return options;
- }
- if (options._setup) {
- options.props = propsFactory(options.props ?? {}, options.name)();
- const propKeys = Object.keys(options.props);
- options.filterProps = function filterProps(props) {
- return pick(props, propKeys, ['class', 'style']);
- };
- options.props._as = String;
- options.setup = function setup(props, ctx) {
- const defaults = injectDefaults();
- // Skip props proxy if defaults are not provided
- if (!defaults.value) return options._setup(props, ctx);
- const {
- props: _props,
- provideSubDefaults
- } = internalUseDefaults(props, props._as ?? options.name, defaults);
- const setupBindings = options._setup(_props, ctx);
- provideSubDefaults();
- return setupBindings;
- };
- }
- return options;
- }
- // Implementation
- function genericComponent() {
- let exposeDefaults = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
- return options => (exposeDefaults ? defineComponent : vue.defineComponent)(options);
- }
- // Composables
- function createSimpleFunctional(klass) {
- let tag = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'div';
- let name = arguments.length > 2 ? arguments[2] : undefined;
- return genericComponent()({
- name: name ?? vue.capitalize(vue.camelize(klass.replace(/__/g, '-'))),
- props: {
- tag: {
- type: String,
- default: tag
- },
- ...makeComponentProps()
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- return () => {
- return vue.h(props.tag, {
- class: [klass, props.class],
- style: props.style
- }, slots.default?.());
- };
- }
- });
- }
- /**
- * Returns:
- * - 'null' if the node is not attached to the DOM
- * - the root node (HTMLDocument | ShadowRoot) otherwise
- */
- function attachedRoot(node) {
- /* istanbul ignore next */
- if (typeof node.getRootNode !== 'function') {
- // Shadow DOM not supported (IE11), lets find the root of this node
- while (node.parentNode) node = node.parentNode;
- // The root parent is the document if the node is attached to the DOM
- if (node !== document) return null;
- return document;
- }
- const root = node.getRootNode();
- // The composed root node is the document if the node is attached to the DOM
- if (root !== document && root.getRootNode({
- composed: true
- }) !== document) return null;
- return root;
- }
- const standardEasing = 'cubic-bezier(0.4, 0, 0.2, 1)';
- const deceleratedEasing = 'cubic-bezier(0.0, 0, 0.2, 1)'; // Entering
- const acceleratedEasing = 'cubic-bezier(0.4, 0, 1, 1)'; // Leaving
- // Utilities
- // Types
- function getCurrentInstance(name, message) {
- const vm = vue.getCurrentInstance();
- if (!vm) {
- throw new Error(`[Vuetify] ${name} ${message || 'must be called from inside a setup function'}`);
- }
- return vm;
- }
- function getCurrentInstanceName() {
- let name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'composables';
- const vm = getCurrentInstance(name).type;
- return toKebabCase(vm?.aliasName || vm?.name);
- }
- let _uid = 0;
- let _map = new WeakMap();
- function getUid() {
- const vm = getCurrentInstance('getUid');
- if (_map.has(vm)) return _map.get(vm);else {
- const uid = _uid++;
- _map.set(vm, uid);
- return uid;
- }
- }
- getUid.reset = () => {
- _uid = 0;
- _map = new WeakMap();
- };
- function getScrollParent(el) {
- let includeHidden = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
- while (el) {
- if (includeHidden ? isPotentiallyScrollable(el) : hasScrollbar(el)) return el;
- el = el.parentElement;
- }
- return document.scrollingElement;
- }
- function getScrollParents(el, stopAt) {
- const elements = [];
- if (stopAt && el && !stopAt.contains(el)) return elements;
- while (el) {
- if (hasScrollbar(el)) elements.push(el);
- if (el === stopAt) break;
- el = el.parentElement;
- }
- return elements;
- }
- function hasScrollbar(el) {
- if (!el || el.nodeType !== Node.ELEMENT_NODE) return false;
- const style = window.getComputedStyle(el);
- return style.overflowY === 'scroll' || style.overflowY === 'auto' && el.scrollHeight > el.clientHeight;
- }
- function isPotentiallyScrollable(el) {
- if (!el || el.nodeType !== Node.ELEMENT_NODE) return false;
- const style = window.getComputedStyle(el);
- return ['scroll', 'auto'].includes(style.overflowY);
- }
- // Utilities
- // Types
- function injectSelf(key) {
- const {
- provides
- } = getCurrentInstance('injectSelf');
- if (provides && key in provides) {
- // TS doesn't allow symbol as index type
- return provides[key];
- }
- return undefined;
- }
- function isFixedPosition(el) {
- while (el) {
- if (window.getComputedStyle(el).position === 'fixed') {
- return true;
- }
- el = el.offsetParent;
- }
- return false;
- }
- // Utilities
- // Types
- function useRender(render) {
- const vm = getCurrentInstance('useRender');
- vm.render = render;
- }
- // Utilities
- // Types
- function useResizeObserver(callback) {
- let box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'content';
- const resizeRef = vue.ref();
- const contentRect = vue.ref();
- if (IN_BROWSER) {
- const observer = new ResizeObserver(entries => {
- callback?.(entries, observer);
- if (!entries.length) return;
- if (box === 'content') {
- contentRect.value = entries[0].contentRect;
- } else {
- contentRect.value = entries[0].target.getBoundingClientRect();
- }
- });
- vue.onBeforeUnmount(() => {
- observer.disconnect();
- });
- vue.watch(resizeRef, (newValue, oldValue) => {
- if (oldValue) {
- observer.unobserve(refElement(oldValue));
- contentRect.value = undefined;
- }
- if (newValue) observer.observe(refElement(newValue));
- }, {
- flush: 'post'
- });
- }
- return {
- resizeRef,
- contentRect: vue.readonly(contentRect)
- };
- }
- // Composables
- // Types
- const VuetifyLayoutKey = Symbol.for('vuetify:layout');
- const VuetifyLayoutItemKey = Symbol.for('vuetify:layout-item');
- const ROOT_ZINDEX = 1000;
- const makeLayoutProps = propsFactory({
- overlaps: {
- type: Array,
- default: () => []
- },
- fullHeight: Boolean
- }, 'layout');
- // Composables
- const makeLayoutItemProps = propsFactory({
- name: {
- type: String
- },
- order: {
- type: [Number, String],
- default: 0
- },
- absolute: Boolean
- }, 'layout-item');
- function useLayout() {
- const layout = vue.inject(VuetifyLayoutKey);
- if (!layout) throw new Error('[Vuetify] Could not find injected layout');
- return {
- getLayoutItem: layout.getLayoutItem,
- mainRect: layout.mainRect,
- mainStyles: layout.mainStyles
- };
- }
- function useLayoutItem(options) {
- const layout = vue.inject(VuetifyLayoutKey);
- if (!layout) throw new Error('[Vuetify] Could not find injected layout');
- const id = options.id ?? `layout-item-${getUid()}`;
- const vm = getCurrentInstance('useLayoutItem');
- vue.provide(VuetifyLayoutItemKey, {
- id
- });
- const isKeptAlive = vue.shallowRef(false);
- vue.onDeactivated(() => isKeptAlive.value = true);
- vue.onActivated(() => isKeptAlive.value = false);
- const {
- layoutItemStyles,
- layoutItemScrimStyles
- } = layout.register(vm, {
- ...options,
- active: vue.computed(() => isKeptAlive.value ? false : options.active.value),
- id
- });
- vue.onBeforeUnmount(() => layout.unregister(id));
- return {
- layoutItemStyles,
- layoutRect: layout.layoutRect,
- layoutItemScrimStyles
- };
- }
- const generateLayers = (layout, positions, layoutSizes, activeItems) => {
- let previousLayer = {
- top: 0,
- left: 0,
- right: 0,
- bottom: 0
- };
- const layers = [{
- id: '',
- layer: {
- ...previousLayer
- }
- }];
- for (const id of layout) {
- const position = positions.get(id);
- const amount = layoutSizes.get(id);
- const active = activeItems.get(id);
- if (!position || !amount || !active) continue;
- const layer = {
- ...previousLayer,
- [position.value]: parseInt(previousLayer[position.value], 10) + (active.value ? parseInt(amount.value, 10) : 0)
- };
- layers.push({
- id,
- layer
- });
- previousLayer = layer;
- }
- return layers;
- };
- function createLayout(props) {
- const parentLayout = vue.inject(VuetifyLayoutKey, null);
- const rootZIndex = vue.computed(() => parentLayout ? parentLayout.rootZIndex.value - 100 : ROOT_ZINDEX);
- const registered = vue.ref([]);
- const positions = vue.reactive(new Map());
- const layoutSizes = vue.reactive(new Map());
- const priorities = vue.reactive(new Map());
- const activeItems = vue.reactive(new Map());
- const disabledTransitions = vue.reactive(new Map());
- const {
- resizeRef,
- contentRect: layoutRect
- } = useResizeObserver();
- const computedOverlaps = vue.computed(() => {
- const map = new Map();
- const overlaps = props.overlaps ?? [];
- for (const overlap of overlaps.filter(item => item.includes(':'))) {
- const [top, bottom] = overlap.split(':');
- if (!registered.value.includes(top) || !registered.value.includes(bottom)) continue;
- const topPosition = positions.get(top);
- const bottomPosition = positions.get(bottom);
- const topAmount = layoutSizes.get(top);
- const bottomAmount = layoutSizes.get(bottom);
- if (!topPosition || !bottomPosition || !topAmount || !bottomAmount) continue;
- map.set(bottom, {
- position: topPosition.value,
- amount: parseInt(topAmount.value, 10)
- });
- map.set(top, {
- position: bottomPosition.value,
- amount: -parseInt(bottomAmount.value, 10)
- });
- }
- return map;
- });
- const layers = vue.computed(() => {
- const uniquePriorities = [...new Set([...priorities.values()].map(p => p.value))].sort((a, b) => a - b);
- const layout = [];
- for (const p of uniquePriorities) {
- const items = registered.value.filter(id => priorities.get(id)?.value === p);
- layout.push(...items);
- }
- return generateLayers(layout, positions, layoutSizes, activeItems);
- });
- const transitionsEnabled = vue.computed(() => {
- return !Array.from(disabledTransitions.values()).some(ref => ref.value);
- });
- const mainRect = vue.computed(() => {
- return layers.value[layers.value.length - 1].layer;
- });
- const mainStyles = vue.computed(() => {
- return {
- '--v-layout-left': convertToUnit(mainRect.value.left),
- '--v-layout-right': convertToUnit(mainRect.value.right),
- '--v-layout-top': convertToUnit(mainRect.value.top),
- '--v-layout-bottom': convertToUnit(mainRect.value.bottom),
- ...(transitionsEnabled.value ? undefined : {
- transition: 'none'
- })
- };
- });
- const items = vue.computed(() => {
- return layers.value.slice(1).map((_ref, index) => {
- let {
- id
- } = _ref;
- const {
- layer
- } = layers.value[index];
- const size = layoutSizes.get(id);
- const position = positions.get(id);
- return {
- id,
- ...layer,
- size: Number(size.value),
- position: position.value
- };
- });
- });
- const getLayoutItem = id => {
- return items.value.find(item => item.id === id);
- };
- const rootVm = getCurrentInstance('createLayout');
- const isMounted = vue.shallowRef(false);
- vue.onMounted(() => {
- isMounted.value = true;
- });
- vue.provide(VuetifyLayoutKey, {
- register: (vm, _ref2) => {
- let {
- id,
- order,
- position,
- layoutSize,
- elementSize,
- active,
- disableTransitions,
- absolute
- } = _ref2;
- priorities.set(id, order);
- positions.set(id, position);
- layoutSizes.set(id, layoutSize);
- activeItems.set(id, active);
- disableTransitions && disabledTransitions.set(id, disableTransitions);
- const instances = findChildrenWithProvide(VuetifyLayoutItemKey, rootVm?.vnode);
- const instanceIndex = instances.indexOf(vm);
- if (instanceIndex > -1) registered.value.splice(instanceIndex, 0, id);else registered.value.push(id);
- const index = vue.computed(() => items.value.findIndex(i => i.id === id));
- const zIndex = vue.computed(() => rootZIndex.value + layers.value.length * 2 - index.value * 2);
- const layoutItemStyles = vue.computed(() => {
- const isHorizontal = position.value === 'left' || position.value === 'right';
- const isOppositeHorizontal = position.value === 'right';
- const isOppositeVertical = position.value === 'bottom';
- const styles = {
- [position.value]: 0,
- zIndex: zIndex.value,
- transform: `translate${isHorizontal ? 'X' : 'Y'}(${(active.value ? 0 : -110) * (isOppositeHorizontal || isOppositeVertical ? -1 : 1)}%)`,
- position: absolute.value || rootZIndex.value !== ROOT_ZINDEX ? 'absolute' : 'fixed',
- ...(transitionsEnabled.value ? undefined : {
- transition: 'none'
- })
- };
- if (!isMounted.value) return styles;
- const item = items.value[index.value];
- if (!item) throw new Error(`[Vuetify] Could not find layout item "${id}"`);
- const overlap = computedOverlaps.value.get(id);
- if (overlap) {
- item[overlap.position] += overlap.amount;
- }
- return {
- ...styles,
- height: isHorizontal ? `calc(100% - ${item.top}px - ${item.bottom}px)` : elementSize.value ? `${elementSize.value}px` : undefined,
- left: isOppositeHorizontal ? undefined : `${item.left}px`,
- right: isOppositeHorizontal ? `${item.right}px` : undefined,
- top: position.value !== 'bottom' ? `${item.top}px` : undefined,
- bottom: position.value !== 'top' ? `${item.bottom}px` : undefined,
- width: !isHorizontal ? `calc(100% - ${item.left}px - ${item.right}px)` : elementSize.value ? `${elementSize.value}px` : undefined
- };
- });
- const layoutItemScrimStyles = vue.computed(() => ({
- zIndex: zIndex.value - 1
- }));
- return {
- layoutItemStyles,
- layoutItemScrimStyles,
- zIndex
- };
- },
- unregister: id => {
- priorities.delete(id);
- positions.delete(id);
- layoutSizes.delete(id);
- activeItems.delete(id);
- disabledTransitions.delete(id);
- registered.value = registered.value.filter(v => v !== id);
- },
- mainRect,
- mainStyles,
- getLayoutItem,
- items,
- layoutRect,
- rootZIndex
- });
- const layoutClasses = vue.computed(() => ['v-layout', {
- 'v-layout--full-height': props.fullHeight
- }]);
- const layoutStyles = vue.computed(() => ({
- zIndex: rootZIndex.value,
- position: parentLayout ? 'relative' : undefined,
- overflow: parentLayout ? 'hidden' : undefined
- }));
- return {
- layoutClasses,
- layoutStyles,
- getLayoutItem,
- items,
- layoutRect,
- layoutRef: resizeRef
- };
- }
- var en = {
- badge: 'Badge',
- close: 'Close',
- dataIterator: {
- noResultsText: 'No matching records found',
- loadingText: 'Loading items...'
- },
- dataTable: {
- itemsPerPageText: 'Rows per page:',
- ariaLabel: {
- sortDescending: 'Sorted descending.',
- sortAscending: 'Sorted ascending.',
- sortNone: 'Not sorted.',
- activateNone: 'Activate to remove sorting.',
- activateDescending: 'Activate to sort descending.',
- activateAscending: 'Activate to sort ascending.'
- },
- sortBy: 'Sort by'
- },
- dataFooter: {
- itemsPerPageText: 'Items per page:',
- itemsPerPageAll: 'All',
- nextPage: 'Next page',
- prevPage: 'Previous page',
- firstPage: 'First page',
- lastPage: 'Last page',
- pageText: '{0}-{1} of {2}'
- },
- dateRangeInput: {
- divider: 'to'
- },
- datePicker: {
- ok: 'OK',
- cancel: 'Cancel',
- range: {
- title: 'Select dates',
- header: 'Enter dates'
- },
- title: 'Select date',
- header: 'Enter date',
- input: {
- placeholder: 'Enter date'
- }
- },
- noDataText: 'No data available',
- carousel: {
- prev: 'Previous visual',
- next: 'Next visual',
- ariaLabel: {
- delimiter: 'Carousel slide {0} of {1}'
- }
- },
- calendar: {
- moreEvents: '{0} more'
- },
- input: {
- clear: 'Clear {0}',
- prependAction: '{0} prepended action',
- appendAction: '{0} appended action',
- otp: 'Please enter OTP character {0}'
- },
- fileInput: {
- counter: '{0} files',
- counterSize: '{0} files ({1} in total)'
- },
- timePicker: {
- am: 'AM',
- pm: 'PM'
- },
- pagination: {
- ariaLabel: {
- root: 'Pagination Navigation',
- next: 'Next page',
- previous: 'Previous page',
- page: 'Go to page {0}',
- currentPage: 'Page {0}, Current page',
- first: 'First page',
- last: 'Last page'
- }
- },
- stepper: {
- next: 'Next',
- prev: 'Previous'
- },
- rating: {
- ariaLabel: {
- item: 'Rating {0} of {1}'
- }
- },
- loading: 'Loading...',
- infiniteScroll: {
- loadMore: 'Load more',
- empty: 'No more'
- }
- };
- const defaultRtl = {
- af: false,
- ar: true,
- bg: false,
- ca: false,
- ckb: false,
- cs: false,
- de: false,
- el: false,
- en: false,
- es: false,
- et: false,
- fa: true,
- fi: false,
- fr: false,
- hr: false,
- hu: false,
- he: true,
- id: false,
- it: false,
- ja: false,
- ko: false,
- lv: false,
- lt: false,
- nl: false,
- no: false,
- pl: false,
- pt: false,
- ro: false,
- ru: false,
- sk: false,
- sl: false,
- srCyrl: false,
- srLatn: false,
- sv: false,
- th: false,
- tr: false,
- az: false,
- uk: false,
- vi: false,
- zhHans: false,
- zhHant: false
- };
- // Composables
- // Types
- // Composables
- function useProxiedModel(props, prop, defaultValue) {
- let transformIn = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : v => v;
- let transformOut = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : v => v;
- const vm = getCurrentInstance('useProxiedModel');
- const internal = vue.ref(props[prop] !== undefined ? props[prop] : defaultValue);
- const kebabProp = toKebabCase(prop);
- const checkKebab = kebabProp !== prop;
- const isControlled = checkKebab ? vue.computed(() => {
- void props[prop];
- return !!((vm.vnode.props?.hasOwnProperty(prop) || vm.vnode.props?.hasOwnProperty(kebabProp)) && (vm.vnode.props?.hasOwnProperty(`onUpdate:${prop}`) || vm.vnode.props?.hasOwnProperty(`onUpdate:${kebabProp}`)));
- }) : vue.computed(() => {
- void props[prop];
- return !!(vm.vnode.props?.hasOwnProperty(prop) && vm.vnode.props?.hasOwnProperty(`onUpdate:${prop}`));
- });
- useToggleScope(() => !isControlled.value, () => {
- vue.watch(() => props[prop], val => {
- internal.value = val;
- });
- });
- const model = vue.computed({
- get() {
- const externalValue = props[prop];
- return transformIn(isControlled.value ? externalValue : internal.value);
- },
- set(internalValue) {
- const newValue = transformOut(internalValue);
- const value = vue.toRaw(isControlled.value ? props[prop] : internal.value);
- if (value === newValue || transformIn(value) === internalValue) {
- return;
- }
- internal.value = newValue;
- vm?.emit(`update:${prop}`, newValue);
- }
- });
- Object.defineProperty(model, 'externalValue', {
- get: () => isControlled.value ? props[prop] : internal.value
- });
- return model;
- }
- // Composables
- // Types
- const LANG_PREFIX = '$vuetify.';
- const replace = (str, params) => {
- return str.replace(/\{(\d+)\}/g, (match, index) => {
- return String(params[+index]);
- });
- };
- const createTranslateFunction = (current, fallback, messages) => {
- return function (key) {
- for (var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
- params[_key - 1] = arguments[_key];
- }
- if (!key.startsWith(LANG_PREFIX)) {
- return replace(key, params);
- }
- const shortKey = key.replace(LANG_PREFIX, '');
- const currentLocale = current.value && messages.value[current.value];
- const fallbackLocale = fallback.value && messages.value[fallback.value];
- let str = getObjectValueByPath(currentLocale, shortKey, null);
- if (!str) {
- consoleWarn(`Translation key "${key}" not found in "${current.value}", trying fallback locale`);
- str = getObjectValueByPath(fallbackLocale, shortKey, null);
- }
- if (!str) {
- consoleError(`Translation key "${key}" not found in fallback`);
- str = key;
- }
- if (typeof str !== 'string') {
- consoleError(`Translation key "${key}" has a non-string value`);
- str = key;
- }
- return replace(str, params);
- };
- };
- function createNumberFunction(current, fallback) {
- return (value, options) => {
- const numberFormat = new Intl.NumberFormat([current.value, fallback.value], options);
- return numberFormat.format(value);
- };
- }
- function useProvided(props, prop, provided) {
- const internal = useProxiedModel(props, prop, props[prop] ?? provided.value);
- // TODO: Remove when defaultValue works
- internal.value = props[prop] ?? provided.value;
- vue.watch(provided, v => {
- if (props[prop] == null) {
- internal.value = provided.value;
- }
- });
- return internal;
- }
- function createProvideFunction(state) {
- return props => {
- const current = useProvided(props, 'locale', state.current);
- const fallback = useProvided(props, 'fallback', state.fallback);
- const messages = useProvided(props, 'messages', state.messages);
- return {
- name: 'vuetify',
- current,
- fallback,
- messages,
- t: createTranslateFunction(current, fallback, messages),
- n: createNumberFunction(current, fallback),
- provide: createProvideFunction({
- current,
- fallback,
- messages
- })
- };
- };
- }
- function createVuetifyAdapter(options) {
- const current = vue.shallowRef(options?.locale ?? 'en');
- const fallback = vue.shallowRef(options?.fallback ?? 'en');
- const messages = vue.ref({
- en,
- ...options?.messages
- });
- return {
- name: 'vuetify',
- current,
- fallback,
- messages,
- t: createTranslateFunction(current, fallback, messages),
- n: createNumberFunction(current, fallback),
- provide: createProvideFunction({
- current,
- fallback,
- messages
- })
- };
- }
- // Utilities
- // Types
- const LocaleSymbol = Symbol.for('vuetify:locale');
- function isLocaleInstance(obj) {
- return obj.name != null;
- }
- function createLocale(options) {
- const i18n = options?.adapter && isLocaleInstance(options?.adapter) ? options?.adapter : createVuetifyAdapter(options);
- const rtl = createRtl(i18n, options);
- return {
- ...i18n,
- ...rtl
- };
- }
- function useLocale() {
- const locale = vue.inject(LocaleSymbol);
- if (!locale) throw new Error('[Vuetify] Could not find injected locale instance');
- return locale;
- }
- function provideLocale(props) {
- const locale = vue.inject(LocaleSymbol);
- if (!locale) throw new Error('[Vuetify] Could not find injected locale instance');
- const i18n = locale.provide(props);
- const rtl = provideRtl(i18n, locale.rtl, props);
- const data = {
- ...i18n,
- ...rtl
- };
- vue.provide(LocaleSymbol, data);
- return data;
- }
- function createRtl(i18n, options) {
- const rtl = vue.ref(options?.rtl ?? defaultRtl);
- const isRtl = vue.computed(() => rtl.value[i18n.current.value] ?? false);
- return {
- isRtl,
- rtl,
- rtlClasses: vue.computed(() => `v-locale--is-${isRtl.value ? 'rtl' : 'ltr'}`)
- };
- }
- function provideRtl(locale, rtl, props) {
- const isRtl = vue.computed(() => props.rtl ?? rtl.value[locale.current.value] ?? false);
- return {
- isRtl,
- rtl,
- rtlClasses: vue.computed(() => `v-locale--is-${isRtl.value ? 'rtl' : 'ltr'}`)
- };
- }
- function useRtl() {
- const locale = vue.inject(LocaleSymbol);
- if (!locale) throw new Error('[Vuetify] Could not find injected rtl instance');
- return {
- isRtl: locale.isRtl,
- rtlClasses: locale.rtlClasses
- };
- }
- /**
- * WCAG 3.0 APCA perceptual contrast algorithm from https://github.com/Myndex/SAPC-APCA
- * @licence https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
- * @see https://www.w3.org/WAI/GL/task-forces/silver/wiki/Visual_Contrast_of_Text_Subgroup
- */
- // Types
- // MAGICAL NUMBERS
- // sRGB Conversion to Relative Luminance (Y)
- // Transfer Curve (aka "Gamma") for sRGB linearization
- // Simple power curve vs piecewise described in docs
- // Essentially, 2.4 best models actual display
- // characteristics in combination with the total method
- const mainTRC = 2.4;
- const Rco = 0.2126729; // sRGB Red Coefficient (from matrix)
- const Gco = 0.7151522; // sRGB Green Coefficient (from matrix)
- const Bco = 0.0721750; // sRGB Blue Coefficient (from matrix)
- // For Finding Raw SAPC Contrast from Relative Luminance (Y)
- // Constants for SAPC Power Curve Exponents
- // One pair for normal text, and one for reverse
- // These are the "beating heart" of SAPC
- const normBG = 0.55;
- const normTXT = 0.58;
- const revTXT = 0.57;
- const revBG = 0.62;
- // For Clamping and Scaling Values
- const blkThrs = 0.03; // Level that triggers the soft black clamp
- const blkClmp = 1.45; // Exponent for the soft black clamp curve
- const deltaYmin = 0.0005; // Lint trap
- const scaleBoW = 1.25; // Scaling for dark text on light
- const scaleWoB = 1.25; // Scaling for light text on dark
- const loConThresh = 0.078; // Threshold for new simple offset scale
- const loConFactor = 12.82051282051282; // = 1/0.078,
- const loConOffset = 0.06; // The simple offset
- const loClip = 0.001; // Output clip (lint trap #2)
- function APCAcontrast(text, background) {
- // Linearize sRGB
- const Rtxt = (text.r / 255) ** mainTRC;
- const Gtxt = (text.g / 255) ** mainTRC;
- const Btxt = (text.b / 255) ** mainTRC;
- const Rbg = (background.r / 255) ** mainTRC;
- const Gbg = (background.g / 255) ** mainTRC;
- const Bbg = (background.b / 255) ** mainTRC;
- // Apply the standard coefficients and sum to Y
- let Ytxt = Rtxt * Rco + Gtxt * Gco + Btxt * Bco;
- let Ybg = Rbg * Rco + Gbg * Gco + Bbg * Bco;
- // Soft clamp Y when near black.
- // Now clamping all colors to prevent crossover errors
- if (Ytxt <= blkThrs) Ytxt += (blkThrs - Ytxt) ** blkClmp;
- if (Ybg <= blkThrs) Ybg += (blkThrs - Ybg) ** blkClmp;
- // Return 0 Early for extremely low ∆Y (lint trap #1)
- if (Math.abs(Ybg - Ytxt) < deltaYmin) return 0.0;
- // SAPC CONTRAST
- let outputContrast; // For weighted final values
- if (Ybg > Ytxt) {
- // For normal polarity, black text on white
- // Calculate the SAPC contrast value and scale
- const SAPC = (Ybg ** normBG - Ytxt ** normTXT) * scaleBoW;
- // NEW! SAPC SmoothScale™
- // Low Contrast Smooth Scale Rollout to prevent polarity reversal
- // and also a low clip for very low contrasts (lint trap #2)
- // much of this is for very low contrasts, less than 10
- // therefore for most reversing needs, only loConOffset is important
- outputContrast = SAPC < loClip ? 0.0 : SAPC < loConThresh ? SAPC - SAPC * loConFactor * loConOffset : SAPC - loConOffset;
- } else {
- // For reverse polarity, light text on dark
- // WoB should always return negative value.
- const SAPC = (Ybg ** revBG - Ytxt ** revTXT) * scaleWoB;
- outputContrast = SAPC > -loClip ? 0.0 : SAPC > -loConThresh ? SAPC - SAPC * loConFactor * loConOffset : SAPC + loConOffset;
- }
- return outputContrast * 100;
- }
- // Utilities
- // Types
- const ThemeSymbol = Symbol.for('vuetify:theme');
- const makeThemeProps = propsFactory({
- theme: String
- }, 'theme');
- const defaultThemeOptions = {
- defaultTheme: 'light',
- variations: {
- colors: [],
- lighten: 0,
- darken: 0
- },
- themes: {
- light: {
- dark: false,
- colors: {
- background: '#FFFFFF',
- surface: '#FFFFFF',
- 'surface-variant': '#424242',
- 'on-surface-variant': '#EEEEEE',
- primary: '#6200EE',
- 'primary-darken-1': '#3700B3',
- secondary: '#03DAC6',
- 'secondary-darken-1': '#018786',
- error: '#B00020',
- info: '#2196F3',
- success: '#4CAF50',
- warning: '#FB8C00'
- },
- variables: {
- 'border-color': '#000000',
- 'border-opacity': 0.12,
- 'high-emphasis-opacity': 0.87,
- 'medium-emphasis-opacity': 0.60,
- 'disabled-opacity': 0.38,
- 'idle-opacity': 0.04,
- 'hover-opacity': 0.04,
- 'focus-opacity': 0.12,
- 'selected-opacity': 0.08,
- 'activated-opacity': 0.12,
- 'pressed-opacity': 0.12,
- 'dragged-opacity': 0.08,
- 'theme-kbd': '#212529',
- 'theme-on-kbd': '#FFFFFF',
- 'theme-code': '#F5F5F5',
- 'theme-on-code': '#000000'
- }
- },
- dark: {
- dark: true,
- colors: {
- background: '#121212',
- surface: '#212121',
- 'surface-variant': '#BDBDBD',
- 'on-surface-variant': '#424242',
- primary: '#BB86FC',
- 'primary-darken-1': '#3700B3',
- secondary: '#03DAC5',
- 'secondary-darken-1': '#03DAC5',
- error: '#CF6679',
- info: '#2196F3',
- success: '#4CAF50',
- warning: '#FB8C00'
- },
- variables: {
- 'border-color': '#FFFFFF',
- 'border-opacity': 0.12,
- 'high-emphasis-opacity': 1,
- 'medium-emphasis-opacity': 0.70,
- 'disabled-opacity': 0.50,
- 'idle-opacity': 0.10,
- 'hover-opacity': 0.04,
- 'focus-opacity': 0.12,
- 'selected-opacity': 0.08,
- 'activated-opacity': 0.12,
- 'pressed-opacity': 0.16,
- 'dragged-opacity': 0.08,
- 'theme-kbd': '#212529',
- 'theme-on-kbd': '#FFFFFF',
- 'theme-code': '#343434',
- 'theme-on-code': '#CCCCCC'
- }
- }
- }
- };
- function parseThemeOptions() {
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultThemeOptions;
- if (!options) return {
- ...defaultThemeOptions,
- isDisabled: true
- };
- const themes = {};
- for (const [key, theme] of Object.entries(options.themes ?? {})) {
- const defaultTheme = theme.dark || key === 'dark' ? defaultThemeOptions.themes?.dark : defaultThemeOptions.themes?.light;
- themes[key] = mergeDeep(defaultTheme, theme);
- }
- return mergeDeep(defaultThemeOptions, {
- ...options,
- themes
- });
- }
- // Composables
- function createTheme(options) {
- const parsedOptions = parseThemeOptions(options);
- const name = vue.ref(parsedOptions.defaultTheme);
- const themes = vue.ref(parsedOptions.themes);
- const computedThemes = vue.computed(() => {
- const acc = {};
- for (const [name, original] of Object.entries(themes.value)) {
- const theme = acc[name] = {
- ...original,
- colors: {
- ...original.colors
- }
- };
- if (parsedOptions.variations) {
- for (const name of parsedOptions.variations.colors) {
- const color = theme.colors[name];
- if (!color) continue;
- for (const variation of ['lighten', 'darken']) {
- const fn = variation === 'lighten' ? lighten : darken;
- for (const amount of createRange(parsedOptions.variations[variation], 1)) {
- theme.colors[`${name}-${variation}-${amount}`] = RGBtoHex(fn(parseColor(color), amount));
- }
- }
- }
- }
- for (const color of Object.keys(theme.colors)) {
- if (/^on-[a-z]/.test(color) || theme.colors[`on-${color}`]) continue;
- const onColor = `on-${color}`;
- const colorVal = parseColor(theme.colors[color]);
- const blackContrast = Math.abs(APCAcontrast(parseColor(0), colorVal));
- const whiteContrast = Math.abs(APCAcontrast(parseColor(0xffffff), colorVal));
- // TODO: warn about poor color selections
- // const contrastAsText = Math.abs(APCAcontrast(colorVal, colorToInt(theme.colors.background)))
- // const minContrast = Math.max(blackContrast, whiteContrast)
- // if (minContrast < 60) {
- // consoleInfo(`${key} theme color ${color} has poor contrast (${minContrast.toFixed()}%)`)
- // } else if (contrastAsText < 60 && !['background', 'surface'].includes(color)) {
- // consoleInfo(`${key} theme color ${color} has poor contrast as text (${contrastAsText.toFixed()}%)`)
- // }
- // Prefer white text if both have an acceptable contrast ratio
- theme.colors[onColor] = whiteContrast > Math.min(blackContrast, 50) ? '#fff' : '#000';
- }
- }
- return acc;
- });
- const current = vue.computed(() => computedThemes.value[name.value]);
- const styles = vue.computed(() => {
- const lines = [];
- if (current.value.dark) {
- createCssClass(lines, ':root', ['color-scheme: dark']);
- }
- createCssClass(lines, ':root', genCssVariables(current.value));
- for (const [themeName, theme] of Object.entries(computedThemes.value)) {
- createCssClass(lines, `.v-theme--${themeName}`, [`color-scheme: ${theme.dark ? 'dark' : 'normal'}`, ...genCssVariables(theme)]);
- }
- const bgLines = [];
- const fgLines = [];
- const colors = new Set(Object.values(computedThemes.value).flatMap(theme => Object.keys(theme.colors)));
- for (const key of colors) {
- if (/^on-[a-z]/.test(key)) {
- createCssClass(fgLines, `.${key}`, [`color: rgb(var(--v-theme-${key})) !important`]);
- } else {
- createCssClass(bgLines, `.bg-${key}`, [`--v-theme-overlay-multiplier: var(--v-theme-${key}-overlay-multiplier)`, `background-color: rgb(var(--v-theme-${key})) !important`, `color: rgb(var(--v-theme-on-${key})) !important`]);
- createCssClass(fgLines, `.text-${key}`, [`color: rgb(var(--v-theme-${key})) !important`]);
- createCssClass(fgLines, `.border-${key}`, [`--v-border-color: var(--v-theme-${key})`]);
- }
- }
- lines.push(...bgLines, ...fgLines);
- return lines.map((str, i) => i === 0 ? str : ` ${str}`).join('');
- });
- function getHead() {
- return {
- style: [{
- children: styles.value,
- id: 'vuetify-theme-stylesheet',
- nonce: parsedOptions.cspNonce || false
- }]
- };
- }
- function install(app) {
- if (parsedOptions.isDisabled) return;
- const head = app._context.provides.usehead;
- if (head) {
- if (head.push) {
- const entry = head.push(getHead);
- if (IN_BROWSER) {
- vue.watch(styles, () => {
- entry.patch(getHead);
- });
- }
- } else {
- if (IN_BROWSER) {
- head.addHeadObjs(vue.computed(getHead));
- vue.watchEffect(() => head.updateDOM());
- } else {
- head.addHeadObjs(getHead());
- }
- }
- } else {
- let styleEl = IN_BROWSER ? document.getElementById('vuetify-theme-stylesheet') : null;
- if (IN_BROWSER) {
- vue.watch(styles, updateStyles, {
- immediate: true
- });
- } else {
- updateStyles();
- }
- function updateStyles() {
- if (typeof document !== 'undefined' && !styleEl) {
- const el = document.createElement('style');
- el.type = 'text/css';
- el.id = 'vuetify-theme-stylesheet';
- if (parsedOptions.cspNonce) el.setAttribute('nonce', parsedOptions.cspNonce);
- styleEl = el;
- document.head.appendChild(styleEl);
- }
- if (styleEl) styleEl.innerHTML = styles.value;
- }
- }
- }
- const themeClasses = vue.computed(() => parsedOptions.isDisabled ? undefined : `v-theme--${name.value}`);
- return {
- install,
- isDisabled: parsedOptions.isDisabled,
- name,
- themes,
- current,
- computedThemes,
- themeClasses,
- styles,
- global: {
- name,
- current
- }
- };
- }
- function provideTheme(props) {
- getCurrentInstance('provideTheme');
- const theme = vue.inject(ThemeSymbol, null);
- if (!theme) throw new Error('Could not find Vuetify theme injection');
- const name = vue.computed(() => {
- return props.theme ?? theme?.name.value;
- });
- const themeClasses = vue.computed(() => theme.isDisabled ? undefined : `v-theme--${name.value}`);
- const newTheme = {
- ...theme,
- name,
- themeClasses
- };
- vue.provide(ThemeSymbol, newTheme);
- return newTheme;
- }
- function useTheme() {
- getCurrentInstance('useTheme');
- const theme = vue.inject(ThemeSymbol, null);
- if (!theme) throw new Error('Could not find Vuetify theme injection');
- return theme;
- }
- function createCssClass(lines, selector, content) {
- lines.push(`${selector} {\n`, ...content.map(line => ` ${line};\n`), '}\n');
- }
- function genCssVariables(theme) {
- const lightOverlay = theme.dark ? 2 : 1;
- const darkOverlay = theme.dark ? 1 : 2;
- const variables = [];
- for (const [key, value] of Object.entries(theme.colors)) {
- const rgb = parseColor(value);
- variables.push(`--v-theme-${key}: ${rgb.r},${rgb.g},${rgb.b}`);
- if (!key.startsWith('on-')) {
- variables.push(`--v-theme-${key}-overlay-multiplier: ${getLuma(value) > 0.18 ? lightOverlay : darkOverlay}`);
- }
- }
- for (const [key, value] of Object.entries(theme.variables)) {
- const color = typeof value === 'string' && value.startsWith('#') ? parseColor(value) : undefined;
- const rgb = color ? `${color.r}, ${color.g}, ${color.b}` : undefined;
- variables.push(`--v-${key}: ${rgb ?? value}`);
- }
- return variables;
- }
- const makeVAppProps = propsFactory({
- ...makeComponentProps(),
- ...makeLayoutProps({
- fullHeight: true
- }),
- ...makeThemeProps()
- }, 'VApp');
- const VApp = genericComponent()({
- name: 'VApp',
- props: makeVAppProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const theme = provideTheme(props);
- const {
- layoutClasses,
- layoutStyles,
- getLayoutItem,
- items,
- layoutRef
- } = createLayout(props);
- const {
- rtlClasses
- } = useRtl();
- useRender(() => vue.createVNode("div", {
- "ref": layoutRef,
- "class": ['v-application', theme.themeClasses.value, layoutClasses.value, rtlClasses.value, props.class],
- "style": [layoutStyles.value, props.style]
- }, [vue.createVNode("div", {
- "class": "v-application__wrap"
- }, [slots.default?.()])]));
- return {
- getLayoutItem,
- items,
- theme
- };
- }
- });
- // Utilities
- // Types
- // Composables
- const makeTagProps = propsFactory({
- tag: {
- type: String,
- default: 'div'
- }
- }, 'tag');
- const makeVToolbarTitleProps = propsFactory({
- text: String,
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VToolbarTitle');
- const VToolbarTitle = genericComponent()({
- name: 'VToolbarTitle',
- props: makeVToolbarTitleProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => {
- const hasText = !!(slots.default || slots.text || props.text);
- return vue.createVNode(props.tag, {
- "class": ['v-toolbar-title', props.class],
- "style": props.style
- }, {
- default: () => [hasText && vue.createVNode("div", {
- "class": "v-toolbar-title__placeholder"
- }, [slots.text ? slots.text() : props.text, slots.default?.()])]
- });
- });
- return {};
- }
- });
- // Utilities
- // Types
- const makeTransitionProps$1 = propsFactory({
- disabled: Boolean,
- group: Boolean,
- hideOnLeave: Boolean,
- leaveAbsolute: Boolean,
- mode: String,
- origin: String
- }, 'transition');
- function createCssTransition(name, origin, mode) {
- return genericComponent()({
- name,
- props: makeTransitionProps$1({
- mode,
- origin
- }),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const functions = {
- onBeforeEnter(el) {
- if (props.origin) {
- el.style.transformOrigin = props.origin;
- }
- },
- onLeave(el) {
- if (props.leaveAbsolute) {
- const {
- offsetTop,
- offsetLeft,
- offsetWidth,
- offsetHeight
- } = el;
- el._transitionInitialStyles = {
- position: el.style.position,
- top: el.style.top,
- left: el.style.left,
- width: el.style.width,
- height: el.style.height
- };
- el.style.position = 'absolute';
- el.style.top = `${offsetTop}px`;
- el.style.left = `${offsetLeft}px`;
- el.style.width = `${offsetWidth}px`;
- el.style.height = `${offsetHeight}px`;
- }
- if (props.hideOnLeave) {
- el.style.setProperty('display', 'none', 'important');
- }
- },
- onAfterLeave(el) {
- if (props.leaveAbsolute && el?._transitionInitialStyles) {
- const {
- position,
- top,
- left,
- width,
- height
- } = el._transitionInitialStyles;
- delete el._transitionInitialStyles;
- el.style.position = position || '';
- el.style.top = top || '';
- el.style.left = left || '';
- el.style.width = width || '';
- el.style.height = height || '';
- }
- }
- };
- return () => {
- const tag = props.group ? vue.TransitionGroup : vue.Transition;
- return vue.h(tag, {
- name: props.disabled ? '' : name,
- css: !props.disabled,
- ...(props.group ? undefined : {
- mode: props.mode
- }),
- ...(props.disabled ? {} : functions)
- }, slots.default);
- };
- }
- });
- }
- function createJavascriptTransition(name, functions) {
- let mode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'in-out';
- return genericComponent()({
- name,
- props: {
- mode: {
- type: String,
- default: mode
- },
- disabled: Boolean
- },
- setup(props, _ref2) {
- let {
- slots
- } = _ref2;
- return () => {
- return vue.h(vue.Transition, {
- name: props.disabled ? '' : name,
- css: !props.disabled,
- // mode: props.mode, // TODO: vuejs/vue-next#3104
- ...(props.disabled ? {} : functions)
- }, slots.default);
- };
- }
- });
- }
- // Utilities
- function ExpandTransitionGenerator () {
- let expandedParentClass = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
- let x = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
- const sizeProperty = x ? 'width' : 'height';
- const offsetProperty = vue.camelize(`offset-${sizeProperty}`);
- return {
- onBeforeEnter(el) {
- el._parent = el.parentNode;
- el._initialStyle = {
- transition: el.style.transition,
- overflow: el.style.overflow,
- [sizeProperty]: el.style[sizeProperty]
- };
- },
- onEnter(el) {
- const initialStyle = el._initialStyle;
- el.style.setProperty('transition', 'none', 'important');
- // Hide overflow to account for collapsed margins in the calculated height
- el.style.overflow = 'hidden';
- const offset = `${el[offsetProperty]}px`;
- el.style[sizeProperty] = '0';
- void el.offsetHeight; // force reflow
- el.style.transition = initialStyle.transition;
- if (expandedParentClass && el._parent) {
- el._parent.classList.add(expandedParentClass);
- }
- requestAnimationFrame(() => {
- el.style[sizeProperty] = offset;
- });
- },
- onAfterEnter: resetStyles,
- onEnterCancelled: resetStyles,
- onLeave(el) {
- el._initialStyle = {
- transition: '',
- overflow: el.style.overflow,
- [sizeProperty]: el.style[sizeProperty]
- };
- el.style.overflow = 'hidden';
- el.style[sizeProperty] = `${el[offsetProperty]}px`;
- void el.offsetHeight; // force reflow
- requestAnimationFrame(() => el.style[sizeProperty] = '0');
- },
- onAfterLeave,
- onLeaveCancelled: onAfterLeave
- };
- function onAfterLeave(el) {
- if (expandedParentClass && el._parent) {
- el._parent.classList.remove(expandedParentClass);
- }
- resetStyles(el);
- }
- function resetStyles(el) {
- const size = el._initialStyle[sizeProperty];
- el.style.overflow = el._initialStyle.overflow;
- if (size != null) el.style[sizeProperty] = size;
- delete el._initialStyle;
- }
- }
- // Types
- const makeVDialogTransitionProps = propsFactory({
- target: Object
- }, 'v-dialog-transition');
- const VDialogTransition = genericComponent()({
- name: 'VDialogTransition',
- props: makeVDialogTransitionProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const functions = {
- onBeforeEnter(el) {
- el.style.pointerEvents = 'none';
- el.style.visibility = 'hidden';
- },
- async onEnter(el, done) {
- await new Promise(resolve => requestAnimationFrame(resolve));
- await new Promise(resolve => requestAnimationFrame(resolve));
- el.style.visibility = '';
- const {
- x,
- y,
- sx,
- sy,
- speed
- } = getDimensions(props.target, el);
- const animation = animate(el, [{
- transform: `translate(${x}px, ${y}px) scale(${sx}, ${sy})`,
- opacity: 0
- }, {}], {
- duration: 225 * speed,
- easing: deceleratedEasing
- });
- getChildren(el)?.forEach(el => {
- animate(el, [{
- opacity: 0
- }, {
- opacity: 0,
- offset: 0.33
- }, {}], {
- duration: 225 * 2 * speed,
- easing: standardEasing
- });
- });
- animation.finished.then(() => done());
- },
- onAfterEnter(el) {
- el.style.removeProperty('pointer-events');
- },
- onBeforeLeave(el) {
- el.style.pointerEvents = 'none';
- },
- async onLeave(el, done) {
- await new Promise(resolve => requestAnimationFrame(resolve));
- const {
- x,
- y,
- sx,
- sy,
- speed
- } = getDimensions(props.target, el);
- const animation = animate(el, [{}, {
- transform: `translate(${x}px, ${y}px) scale(${sx}, ${sy})`,
- opacity: 0
- }], {
- duration: 125 * speed,
- easing: acceleratedEasing
- });
- animation.finished.then(() => done());
- getChildren(el)?.forEach(el => {
- animate(el, [{}, {
- opacity: 0,
- offset: 0.2
- }, {
- opacity: 0
- }], {
- duration: 125 * 2 * speed,
- easing: standardEasing
- });
- });
- },
- onAfterLeave(el) {
- el.style.removeProperty('pointer-events');
- }
- };
- return () => {
- return props.target ? vue.createVNode(vue.Transition, vue.mergeProps({
- "name": "dialog-transition"
- }, functions, {
- "css": false
- }), slots) : vue.createVNode(vue.Transition, {
- "name": "dialog-transition"
- }, slots);
- };
- }
- });
- /** Animatable children (card, sheet, list) */
- function getChildren(el) {
- const els = el.querySelector(':scope > .v-card, :scope > .v-sheet, :scope > .v-list')?.children;
- return els && [...els];
- }
- function getDimensions(target, el) {
- const targetBox = target.getBoundingClientRect();
- const elBox = nullifyTransforms(el);
- const [originX, originY] = getComputedStyle(el).transformOrigin.split(' ').map(v => parseFloat(v));
- const [anchorSide, anchorOffset] = getComputedStyle(el).getPropertyValue('--v-overlay-anchor-origin').split(' ');
- let offsetX = targetBox.left + targetBox.width / 2;
- if (anchorSide === 'left' || anchorOffset === 'left') {
- offsetX -= targetBox.width / 2;
- } else if (anchorSide === 'right' || anchorOffset === 'right') {
- offsetX += targetBox.width / 2;
- }
- let offsetY = targetBox.top + targetBox.height / 2;
- if (anchorSide === 'top' || anchorOffset === 'top') {
- offsetY -= targetBox.height / 2;
- } else if (anchorSide === 'bottom' || anchorOffset === 'bottom') {
- offsetY += targetBox.height / 2;
- }
- const tsx = targetBox.width / elBox.width;
- const tsy = targetBox.height / elBox.height;
- const maxs = Math.max(1, tsx, tsy);
- const sx = tsx / maxs || 0;
- const sy = tsy / maxs || 0;
- // Animate elements larger than 12% of the screen area up to 1.5x slower
- const asa = elBox.width * elBox.height / (window.innerWidth * window.innerHeight);
- const speed = asa > 0.12 ? Math.min(1.5, (asa - 0.12) * 10 + 1) : 1;
- return {
- x: offsetX - (originX + elBox.left),
- y: offsetY - (originY + elBox.top),
- sx,
- sy,
- speed
- };
- }
- // Component specific transitions
- const VFabTransition = createCssTransition('fab-transition', 'center center', 'out-in');
- // Generic transitions
- const VDialogBottomTransition = createCssTransition('dialog-bottom-transition');
- const VDialogTopTransition = createCssTransition('dialog-top-transition');
- const VFadeTransition = createCssTransition('fade-transition');
- const VScaleTransition = createCssTransition('scale-transition');
- const VScrollXTransition = createCssTransition('scroll-x-transition');
- const VScrollXReverseTransition = createCssTransition('scroll-x-reverse-transition');
- const VScrollYTransition = createCssTransition('scroll-y-transition');
- const VScrollYReverseTransition = createCssTransition('scroll-y-reverse-transition');
- const VSlideXTransition = createCssTransition('slide-x-transition');
- const VSlideXReverseTransition = createCssTransition('slide-x-reverse-transition');
- const VSlideYTransition = createCssTransition('slide-y-transition');
- const VSlideYReverseTransition = createCssTransition('slide-y-reverse-transition');
- // Javascript transitions
- const VExpandTransition = createJavascriptTransition('expand-transition', ExpandTransitionGenerator());
- const VExpandXTransition = createJavascriptTransition('expand-x-transition', ExpandTransitionGenerator('', true));
- // Composables
- // Types
- const makeVDefaultsProviderProps = propsFactory({
- defaults: Object,
- disabled: Boolean,
- reset: [Number, String],
- root: [Boolean, String],
- scoped: Boolean
- }, 'VDefaultsProvider');
- const VDefaultsProvider = genericComponent(false)({
- name: 'VDefaultsProvider',
- props: makeVDefaultsProviderProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- defaults,
- disabled,
- reset,
- root,
- scoped
- } = vue.toRefs(props);
- provideDefaults(defaults, {
- reset,
- root,
- scoped,
- disabled
- });
- return () => slots.default?.();
- }
- });
- // Utilities
- // Types
- // Composables
- const makeDimensionProps = propsFactory({
- height: [Number, String],
- maxHeight: [Number, String],
- maxWidth: [Number, String],
- minHeight: [Number, String],
- minWidth: [Number, String],
- width: [Number, String]
- }, 'dimension');
- function useDimension(props) {
- const dimensionStyles = vue.computed(() => ({
- height: convertToUnit(props.height),
- maxHeight: convertToUnit(props.maxHeight),
- maxWidth: convertToUnit(props.maxWidth),
- minHeight: convertToUnit(props.minHeight),
- minWidth: convertToUnit(props.minWidth),
- width: convertToUnit(props.width)
- }));
- return {
- dimensionStyles
- };
- }
- function useAspectStyles(props) {
- return {
- aspectStyles: vue.computed(() => {
- const ratio = Number(props.aspectRatio);
- return ratio ? {
- paddingBottom: String(1 / ratio * 100) + '%'
- } : undefined;
- })
- };
- }
- const makeVResponsiveProps = propsFactory({
- aspectRatio: [String, Number],
- contentClass: String,
- inline: Boolean,
- ...makeComponentProps(),
- ...makeDimensionProps()
- }, 'VResponsive');
- const VResponsive = genericComponent()({
- name: 'VResponsive',
- props: makeVResponsiveProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- aspectStyles
- } = useAspectStyles(props);
- const {
- dimensionStyles
- } = useDimension(props);
- useRender(() => vue.createVNode("div", {
- "class": ['v-responsive', {
- 'v-responsive--inline': props.inline
- }, props.class],
- "style": [dimensionStyles.value, props.style]
- }, [vue.createVNode("div", {
- "class": "v-responsive__sizer",
- "style": aspectStyles.value
- }, null), slots.additional?.(), slots.default && vue.createVNode("div", {
- "class": ['v-responsive__content', props.contentClass]
- }, [slots.default()])]));
- return {};
- }
- });
- // Utilities
- // Types
- const makeTransitionProps = propsFactory({
- transition: {
- type: [Boolean, String, Object],
- default: 'fade-transition',
- validator: val => val !== true
- }
- }, 'transition');
- const MaybeTransition = (props, _ref) => {
- let {
- slots
- } = _ref;
- const {
- transition,
- disabled,
- ...rest
- } = props;
- const {
- component = vue.Transition,
- ...customProps
- } = typeof transition === 'object' ? transition : {};
- return vue.h(component, vue.mergeProps(typeof transition === 'string' ? {
- name: disabled ? '' : transition
- } : customProps, rest, {
- disabled
- }), slots);
- };
- // Utilities
- // Types
- function mounted$5(el, binding) {
- if (!SUPPORTS_INTERSECTION) return;
- const modifiers = binding.modifiers || {};
- const value = binding.value;
- const {
- handler,
- options
- } = typeof value === 'object' ? value : {
- handler: value,
- options: {}
- };
- const observer = new IntersectionObserver(function () {
- let entries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
- let observer = arguments.length > 1 ? arguments[1] : undefined;
- const _observe = el._observe?.[binding.instance.$.uid];
- if (!_observe) return; // Just in case, should never fire
- const isIntersecting = entries.some(entry => entry.isIntersecting);
- // If is not quiet or has already been
- // initted, invoke the user callback
- if (handler && (!modifiers.quiet || _observe.init) && (!modifiers.once || isIntersecting || _observe.init)) {
- handler(isIntersecting, entries, observer);
- }
- if (isIntersecting && modifiers.once) unmounted$5(el, binding);else _observe.init = true;
- }, options);
- el._observe = Object(el._observe);
- el._observe[binding.instance.$.uid] = {
- init: false,
- observer
- };
- observer.observe(el);
- }
- function unmounted$5(el, binding) {
- const observe = el._observe?.[binding.instance.$.uid];
- if (!observe) return;
- observe.observer.unobserve(el);
- delete el._observe[binding.instance.$.uid];
- }
- const Intersect = {
- mounted: mounted$5,
- unmounted: unmounted$5
- };
- // Types
- const makeVImgProps = propsFactory({
- alt: String,
- cover: Boolean,
- eager: Boolean,
- gradient: String,
- lazySrc: String,
- options: {
- type: Object,
- // For more information on types, navigate to:
- // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
- default: () => ({
- root: undefined,
- rootMargin: undefined,
- threshold: undefined
- })
- },
- sizes: String,
- src: {
- type: [String, Object],
- default: ''
- },
- srcset: String,
- ...makeVResponsiveProps(),
- ...makeComponentProps(),
- ...makeTransitionProps()
- }, 'VImg');
- const VImg = genericComponent()({
- name: 'VImg',
- directives: {
- intersect: Intersect
- },
- props: makeVImgProps(),
- emits: {
- loadstart: value => true,
- load: value => true,
- error: value => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const currentSrc = vue.shallowRef(''); // Set from srcset
- const image = vue.ref();
- const state = vue.shallowRef(props.eager ? 'loading' : 'idle');
- const naturalWidth = vue.shallowRef();
- const naturalHeight = vue.shallowRef();
- const normalisedSrc = vue.computed(() => {
- return props.src && typeof props.src === 'object' ? {
- src: props.src.src,
- srcset: props.srcset || props.src.srcset,
- lazySrc: props.lazySrc || props.src.lazySrc,
- aspect: Number(props.aspectRatio || props.src.aspect || 0)
- } : {
- src: props.src,
- srcset: props.srcset,
- lazySrc: props.lazySrc,
- aspect: Number(props.aspectRatio || 0)
- };
- });
- const aspectRatio = vue.computed(() => {
- return normalisedSrc.value.aspect || naturalWidth.value / naturalHeight.value || 0;
- });
- vue.watch(() => props.src, () => {
- init(state.value !== 'idle');
- });
- vue.watch(aspectRatio, (val, oldVal) => {
- if (!val && oldVal && image.value) {
- pollForSize(image.value);
- }
- });
- // TODO: getSrc when window width changes
- vue.onBeforeMount(() => init());
- function init(isIntersecting) {
- if (props.eager && isIntersecting) return;
- if (SUPPORTS_INTERSECTION && !isIntersecting && !props.eager) return;
- state.value = 'loading';
- if (normalisedSrc.value.lazySrc) {
- const lazyImg = new Image();
- lazyImg.src = normalisedSrc.value.lazySrc;
- pollForSize(lazyImg, null);
- }
- if (!normalisedSrc.value.src) return;
- vue.nextTick(() => {
- emit('loadstart', image.value?.currentSrc || normalisedSrc.value.src);
- if (image.value?.complete) {
- if (!image.value.naturalWidth) {
- onError();
- }
- if (state.value === 'error') return;
- if (!aspectRatio.value) pollForSize(image.value, null);
- onLoad();
- } else {
- if (!aspectRatio.value) pollForSize(image.value);
- getSrc();
- }
- });
- }
- function onLoad() {
- getSrc();
- state.value = 'loaded';
- emit('load', image.value?.currentSrc || normalisedSrc.value.src);
- }
- function onError() {
- state.value = 'error';
- emit('error', image.value?.currentSrc || normalisedSrc.value.src);
- }
- function getSrc() {
- const img = image.value;
- if (img) currentSrc.value = img.currentSrc || img.src;
- }
- let timer = -1;
- function pollForSize(img) {
- let timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100;
- const poll = () => {
- clearTimeout(timer);
- const {
- naturalHeight: imgHeight,
- naturalWidth: imgWidth
- } = img;
- if (imgHeight || imgWidth) {
- naturalWidth.value = imgWidth;
- naturalHeight.value = imgHeight;
- } else if (!img.complete && state.value === 'loading' && timeout != null) {
- timer = window.setTimeout(poll, timeout);
- } else if (img.currentSrc.endsWith('.svg') || img.currentSrc.startsWith('data:image/svg+xml')) {
- naturalWidth.value = 1;
- naturalHeight.value = 1;
- }
- };
- poll();
- }
- const containClasses = vue.computed(() => ({
- 'v-img__img--cover': props.cover,
- 'v-img__img--contain': !props.cover
- }));
- const __image = () => {
- if (!normalisedSrc.value.src || state.value === 'idle') return null;
- const img = vue.createVNode("img", {
- "class": ['v-img__img', containClasses.value],
- "src": normalisedSrc.value.src,
- "srcset": normalisedSrc.value.srcset,
- "alt": props.alt,
- "sizes": props.sizes,
- "ref": image,
- "onLoad": onLoad,
- "onError": onError
- }, null);
- const sources = slots.sources?.();
- return vue.createVNode(MaybeTransition, {
- "transition": props.transition,
- "appear": true
- }, {
- default: () => [vue.withDirectives(sources ? vue.createVNode("picture", {
- "class": "v-img__picture"
- }, [sources, img]) : img, [[vue.vShow, state.value === 'loaded']])]
- });
- };
- const __preloadImage = () => vue.createVNode(MaybeTransition, {
- "transition": props.transition
- }, {
- default: () => [normalisedSrc.value.lazySrc && state.value !== 'loaded' && vue.createVNode("img", {
- "class": ['v-img__img', 'v-img__img--preload', containClasses.value],
- "src": normalisedSrc.value.lazySrc,
- "alt": props.alt
- }, null)]
- });
- const __placeholder = () => {
- if (!slots.placeholder) return null;
- return vue.createVNode(MaybeTransition, {
- "transition": props.transition,
- "appear": true
- }, {
- default: () => [(state.value === 'loading' || state.value === 'error' && !slots.error) && vue.createVNode("div", {
- "class": "v-img__placeholder"
- }, [slots.placeholder()])]
- });
- };
- const __error = () => {
- if (!slots.error) return null;
- return vue.createVNode(MaybeTransition, {
- "transition": props.transition,
- "appear": true
- }, {
- default: () => [state.value === 'error' && vue.createVNode("div", {
- "class": "v-img__error"
- }, [slots.error()])]
- });
- };
- const __gradient = () => {
- if (!props.gradient) return null;
- return vue.createVNode("div", {
- "class": "v-img__gradient",
- "style": {
- backgroundImage: `linear-gradient(${props.gradient})`
- }
- }, null);
- };
- const isBooted = vue.shallowRef(false);
- {
- const stop = vue.watch(aspectRatio, val => {
- if (val) {
- // Doesn't work with nextTick, idk why
- requestAnimationFrame(() => {
- requestAnimationFrame(() => {
- isBooted.value = true;
- });
- });
- stop();
- }
- });
- }
- useRender(() => {
- const [responsiveProps] = VResponsive.filterProps(props);
- return vue.withDirectives(vue.createVNode(VResponsive, vue.mergeProps({
- "class": ['v-img', {
- 'v-img--booting': !isBooted.value
- }, props.class],
- "style": [{
- width: convertToUnit(props.width === 'auto' ? naturalWidth.value : props.width)
- }, props.style]
- }, responsiveProps, {
- "aspectRatio": aspectRatio.value,
- "aria-label": props.alt,
- "role": props.alt ? 'img' : undefined
- }), {
- additional: () => vue.createVNode(vue.Fragment, null, [vue.createVNode(__image, null, null), vue.createVNode(__preloadImage, null, null), vue.createVNode(__gradient, null, null), vue.createVNode(__placeholder, null, null), vue.createVNode(__error, null, null)]),
- default: slots.default
- }), [[vue.resolveDirective("intersect"), {
- handler: init,
- options: props.options
- }, null, {
- once: true
- }]]);
- });
- return {
- currentSrc,
- image,
- state,
- naturalWidth,
- naturalHeight
- };
- }
- });
- // Utilities
- // Types
- // Composables
- const makeBorderProps = propsFactory({
- border: [Boolean, Number, String]
- }, 'border');
- function useBorder(props) {
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- const borderClasses = vue.computed(() => {
- const border = vue.isRef(props) ? props.value : props.border;
- const classes = [];
- if (border === true || border === '') {
- classes.push(`${name}--border`);
- } else if (typeof border === 'string' || border === 0) {
- for (const value of String(border).split(' ')) {
- classes.push(`border-${value}`);
- }
- }
- return classes;
- });
- return {
- borderClasses
- };
- }
- // Utilities
- // Types
- // Composables
- function useColor(colors) {
- return destructComputed(() => {
- const classes = [];
- const styles = {};
- if (colors.value.background) {
- if (isCssColor(colors.value.background)) {
- styles.backgroundColor = colors.value.background;
- } else {
- classes.push(`bg-${colors.value.background}`);
- }
- }
- if (colors.value.text) {
- if (isCssColor(colors.value.text)) {
- styles.color = colors.value.text;
- styles.caretColor = colors.value.text;
- } else {
- classes.push(`text-${colors.value.text}`);
- }
- }
- return {
- colorClasses: classes,
- colorStyles: styles
- };
- });
- }
- function useTextColor(props, name) {
- const colors = vue.computed(() => ({
- text: vue.isRef(props) ? props.value : name ? props[name] : null
- }));
- const {
- colorClasses: textColorClasses,
- colorStyles: textColorStyles
- } = useColor(colors);
- return {
- textColorClasses,
- textColorStyles
- };
- }
- function useBackgroundColor(props, name) {
- const colors = vue.computed(() => ({
- background: vue.isRef(props) ? props.value : name ? props[name] : null
- }));
- const {
- colorClasses: backgroundColorClasses,
- colorStyles: backgroundColorStyles
- } = useColor(colors);
- return {
- backgroundColorClasses,
- backgroundColorStyles
- };
- }
- // Utilities
- // Types
- // Composables
- const makeElevationProps = propsFactory({
- elevation: {
- type: [Number, String],
- validator(v) {
- const value = parseInt(v);
- return !isNaN(value) && value >= 0 &&
- // Material Design has a maximum elevation of 24
- // https://material.io/design/environment/elevation.html#default-elevations
- value <= 24;
- }
- }
- }, 'elevation');
- function useElevation(props) {
- const elevationClasses = vue.computed(() => {
- const elevation = vue.isRef(props) ? props.value : props.elevation;
- const classes = [];
- if (elevation == null) return classes;
- classes.push(`elevation-${elevation}`);
- return classes;
- });
- return {
- elevationClasses
- };
- }
- // Utilities
- // Types
- // Composables
- const makeRoundedProps = propsFactory({
- rounded: {
- type: [Boolean, Number, String],
- default: undefined
- }
- }, 'rounded');
- function useRounded(props) {
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- const roundedClasses = vue.computed(() => {
- const rounded = vue.isRef(props) ? props.value : props.rounded;
- const classes = [];
- if (rounded === true || rounded === '') {
- classes.push(`${name}--rounded`);
- } else if (typeof rounded === 'string' || rounded === 0) {
- for (const value of String(rounded).split(' ')) {
- classes.push(`rounded-${value}`);
- }
- }
- return classes;
- });
- return {
- roundedClasses
- };
- }
- // Types
- const allowedDensities$1 = [null, 'prominent', 'default', 'comfortable', 'compact'];
- const makeVToolbarProps = propsFactory({
- absolute: Boolean,
- collapse: Boolean,
- color: String,
- density: {
- type: String,
- default: 'default',
- validator: v => allowedDensities$1.includes(v)
- },
- extended: Boolean,
- extensionHeight: {
- type: [Number, String],
- default: 48
- },
- flat: Boolean,
- floating: Boolean,
- height: {
- type: [Number, String],
- default: 64
- },
- image: String,
- title: String,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeElevationProps(),
- ...makeRoundedProps(),
- ...makeTagProps({
- tag: 'header'
- }),
- ...makeThemeProps()
- }, 'VToolbar');
- const VToolbar = genericComponent()({
- name: 'VToolbar',
- props: makeVToolbarProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- const {
- borderClasses
- } = useBorder(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- themeClasses
- } = provideTheme(props);
- const {
- rtlClasses
- } = useRtl();
- const isExtended = vue.shallowRef(!!(props.extended || slots.extension?.()));
- const contentHeight = vue.computed(() => parseInt(Number(props.height) + (props.density === 'prominent' ? Number(props.height) : 0) - (props.density === 'comfortable' ? 8 : 0) - (props.density === 'compact' ? 16 : 0), 10));
- const extensionHeight = vue.computed(() => isExtended.value ? parseInt(Number(props.extensionHeight) + (props.density === 'prominent' ? Number(props.extensionHeight) : 0) - (props.density === 'comfortable' ? 4 : 0) - (props.density === 'compact' ? 8 : 0), 10) : 0);
- provideDefaults({
- VBtn: {
- variant: 'text'
- }
- });
- useRender(() => {
- const hasTitle = !!(props.title || slots.title);
- const hasImage = !!(slots.image || props.image);
- const extension = slots.extension?.();
- isExtended.value = !!(props.extended || extension);
- return vue.createVNode(props.tag, {
- "class": ['v-toolbar', {
- 'v-toolbar--absolute': props.absolute,
- 'v-toolbar--collapse': props.collapse,
- 'v-toolbar--flat': props.flat,
- 'v-toolbar--floating': props.floating,
- [`v-toolbar--density-${props.density}`]: true
- }, backgroundColorClasses.value, borderClasses.value, elevationClasses.value, roundedClasses.value, themeClasses.value, rtlClasses.value, props.class],
- "style": [backgroundColorStyles.value, props.style]
- }, {
- default: () => [hasImage && vue.createVNode("div", {
- "key": "image",
- "class": "v-toolbar__image"
- }, [!slots.image ? vue.createVNode(VImg, {
- "key": "image-img",
- "cover": true,
- "src": props.image
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "image-defaults",
- "disabled": !props.image,
- "defaults": {
- VImg: {
- cover: true,
- src: props.image
- }
- }
- }, slots.image)]), vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VTabs: {
- height: convertToUnit(contentHeight.value)
- }
- }
- }, {
- default: () => [vue.createVNode("div", {
- "class": "v-toolbar__content",
- "style": {
- height: convertToUnit(contentHeight.value)
- }
- }, [slots.prepend && vue.createVNode("div", {
- "class": "v-toolbar__prepend"
- }, [slots.prepend?.()]), hasTitle && vue.createVNode(VToolbarTitle, {
- "key": "title",
- "text": props.title
- }, {
- text: slots.title
- }), slots.default?.(), slots.append && vue.createVNode("div", {
- "class": "v-toolbar__append"
- }, [slots.append?.()])])]
- }), vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VTabs: {
- height: convertToUnit(extensionHeight.value)
- }
- }
- }, {
- default: () => [vue.createVNode(VExpandTransition, null, {
- default: () => [isExtended.value && vue.createVNode("div", {
- "class": "v-toolbar__extension",
- "style": {
- height: convertToUnit(extensionHeight.value)
- }
- }, [extension])]
- })]
- })]
- });
- });
- return {
- contentHeight,
- extensionHeight
- };
- }
- });
- // Utilities
- // Types
- // Composables
- const makeScrollProps = propsFactory({
- scrollTarget: {
- type: String
- },
- scrollThreshold: {
- type: [String, Number],
- default: 300
- }
- }, 'scroll');
- function useScroll(props) {
- let args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
- const {
- canScroll
- } = args;
- let previousScroll = 0;
- const target = vue.ref(null);
- const currentScroll = vue.shallowRef(0);
- const savedScroll = vue.shallowRef(0);
- const currentThreshold = vue.shallowRef(0);
- const isScrollActive = vue.shallowRef(false);
- const isScrollingUp = vue.shallowRef(false);
- const scrollThreshold = vue.computed(() => {
- return Number(props.scrollThreshold);
- });
- /**
- * 1: at top
- * 0: at threshold
- */
- const scrollRatio = vue.computed(() => {
- return clamp((scrollThreshold.value - currentScroll.value) / scrollThreshold.value || 0);
- });
- const onScroll = () => {
- const targetEl = target.value;
- if (!targetEl || canScroll && !canScroll.value) return;
- previousScroll = currentScroll.value;
- currentScroll.value = 'window' in targetEl ? targetEl.pageYOffset : targetEl.scrollTop;
- isScrollingUp.value = currentScroll.value < previousScroll;
- currentThreshold.value = Math.abs(currentScroll.value - scrollThreshold.value);
- };
- vue.watch(isScrollingUp, () => {
- savedScroll.value = savedScroll.value || currentScroll.value;
- });
- vue.watch(isScrollActive, () => {
- savedScroll.value = 0;
- });
- vue.onMounted(() => {
- vue.watch(() => props.scrollTarget, scrollTarget => {
- const newTarget = scrollTarget ? document.querySelector(scrollTarget) : window;
- if (!newTarget) {
- consoleWarn(`Unable to locate element with identifier ${scrollTarget}`);
- return;
- }
- if (newTarget === target.value) return;
- target.value?.removeEventListener('scroll', onScroll);
- target.value = newTarget;
- target.value.addEventListener('scroll', onScroll, {
- passive: true
- });
- }, {
- immediate: true
- });
- });
- vue.onBeforeUnmount(() => {
- target.value?.removeEventListener('scroll', onScroll);
- });
- // Do we need this? If yes - seems that
- // there's no need to expose onScroll
- canScroll && vue.watch(canScroll, onScroll, {
- immediate: true
- });
- return {
- scrollThreshold,
- currentScroll,
- currentThreshold,
- isScrollActive,
- scrollRatio,
- // required only for testing
- // probably can be removed
- // later (2 chars chlng)
- isScrollingUp,
- savedScroll
- };
- }
- // Utilities
- // Composables
- function useSsrBoot() {
- const isBooted = vue.shallowRef(false);
- vue.onMounted(() => {
- window.requestAnimationFrame(() => {
- isBooted.value = true;
- });
- });
- const ssrBootStyles = vue.computed(() => !isBooted.value ? {
- transition: 'none !important'
- } : undefined);
- return {
- ssrBootStyles,
- isBooted: vue.readonly(isBooted)
- };
- }
- // Types
- const makeVAppBarProps = propsFactory({
- scrollBehavior: String,
- modelValue: {
- type: Boolean,
- default: true
- },
- location: {
- type: String,
- default: 'top',
- validator: value => ['top', 'bottom'].includes(value)
- },
- ...makeVToolbarProps(),
- ...makeLayoutItemProps(),
- ...makeScrollProps(),
- height: {
- type: [Number, String],
- default: 64
- }
- }, 'VAppBar');
- const VAppBar = genericComponent()({
- name: 'VAppBar',
- props: makeVAppBarProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const vToolbarRef = vue.ref();
- const isActive = useProxiedModel(props, 'modelValue');
- const scrollBehavior = vue.computed(() => {
- const behavior = new Set(props.scrollBehavior?.split(' ') ?? []);
- return {
- hide: behavior.has('hide'),
- // fullyHide: behavior.has('fully-hide'),
- inverted: behavior.has('inverted'),
- collapse: behavior.has('collapse'),
- elevate: behavior.has('elevate'),
- fadeImage: behavior.has('fade-image')
- // shrink: behavior.has('shrink'),
- };
- });
- const canScroll = vue.computed(() => {
- const behavior = scrollBehavior.value;
- return behavior.hide ||
- // behavior.fullyHide ||
- behavior.inverted || behavior.collapse || behavior.elevate || behavior.fadeImage ||
- // behavior.shrink ||
- !isActive.value;
- });
- const {
- currentScroll,
- scrollThreshold,
- isScrollingUp,
- scrollRatio
- } = useScroll(props, {
- canScroll
- });
- const isCollapsed = vue.computed(() => props.collapse || scrollBehavior.value.collapse && (scrollBehavior.value.inverted ? scrollRatio.value > 0 : scrollRatio.value === 0));
- const isFlat = vue.computed(() => props.flat || scrollBehavior.value.elevate && (scrollBehavior.value.inverted ? currentScroll.value > 0 : currentScroll.value === 0));
- const opacity = vue.computed(() => scrollBehavior.value.fadeImage ? scrollBehavior.value.inverted ? 1 - scrollRatio.value : scrollRatio.value : undefined);
- const height = vue.computed(() => {
- if (scrollBehavior.value.hide && scrollBehavior.value.inverted) return 0;
- const height = vToolbarRef.value?.contentHeight ?? 0;
- const extensionHeight = vToolbarRef.value?.extensionHeight ?? 0;
- return height + extensionHeight;
- });
- useToggleScope(vue.computed(() => !!props.scrollBehavior), () => {
- vue.watchEffect(() => {
- if (scrollBehavior.value.hide) {
- if (scrollBehavior.value.inverted) {
- isActive.value = currentScroll.value > scrollThreshold.value;
- } else {
- isActive.value = isScrollingUp.value || currentScroll.value < scrollThreshold.value;
- }
- } else {
- isActive.value = true;
- }
- });
- });
- const {
- ssrBootStyles
- } = useSsrBoot();
- const {
- layoutItemStyles
- } = useLayoutItem({
- id: props.name,
- order: vue.computed(() => parseInt(props.order, 10)),
- position: vue.toRef(props, 'location'),
- layoutSize: height,
- elementSize: vue.shallowRef(undefined),
- active: isActive,
- absolute: vue.toRef(props, 'absolute')
- });
- useRender(() => {
- const [toolbarProps] = VToolbar.filterProps(props);
- return vue.createVNode(VToolbar, vue.mergeProps({
- "ref": vToolbarRef,
- "class": ['v-app-bar', {
- 'v-app-bar--bottom': props.location === 'bottom'
- }, props.class],
- "style": [{
- ...layoutItemStyles.value,
- '--v-toolbar-image-opacity': opacity.value,
- height: undefined,
- ...ssrBootStyles.value
- }, props.style]
- }, toolbarProps, {
- "collapse": isCollapsed.value,
- "flat": isFlat.value
- }), slots);
- });
- return {};
- }
- });
- // Utilities
- // Types
- const allowedDensities = [null, 'default', 'comfortable', 'compact'];
- // typeof allowedDensities[number] evalutes to any
- // when generating api types for whatever reason.
- // Composables
- const makeDensityProps = propsFactory({
- density: {
- type: String,
- default: 'default',
- validator: v => allowedDensities.includes(v)
- }
- }, 'density');
- function useDensity(props) {
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- const densityClasses = vue.computed(() => {
- return `${name}--density-${props.density}`;
- });
- return {
- densityClasses
- };
- }
- // Types
- const allowedVariants$2 = ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain'];
- function genOverlays(isClickable, name) {
- return vue.createVNode(vue.Fragment, null, [isClickable && vue.createVNode("span", {
- "key": "overlay",
- "class": `${name}__overlay`
- }, null), vue.createVNode("span", {
- "key": "underlay",
- "class": `${name}__underlay`
- }, null)]);
- }
- const makeVariantProps = propsFactory({
- color: String,
- variant: {
- type: String,
- default: 'elevated',
- validator: v => allowedVariants$2.includes(v)
- }
- }, 'variant');
- function useVariant(props) {
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- const variantClasses = vue.computed(() => {
- const {
- variant
- } = vue.unref(props);
- return `${name}--variant-${variant}`;
- });
- const {
- colorClasses,
- colorStyles
- } = useColor(vue.computed(() => {
- const {
- variant,
- color
- } = vue.unref(props);
- return {
- [['elevated', 'flat'].includes(variant) ? 'background' : 'text']: color
- };
- }));
- return {
- colorClasses,
- colorStyles,
- variantClasses
- };
- }
- const makeVBtnGroupProps = propsFactory({
- divided: Boolean,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeElevationProps(),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeThemeProps(),
- ...makeVariantProps()
- }, 'VBtnGroup');
- const VBtnGroup = genericComponent()({
- name: 'VBtnGroup',
- props: makeVBtnGroupProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- densityClasses
- } = useDensity(props);
- const {
- borderClasses
- } = useBorder(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- roundedClasses
- } = useRounded(props);
- provideDefaults({
- VBtn: {
- height: 'auto',
- color: vue.toRef(props, 'color'),
- density: vue.toRef(props, 'density'),
- flat: true,
- variant: vue.toRef(props, 'variant')
- }
- });
- useRender(() => {
- return vue.createVNode(props.tag, {
- "class": ['v-btn-group', {
- 'v-btn-group--divided': props.divided
- }, themeClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, roundedClasses.value, props.class],
- "style": props.style
- }, slots);
- });
- }
- });
- // Composables
- // Types
- const makeGroupProps = propsFactory({
- modelValue: {
- type: null,
- default: undefined
- },
- multiple: Boolean,
- mandatory: [Boolean, String],
- max: Number,
- selectedClass: String,
- disabled: Boolean
- }, 'group');
- const makeGroupItemProps = propsFactory({
- value: null,
- disabled: Boolean,
- selectedClass: String
- }, 'group-item');
- function useGroupItem(props, injectKey) {
- let required = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
- const vm = getCurrentInstance('useGroupItem');
- if (!vm) {
- throw new Error('[Vuetify] useGroupItem composable must be used inside a component setup function');
- }
- const id = getUid();
- vue.provide(Symbol.for(`${injectKey.description}:id`), id);
- const group = vue.inject(injectKey, null);
- if (!group) {
- if (!required) return group;
- throw new Error(`[Vuetify] Could not find useGroup injection with symbol ${injectKey.description}`);
- }
- const value = vue.toRef(props, 'value');
- const disabled = vue.computed(() => !!(group.disabled.value || props.disabled));
- group.register({
- id,
- value,
- disabled
- }, vm);
- vue.onBeforeUnmount(() => {
- group.unregister(id);
- });
- const isSelected = vue.computed(() => {
- return group.isSelected(id);
- });
- const selectedClass = vue.computed(() => isSelected.value && [group.selectedClass.value, props.selectedClass]);
- vue.watch(isSelected, value => {
- vm.emit('group:selected', {
- value
- });
- });
- return {
- id,
- isSelected,
- toggle: () => group.select(id, !isSelected.value),
- select: value => group.select(id, value),
- selectedClass,
- value,
- disabled,
- group
- };
- }
- function useGroup(props, injectKey) {
- let isUnmounted = false;
- const items = vue.reactive([]);
- const selected = useProxiedModel(props, 'modelValue', [], v => {
- if (v == null) return [];
- return getIds(items, wrapInArray(v));
- }, v => {
- const arr = getValues(items, v);
- return props.multiple ? arr : arr[0];
- });
- const groupVm = getCurrentInstance('useGroup');
- function register(item, vm) {
- // Is there a better way to fix this typing?
- const unwrapped = item;
- const key = Symbol.for(`${injectKey.description}:id`);
- const children = findChildrenWithProvide(key, groupVm?.vnode);
- const index = children.indexOf(vm);
- if (index > -1) {
- items.splice(index, 0, unwrapped);
- } else {
- items.push(unwrapped);
- }
- }
- function unregister(id) {
- if (isUnmounted) return;
- // TODO: re-evaluate this line's importance in the future
- // should we only modify the model if mandatory is set.
- // selected.value = selected.value.filter(v => v !== id)
- forceMandatoryValue();
- const index = items.findIndex(item => item.id === id);
- items.splice(index, 1);
- }
- // If mandatory and nothing is selected, then select first non-disabled item
- function forceMandatoryValue() {
- const item = items.find(item => !item.disabled);
- if (item && props.mandatory === 'force' && !selected.value.length) {
- selected.value = [item.id];
- }
- }
- vue.onMounted(() => {
- forceMandatoryValue();
- });
- vue.onBeforeUnmount(() => {
- isUnmounted = true;
- });
- function select(id, value) {
- const item = items.find(item => item.id === id);
- if (value && item?.disabled) return;
- if (props.multiple) {
- const internalValue = selected.value.slice();
- const index = internalValue.findIndex(v => v === id);
- const isSelected = ~index;
- value = value ?? !isSelected;
- // We can't remove value if group is
- // mandatory, value already exists,
- // and it is the only value
- if (isSelected && props.mandatory && internalValue.length <= 1) return;
- // We can't add value if it would
- // cause max limit to be exceeded
- if (!isSelected && props.max != null && internalValue.length + 1 > props.max) return;
- if (index < 0 && value) internalValue.push(id);else if (index >= 0 && !value) internalValue.splice(index, 1);
- selected.value = internalValue;
- } else {
- const isSelected = selected.value.includes(id);
- if (props.mandatory && isSelected) return;
- selected.value = value ?? !isSelected ? [id] : [];
- }
- }
- function step(offset) {
- // getting an offset from selected value obviously won't work with multiple values
- if (props.multiple) consoleWarn('This method is not supported when using "multiple" prop');
- if (!selected.value.length) {
- const item = items.find(item => !item.disabled);
- item && (selected.value = [item.id]);
- } else {
- const currentId = selected.value[0];
- const currentIndex = items.findIndex(i => i.id === currentId);
- let newIndex = (currentIndex + offset) % items.length;
- let newItem = items[newIndex];
- while (newItem.disabled && newIndex !== currentIndex) {
- newIndex = (newIndex + offset) % items.length;
- newItem = items[newIndex];
- }
- if (newItem.disabled) return;
- selected.value = [items[newIndex].id];
- }
- }
- const state = {
- register,
- unregister,
- selected,
- select,
- disabled: vue.toRef(props, 'disabled'),
- prev: () => step(items.length - 1),
- next: () => step(1),
- isSelected: id => selected.value.includes(id),
- selectedClass: vue.computed(() => props.selectedClass),
- items: vue.computed(() => items),
- getItemIndex: value => getItemIndex(items, value)
- };
- vue.provide(injectKey, state);
- return state;
- }
- function getItemIndex(items, value) {
- const ids = getIds(items, [value]);
- if (!ids.length) return -1;
- return items.findIndex(item => item.id === ids[0]);
- }
- function getIds(items, modelValue) {
- const ids = [];
- modelValue.forEach(value => {
- const item = items.find(item => deepEqual(value, item.value));
- const itemByIndex = items[value];
- if (item?.value != null) {
- ids.push(item.id);
- } else if (itemByIndex != null) {
- ids.push(itemByIndex.id);
- }
- });
- return ids;
- }
- function getValues(items, ids) {
- const values = [];
- ids.forEach(id => {
- const itemIndex = items.findIndex(item => item.id === id);
- if (~itemIndex) {
- const item = items[itemIndex];
- values.push(item.value != null ? item.value : itemIndex);
- }
- });
- return values;
- }
- // Types
- const VBtnToggleSymbol = Symbol.for('vuetify:v-btn-toggle');
- const makeVBtnToggleProps = propsFactory({
- ...makeVBtnGroupProps(),
- ...makeGroupProps()
- }, 'VBtnToggle');
- const VBtnToggle = genericComponent()({
- name: 'VBtnToggle',
- props: makeVBtnToggleProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- isSelected,
- next,
- prev,
- select,
- selected
- } = useGroup(props, VBtnToggleSymbol);
- useRender(() => {
- const [btnGroupProps] = VBtnGroup.filterProps(props);
- return vue.createVNode(VBtnGroup, vue.mergeProps({
- "class": ['v-btn-toggle', props.class]
- }, btnGroupProps, {
- "style": props.style
- }), {
- default: () => [slots.default?.({
- isSelected,
- next,
- prev,
- select,
- selected
- })]
- });
- });
- return {
- next,
- prev,
- select
- };
- }
- });
- // Composables
- // Types
- const aliases = {
- collapse: 'mdi-chevron-up',
- complete: 'mdi-check',
- cancel: 'mdi-close-circle',
- close: 'mdi-close',
- delete: 'mdi-close-circle',
- // delete (e.g. v-chip close)
- clear: 'mdi-close-circle',
- success: 'mdi-check-circle',
- info: 'mdi-information',
- warning: 'mdi-alert-circle',
- error: 'mdi-close-circle',
- prev: 'mdi-chevron-left',
- next: 'mdi-chevron-right',
- checkboxOn: 'mdi-checkbox-marked',
- checkboxOff: 'mdi-checkbox-blank-outline',
- checkboxIndeterminate: 'mdi-minus-box',
- delimiter: 'mdi-circle',
- // for carousel
- sortAsc: 'mdi-arrow-up',
- sortDesc: 'mdi-arrow-down',
- expand: 'mdi-chevron-down',
- menu: 'mdi-menu',
- subgroup: 'mdi-menu-down',
- dropdown: 'mdi-menu-down',
- radioOn: 'mdi-radiobox-marked',
- radioOff: 'mdi-radiobox-blank',
- edit: 'mdi-pencil',
- ratingEmpty: 'mdi-star-outline',
- ratingFull: 'mdi-star',
- ratingHalf: 'mdi-star-half-full',
- loading: 'mdi-cached',
- first: 'mdi-page-first',
- last: 'mdi-page-last',
- unfold: 'mdi-unfold-more-horizontal',
- file: 'mdi-paperclip',
- plus: 'mdi-plus',
- minus: 'mdi-minus',
- calendar: 'mdi-calendar'
- };
- const mdi = {
- // Not using mergeProps here, functional components merge props by default (?)
- component: props => vue.h(VClassIcon, {
- ...props,
- class: 'mdi'
- })
- };
- // Types
- const IconValue = [String, Function, Object, Array];
- const IconSymbol = Symbol.for('vuetify:icons');
- const makeIconProps = propsFactory({
- icon: {
- type: IconValue
- },
- // Could not remove this and use makeTagProps, types complained because it is not required
- tag: {
- type: String,
- required: true
- }
- }, 'icon');
- const VComponentIcon = genericComponent()({
- name: 'VComponentIcon',
- props: makeIconProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- return () => {
- const Icon = props.icon;
- return vue.createVNode(props.tag, null, {
- default: () => [props.icon ? vue.createVNode(Icon, null, null) : slots.default?.()]
- });
- };
- }
- });
- const VSvgIcon = defineComponent({
- name: 'VSvgIcon',
- inheritAttrs: false,
- props: makeIconProps(),
- setup(props, _ref2) {
- let {
- attrs
- } = _ref2;
- return () => {
- return vue.createVNode(props.tag, vue.mergeProps(attrs, {
- "style": null
- }), {
- default: () => [vue.createVNode("svg", {
- "class": "v-icon__svg",
- "xmlns": "http://www.w3.org/2000/svg",
- "viewBox": "0 0 24 24",
- "role": "img",
- "aria-hidden": "true"
- }, [Array.isArray(props.icon) ? props.icon.map(path => Array.isArray(path) ? vue.createVNode("path", {
- "d": path[0],
- "fill-opacity": path[1]
- }, null) : vue.createVNode("path", {
- "d": path
- }, null)) : vue.createVNode("path", {
- "d": props.icon
- }, null)])]
- });
- };
- }
- });
- const VLigatureIcon = defineComponent({
- name: 'VLigatureIcon',
- props: makeIconProps(),
- setup(props) {
- return () => {
- return vue.createVNode(props.tag, null, {
- default: () => [props.icon]
- });
- };
- }
- });
- const VClassIcon = defineComponent({
- name: 'VClassIcon',
- props: makeIconProps(),
- setup(props) {
- return () => {
- return vue.createVNode(props.tag, {
- "class": props.icon
- }, null);
- };
- }
- });
- const defaultSets = {
- svg: {
- component: VSvgIcon
- },
- class: {
- component: VClassIcon
- }
- };
- // Composables
- function createIcons(options) {
- return mergeDeep({
- defaultSet: 'mdi',
- sets: {
- ...defaultSets,
- mdi
- },
- aliases: {
- ...aliases,
- /* eslint-disable max-len */
- vuetify: ['M8.2241 14.2009L12 21L22 3H14.4459L8.2241 14.2009Z', ['M7.26303 12.4733L7.00113 12L2 3H12.5261C12.5261 3 12.5261 3 12.5261 3L7.26303 12.4733Z', 0.6]],
- 'vuetify-outline': 'svg:M7.26 12.47 12.53 3H2L7.26 12.47ZM14.45 3 8.22 14.2 12 21 22 3H14.45ZM18.6 5 12 16.88 10.51 14.2 15.62 5ZM7.26 8.35 5.4 5H9.13L7.26 8.35Z'
- /* eslint-enable max-len */
- }
- }, options);
- }
- const useIcon = props => {
- const icons = vue.inject(IconSymbol);
- if (!icons) throw new Error('Missing Vuetify Icons provide!');
- const iconData = vue.computed(() => {
- const iconAlias = vue.unref(props);
- if (!iconAlias) return {
- component: VComponentIcon
- };
- let icon = iconAlias;
- if (typeof icon === 'string') {
- icon = icon.trim();
- if (icon.startsWith('$')) {
- icon = icons.aliases?.[icon.slice(1)];
- }
- }
- if (!icon) throw new Error(`Could not find aliased icon "${iconAlias}"`);
- if (Array.isArray(icon)) {
- return {
- component: VSvgIcon,
- icon
- };
- } else if (typeof icon !== 'string') {
- return {
- component: VComponentIcon,
- icon
- };
- }
- const iconSetName = Object.keys(icons.sets).find(setName => typeof icon === 'string' && icon.startsWith(`${setName}:`));
- const iconName = iconSetName ? icon.slice(iconSetName.length + 1) : icon;
- const iconSet = icons.sets[iconSetName ?? icons.defaultSet];
- return {
- component: iconSet.component,
- icon: iconName
- };
- });
- return {
- iconData
- };
- };
- // Utilities
- // Types
- const predefinedSizes = ['x-small', 'small', 'default', 'large', 'x-large'];
- // Composables
- const makeSizeProps = propsFactory({
- size: {
- type: [String, Number],
- default: 'default'
- }
- }, 'size');
- function useSize(props) {
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- return destructComputed(() => {
- let sizeClasses;
- let sizeStyles;
- if (includes(predefinedSizes, props.size)) {
- sizeClasses = `${name}--size-${props.size}`;
- } else if (props.size) {
- sizeStyles = {
- width: convertToUnit(props.size),
- height: convertToUnit(props.size)
- };
- }
- return {
- sizeClasses,
- sizeStyles
- };
- });
- }
- const makeVIconProps = propsFactory({
- color: String,
- start: Boolean,
- end: Boolean,
- icon: IconValue,
- ...makeComponentProps(),
- ...makeSizeProps(),
- ...makeTagProps({
- tag: 'i'
- }),
- ...makeThemeProps()
- }, 'VIcon');
- const VIcon = genericComponent()({
- name: 'VIcon',
- props: makeVIconProps(),
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const slotIcon = vue.ref();
- const {
- themeClasses
- } = provideTheme(props);
- const {
- iconData
- } = useIcon(vue.computed(() => slotIcon.value || props.icon));
- const {
- sizeClasses
- } = useSize(props);
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.toRef(props, 'color'));
- useRender(() => {
- const slotValue = slots.default?.();
- if (slotValue) {
- slotIcon.value = flattenFragments(slotValue).filter(node => node.type === vue.Text && node.children && typeof node.children === 'string')[0]?.children;
- }
- return vue.createVNode(iconData.value.component, {
- "tag": props.tag,
- "icon": iconData.value.icon,
- "class": ['v-icon', 'notranslate', themeClasses.value, sizeClasses.value, textColorClasses.value, {
- 'v-icon--clickable': !!attrs.onClick,
- 'v-icon--start': props.start,
- 'v-icon--end': props.end
- }, props.class],
- "style": [!sizeClasses.value ? {
- fontSize: convertToUnit(props.size),
- height: convertToUnit(props.size),
- width: convertToUnit(props.size)
- } : undefined, textColorStyles.value, props.style],
- "role": attrs.onClick ? 'button' : undefined,
- "aria-hidden": !attrs.onClick
- }, {
- default: () => [slotValue]
- });
- });
- return {};
- }
- });
- // Utilities
- function useIntersectionObserver(callback, options) {
- const intersectionRef = vue.ref();
- const isIntersecting = vue.shallowRef(false);
- if (SUPPORTS_INTERSECTION) {
- const observer = new IntersectionObserver(entries => {
- callback?.(entries, observer);
- isIntersecting.value = !!entries.find(entry => entry.isIntersecting);
- }, options);
- vue.onBeforeUnmount(() => {
- observer.disconnect();
- });
- vue.watch(intersectionRef, (newValue, oldValue) => {
- if (oldValue) {
- observer.unobserve(oldValue);
- isIntersecting.value = false;
- }
- if (newValue) observer.observe(newValue);
- }, {
- flush: 'post'
- });
- }
- return {
- intersectionRef,
- isIntersecting
- };
- }
- // Types
- const makeVProgressCircularProps = propsFactory({
- bgColor: String,
- color: String,
- indeterminate: [Boolean, String],
- modelValue: {
- type: [Number, String],
- default: 0
- },
- rotate: {
- type: [Number, String],
- default: 0
- },
- width: {
- type: [Number, String],
- default: 4
- },
- ...makeComponentProps(),
- ...makeSizeProps(),
- ...makeTagProps({
- tag: 'div'
- }),
- ...makeThemeProps()
- }, 'VProgressCircular');
- const VProgressCircular = genericComponent()({
- name: 'VProgressCircular',
- props: makeVProgressCircularProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const MAGIC_RADIUS_CONSTANT = 20;
- const CIRCUMFERENCE = 2 * Math.PI * MAGIC_RADIUS_CONSTANT;
- const root = vue.ref();
- const {
- themeClasses
- } = provideTheme(props);
- const {
- sizeClasses,
- sizeStyles
- } = useSize(props);
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.toRef(props, 'color'));
- const {
- textColorClasses: underlayColorClasses,
- textColorStyles: underlayColorStyles
- } = useTextColor(vue.toRef(props, 'bgColor'));
- const {
- intersectionRef,
- isIntersecting
- } = useIntersectionObserver();
- const {
- resizeRef,
- contentRect
- } = useResizeObserver();
- const normalizedValue = vue.computed(() => Math.max(0, Math.min(100, parseFloat(props.modelValue))));
- const width = vue.computed(() => Number(props.width));
- const size = vue.computed(() => {
- // Get size from element if size prop value is small, large etc
- return sizeStyles.value ? Number(props.size) : contentRect.value ? contentRect.value.width : Math.max(width.value, 32);
- });
- const diameter = vue.computed(() => MAGIC_RADIUS_CONSTANT / (1 - width.value / size.value) * 2);
- const strokeWidth = vue.computed(() => width.value / size.value * diameter.value);
- const strokeDashOffset = vue.computed(() => convertToUnit((100 - normalizedValue.value) / 100 * CIRCUMFERENCE));
- vue.watchEffect(() => {
- intersectionRef.value = root.value;
- resizeRef.value = root.value;
- });
- useRender(() => vue.createVNode(props.tag, {
- "ref": root,
- "class": ['v-progress-circular', {
- 'v-progress-circular--indeterminate': !!props.indeterminate,
- 'v-progress-circular--visible': isIntersecting.value,
- 'v-progress-circular--disable-shrink': props.indeterminate === 'disable-shrink'
- }, themeClasses.value, sizeClasses.value, textColorClasses.value, props.class],
- "style": [sizeStyles.value, textColorStyles.value, props.style],
- "role": "progressbar",
- "aria-valuemin": "0",
- "aria-valuemax": "100",
- "aria-valuenow": props.indeterminate ? undefined : normalizedValue.value
- }, {
- default: () => [vue.createVNode("svg", {
- "style": {
- transform: `rotate(calc(-90deg + ${Number(props.rotate)}deg))`
- },
- "xmlns": "http://www.w3.org/2000/svg",
- "viewBox": `0 0 ${diameter.value} ${diameter.value}`
- }, [vue.createVNode("circle", {
- "class": ['v-progress-circular__underlay', underlayColorClasses.value],
- "style": underlayColorStyles.value,
- "fill": "transparent",
- "cx": "50%",
- "cy": "50%",
- "r": MAGIC_RADIUS_CONSTANT,
- "stroke-width": strokeWidth.value,
- "stroke-dasharray": CIRCUMFERENCE,
- "stroke-dashoffset": 0
- }, null), vue.createVNode("circle", {
- "class": "v-progress-circular__overlay",
- "fill": "transparent",
- "cx": "50%",
- "cy": "50%",
- "r": MAGIC_RADIUS_CONSTANT,
- "stroke-width": strokeWidth.value,
- "stroke-dasharray": CIRCUMFERENCE,
- "stroke-dashoffset": strokeDashOffset.value
- }, null)]), slots.default && vue.createVNode("div", {
- "class": "v-progress-circular__content"
- }, [slots.default({
- value: normalizedValue.value
- })])]
- }));
- return {};
- }
- });
- // Composables
- // Types
- const oppositeMap = {
- center: 'center',
- top: 'bottom',
- bottom: 'top',
- left: 'right',
- right: 'left'
- };
- const makeLocationProps = propsFactory({
- location: String
- }, 'location');
- function useLocation(props) {
- let opposite = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
- let offset = arguments.length > 2 ? arguments[2] : undefined;
- const {
- isRtl
- } = useRtl();
- const locationStyles = vue.computed(() => {
- if (!props.location) return {};
- const {
- side,
- align
- } = parseAnchor(props.location.split(' ').length > 1 ? props.location : `${props.location} center`, isRtl.value);
- function getOffset(side) {
- return offset ? offset(side) : 0;
- }
- const styles = {};
- if (side !== 'center') {
- if (opposite) styles[oppositeMap[side]] = `calc(100% - ${getOffset(side)}px)`;else styles[side] = 0;
- }
- if (align !== 'center') {
- if (opposite) styles[oppositeMap[align]] = `calc(100% - ${getOffset(align)}px)`;else styles[align] = 0;
- } else {
- if (side === 'center') styles.top = styles.left = '50%';else {
- styles[{
- top: 'left',
- bottom: 'left',
- left: 'top',
- right: 'top'
- }[side]] = '50%';
- }
- styles.transform = {
- top: 'translateX(-50%)',
- bottom: 'translateX(-50%)',
- left: 'translateY(-50%)',
- right: 'translateY(-50%)',
- center: 'translate(-50%, -50%)'
- }[side];
- }
- return styles;
- });
- return {
- locationStyles
- };
- }
- const makeVProgressLinearProps = propsFactory({
- absolute: Boolean,
- active: {
- type: Boolean,
- default: true
- },
- bgColor: String,
- bgOpacity: [Number, String],
- bufferValue: {
- type: [Number, String],
- default: 0
- },
- clickable: Boolean,
- color: String,
- height: {
- type: [Number, String],
- default: 4
- },
- indeterminate: Boolean,
- max: {
- type: [Number, String],
- default: 100
- },
- modelValue: {
- type: [Number, String],
- default: 0
- },
- reverse: Boolean,
- stream: Boolean,
- striped: Boolean,
- roundedBar: Boolean,
- ...makeComponentProps(),
- ...makeLocationProps({
- location: 'top'
- }),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VProgressLinear');
- const VProgressLinear = genericComponent()({
- name: 'VProgressLinear',
- props: makeVProgressLinearProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const progress = useProxiedModel(props, 'modelValue');
- const {
- isRtl,
- rtlClasses
- } = useRtl();
- const {
- themeClasses
- } = provideTheme(props);
- const {
- locationStyles
- } = useLocation(props);
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(props, 'color');
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.computed(() => props.bgColor || props.color));
- const {
- backgroundColorClasses: barColorClasses,
- backgroundColorStyles: barColorStyles
- } = useBackgroundColor(props, 'color');
- const {
- roundedClasses
- } = useRounded(props);
- const {
- intersectionRef,
- isIntersecting
- } = useIntersectionObserver();
- const max = vue.computed(() => parseInt(props.max, 10));
- const height = vue.computed(() => parseInt(props.height, 10));
- const normalizedBuffer = vue.computed(() => parseFloat(props.bufferValue) / max.value * 100);
- const normalizedValue = vue.computed(() => parseFloat(progress.value) / max.value * 100);
- const isReversed = vue.computed(() => isRtl.value !== props.reverse);
- const transition = vue.computed(() => props.indeterminate ? 'fade-transition' : 'slide-x-transition');
- const opacity = vue.computed(() => {
- return props.bgOpacity == null ? props.bgOpacity : parseFloat(props.bgOpacity);
- });
- function handleClick(e) {
- if (!intersectionRef.value) return;
- const {
- left,
- right,
- width
- } = intersectionRef.value.getBoundingClientRect();
- const value = isReversed.value ? width - e.clientX + (right - width) : e.clientX - left;
- progress.value = Math.round(value / width * max.value);
- }
- useRender(() => vue.createVNode(props.tag, {
- "ref": intersectionRef,
- "class": ['v-progress-linear', {
- 'v-progress-linear--absolute': props.absolute,
- 'v-progress-linear--active': props.active && isIntersecting.value,
- 'v-progress-linear--reverse': isReversed.value,
- 'v-progress-linear--rounded': props.rounded,
- 'v-progress-linear--rounded-bar': props.roundedBar,
- 'v-progress-linear--striped': props.striped
- }, roundedClasses.value, themeClasses.value, rtlClasses.value, props.class],
- "style": [{
- bottom: props.location === 'bottom' ? 0 : undefined,
- top: props.location === 'top' ? 0 : undefined,
- height: props.active ? convertToUnit(height.value) : 0,
- '--v-progress-linear-height': convertToUnit(height.value),
- ...locationStyles.value
- }, props.style],
- "role": "progressbar",
- "aria-hidden": props.active ? 'false' : 'true',
- "aria-valuemin": "0",
- "aria-valuemax": props.max,
- "aria-valuenow": props.indeterminate ? undefined : normalizedValue.value,
- "onClick": props.clickable && handleClick
- }, {
- default: () => [props.stream && vue.createVNode("div", {
- "key": "stream",
- "class": ['v-progress-linear__stream', textColorClasses.value],
- "style": {
- ...textColorStyles.value,
- [isReversed.value ? 'left' : 'right']: convertToUnit(-height.value),
- borderTop: `${convertToUnit(height.value / 2)} dotted`,
- opacity: opacity.value,
- top: `calc(50% - ${convertToUnit(height.value / 4)})`,
- width: convertToUnit(100 - normalizedBuffer.value, '%'),
- '--v-progress-linear-stream-to': convertToUnit(height.value * (isReversed.value ? 1 : -1))
- }
- }, null), vue.createVNode("div", {
- "class": ['v-progress-linear__background', backgroundColorClasses.value],
- "style": [backgroundColorStyles.value, {
- opacity: opacity.value,
- width: convertToUnit(!props.stream ? 100 : normalizedBuffer.value, '%')
- }]
- }, null), vue.createVNode(vue.Transition, {
- "name": transition.value
- }, {
- default: () => [!props.indeterminate ? vue.createVNode("div", {
- "class": ['v-progress-linear__determinate', barColorClasses.value],
- "style": [barColorStyles.value, {
- width: convertToUnit(normalizedValue.value, '%')
- }]
- }, null) : vue.createVNode("div", {
- "class": "v-progress-linear__indeterminate"
- }, [['long', 'short'].map(bar => vue.createVNode("div", {
- "key": bar,
- "class": ['v-progress-linear__indeterminate', bar, barColorClasses.value],
- "style": barColorStyles.value
- }, null))])]
- }), slots.default && vue.createVNode("div", {
- "class": "v-progress-linear__content"
- }, [slots.default({
- value: normalizedValue.value,
- buffer: normalizedBuffer.value
- })])]
- }));
- return {};
- }
- });
- // Types
- // Composables
- const makeLoaderProps = propsFactory({
- loading: [Boolean, String]
- }, 'loader');
- function useLoader(props) {
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- const loaderClasses = vue.computed(() => ({
- [`${name}--loading`]: props.loading
- }));
- return {
- loaderClasses
- };
- }
- function LoaderSlot(props, _ref) {
- let {
- slots
- } = _ref;
- return vue.createVNode("div", {
- "class": `${props.name}__loader`
- }, [slots.default?.({
- color: props.color,
- isActive: props.active
- }) || vue.createVNode(VProgressLinear, {
- "active": props.active,
- "color": props.color,
- "height": "2",
- "indeterminate": true
- }, null)]);
- }
- // Utilities
- // Types
- const positionValues = ['static', 'relative', 'fixed', 'absolute', 'sticky'];
- // Composables
- const makePositionProps = propsFactory({
- position: {
- type: String,
- validator: /* istanbul ignore next */v => positionValues.includes(v)
- }
- }, 'position');
- function usePosition(props) {
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- const positionClasses = vue.computed(() => {
- return props.position ? `${name}--${props.position}` : undefined;
- });
- return {
- positionClasses
- };
- }
- // Utilities
- function useRouter() {
- return getCurrentInstance('useRouter')?.proxy?.$router;
- }
- function useLink(props, attrs) {
- const RouterLink = vue.resolveDynamicComponent('RouterLink');
- const isLink = vue.computed(() => !!(props.href || props.to));
- const isClickable = vue.computed(() => {
- return isLink?.value || hasEvent(attrs, 'click') || hasEvent(props, 'click');
- });
- if (typeof RouterLink === 'string') {
- return {
- isLink,
- isClickable,
- href: vue.toRef(props, 'href')
- };
- }
- const link = props.to ? RouterLink.useLink(props) : undefined;
- return {
- isLink,
- isClickable,
- route: link?.route,
- navigate: link?.navigate,
- isActive: link && vue.computed(() => props.exact ? link.isExactActive?.value : link.isActive?.value),
- href: vue.computed(() => props.to ? link?.route.value.href : props.href)
- };
- }
- const makeRouterProps = propsFactory({
- href: String,
- replace: Boolean,
- to: [String, Object],
- exact: Boolean
- }, 'router');
- let inTransition = false;
- function useBackButton(router, cb) {
- let popped = false;
- let removeBefore;
- let removeAfter;
- if (IN_BROWSER) {
- vue.nextTick(() => {
- window.addEventListener('popstate', onPopstate);
- removeBefore = router?.beforeEach((to, from, next) => {
- if (!inTransition) {
- setTimeout(() => popped ? cb(next) : next());
- } else {
- popped ? cb(next) : next();
- }
- inTransition = true;
- });
- removeAfter = router?.afterEach(() => {
- inTransition = false;
- });
- });
- vue.onScopeDispose(() => {
- window.removeEventListener('popstate', onPopstate);
- removeBefore?.();
- removeAfter?.();
- });
- }
- function onPopstate(e) {
- if (e.state?.replaced) return;
- popped = true;
- setTimeout(() => popped = false);
- }
- }
- // Utilities
- // Types
- function useSelectLink(link, select) {
- vue.watch(() => link.isActive?.value, isActive => {
- if (link.isLink.value && isActive && select) {
- vue.nextTick(() => {
- select(true);
- });
- }
- }, {
- immediate: true
- });
- }
- // Styles
- // Types
- const stopSymbol = Symbol('rippleStop');
- const DELAY_RIPPLE = 80;
- function transform(el, value) {
- el.style.transform = value;
- el.style.webkitTransform = value;
- }
- function isTouchEvent(e) {
- return e.constructor.name === 'TouchEvent';
- }
- function isKeyboardEvent(e) {
- return e.constructor.name === 'KeyboardEvent';
- }
- const calculate = function (e, el) {
- let value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
- let localX = 0;
- let localY = 0;
- if (!isKeyboardEvent(e)) {
- const offset = el.getBoundingClientRect();
- const target = isTouchEvent(e) ? e.touches[e.touches.length - 1] : e;
- localX = target.clientX - offset.left;
- localY = target.clientY - offset.top;
- }
- let radius = 0;
- let scale = 0.3;
- if (el._ripple?.circle) {
- scale = 0.15;
- radius = el.clientWidth / 2;
- radius = value.center ? radius : radius + Math.sqrt((localX - radius) ** 2 + (localY - radius) ** 2) / 4;
- } else {
- radius = Math.sqrt(el.clientWidth ** 2 + el.clientHeight ** 2) / 2;
- }
- const centerX = `${(el.clientWidth - radius * 2) / 2}px`;
- const centerY = `${(el.clientHeight - radius * 2) / 2}px`;
- const x = value.center ? centerX : `${localX - radius}px`;
- const y = value.center ? centerY : `${localY - radius}px`;
- return {
- radius,
- scale,
- x,
- y,
- centerX,
- centerY
- };
- };
- const ripples = {
- /* eslint-disable max-statements */
- show(e, el) {
- let value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
- if (!el?._ripple?.enabled) {
- return;
- }
- const container = document.createElement('span');
- const animation = document.createElement('span');
- container.appendChild(animation);
- container.className = 'v-ripple__container';
- if (value.class) {
- container.className += ` ${value.class}`;
- }
- const {
- radius,
- scale,
- x,
- y,
- centerX,
- centerY
- } = calculate(e, el, value);
- const size = `${radius * 2}px`;
- animation.className = 'v-ripple__animation';
- animation.style.width = size;
- animation.style.height = size;
- el.appendChild(container);
- const computed = window.getComputedStyle(el);
- if (computed && computed.position === 'static') {
- el.style.position = 'relative';
- el.dataset.previousPosition = 'static';
- }
- animation.classList.add('v-ripple__animation--enter');
- animation.classList.add('v-ripple__animation--visible');
- transform(animation, `translate(${x}, ${y}) scale3d(${scale},${scale},${scale})`);
- animation.dataset.activated = String(performance.now());
- setTimeout(() => {
- animation.classList.remove('v-ripple__animation--enter');
- animation.classList.add('v-ripple__animation--in');
- transform(animation, `translate(${centerX}, ${centerY}) scale3d(1,1,1)`);
- }, 0);
- },
- hide(el) {
- if (!el?._ripple?.enabled) return;
- const ripples = el.getElementsByClassName('v-ripple__animation');
- if (ripples.length === 0) return;
- const animation = ripples[ripples.length - 1];
- if (animation.dataset.isHiding) return;else animation.dataset.isHiding = 'true';
- const diff = performance.now() - Number(animation.dataset.activated);
- const delay = Math.max(250 - diff, 0);
- setTimeout(() => {
- animation.classList.remove('v-ripple__animation--in');
- animation.classList.add('v-ripple__animation--out');
- setTimeout(() => {
- const ripples = el.getElementsByClassName('v-ripple__animation');
- if (ripples.length === 1 && el.dataset.previousPosition) {
- el.style.position = el.dataset.previousPosition;
- delete el.dataset.previousPosition;
- }
- if (animation.parentNode?.parentNode === el) el.removeChild(animation.parentNode);
- }, 300);
- }, delay);
- }
- };
- function isRippleEnabled(value) {
- return typeof value === 'undefined' || !!value;
- }
- function rippleShow(e) {
- const value = {};
- const element = e.currentTarget;
- if (!element?._ripple || element._ripple.touched || e[stopSymbol]) return;
- // Don't allow the event to trigger ripples on any other elements
- e[stopSymbol] = true;
- if (isTouchEvent(e)) {
- element._ripple.touched = true;
- element._ripple.isTouch = true;
- } else {
- // It's possible for touch events to fire
- // as mouse events on Android/iOS, this
- // will skip the event call if it has
- // already been registered as touch
- if (element._ripple.isTouch) return;
- }
- value.center = element._ripple.centered || isKeyboardEvent(e);
- if (element._ripple.class) {
- value.class = element._ripple.class;
- }
- if (isTouchEvent(e)) {
- // already queued that shows or hides the ripple
- if (element._ripple.showTimerCommit) return;
- element._ripple.showTimerCommit = () => {
- ripples.show(e, element, value);
- };
- element._ripple.showTimer = window.setTimeout(() => {
- if (element?._ripple?.showTimerCommit) {
- element._ripple.showTimerCommit();
- element._ripple.showTimerCommit = null;
- }
- }, DELAY_RIPPLE);
- } else {
- ripples.show(e, element, value);
- }
- }
- function rippleStop(e) {
- e[stopSymbol] = true;
- }
- function rippleHide(e) {
- const element = e.currentTarget;
- if (!element?._ripple) return;
- window.clearTimeout(element._ripple.showTimer);
- // The touch interaction occurs before the show timer is triggered.
- // We still want to show ripple effect.
- if (e.type === 'touchend' && element._ripple.showTimerCommit) {
- element._ripple.showTimerCommit();
- element._ripple.showTimerCommit = null;
- // re-queue ripple hiding
- element._ripple.showTimer = window.setTimeout(() => {
- rippleHide(e);
- });
- return;
- }
- window.setTimeout(() => {
- if (element._ripple) {
- element._ripple.touched = false;
- }
- });
- ripples.hide(element);
- }
- function rippleCancelShow(e) {
- const element = e.currentTarget;
- if (!element?._ripple) return;
- if (element._ripple.showTimerCommit) {
- element._ripple.showTimerCommit = null;
- }
- window.clearTimeout(element._ripple.showTimer);
- }
- let keyboardRipple = false;
- function keyboardRippleShow(e) {
- if (!keyboardRipple && (e.keyCode === keyCodes.enter || e.keyCode === keyCodes.space)) {
- keyboardRipple = true;
- rippleShow(e);
- }
- }
- function keyboardRippleHide(e) {
- keyboardRipple = false;
- rippleHide(e);
- }
- function focusRippleHide(e) {
- if (keyboardRipple) {
- keyboardRipple = false;
- rippleHide(e);
- }
- }
- function updateRipple(el, binding, wasEnabled) {
- const {
- value,
- modifiers
- } = binding;
- const enabled = isRippleEnabled(value);
- if (!enabled) {
- ripples.hide(el);
- }
- el._ripple = el._ripple ?? {};
- el._ripple.enabled = enabled;
- el._ripple.centered = modifiers.center;
- el._ripple.circle = modifiers.circle;
- if (isObject(value) && value.class) {
- el._ripple.class = value.class;
- }
- if (enabled && !wasEnabled) {
- if (modifiers.stop) {
- el.addEventListener('touchstart', rippleStop, {
- passive: true
- });
- el.addEventListener('mousedown', rippleStop);
- return;
- }
- el.addEventListener('touchstart', rippleShow, {
- passive: true
- });
- el.addEventListener('touchend', rippleHide, {
- passive: true
- });
- el.addEventListener('touchmove', rippleCancelShow, {
- passive: true
- });
- el.addEventListener('touchcancel', rippleHide);
- el.addEventListener('mousedown', rippleShow);
- el.addEventListener('mouseup', rippleHide);
- el.addEventListener('mouseleave', rippleHide);
- el.addEventListener('keydown', keyboardRippleShow);
- el.addEventListener('keyup', keyboardRippleHide);
- el.addEventListener('blur', focusRippleHide);
- // Anchor tags can be dragged, causes other hides to fail - #1537
- el.addEventListener('dragstart', rippleHide, {
- passive: true
- });
- } else if (!enabled && wasEnabled) {
- removeListeners(el);
- }
- }
- function removeListeners(el) {
- el.removeEventListener('mousedown', rippleShow);
- el.removeEventListener('touchstart', rippleShow);
- el.removeEventListener('touchend', rippleHide);
- el.removeEventListener('touchmove', rippleCancelShow);
- el.removeEventListener('touchcancel', rippleHide);
- el.removeEventListener('mouseup', rippleHide);
- el.removeEventListener('mouseleave', rippleHide);
- el.removeEventListener('keydown', keyboardRippleShow);
- el.removeEventListener('keyup', keyboardRippleHide);
- el.removeEventListener('dragstart', rippleHide);
- el.removeEventListener('blur', focusRippleHide);
- }
- function mounted$4(el, binding) {
- updateRipple(el, binding, false);
- }
- function unmounted$4(el) {
- delete el._ripple;
- removeListeners(el);
- }
- function updated$1(el, binding) {
- if (binding.value === binding.oldValue) {
- return;
- }
- const wasEnabled = isRippleEnabled(binding.oldValue);
- updateRipple(el, binding, wasEnabled);
- }
- const Ripple = {
- mounted: mounted$4,
- unmounted: unmounted$4,
- updated: updated$1
- };
- // Types
- const makeVBtnProps = propsFactory({
- active: {
- type: Boolean,
- default: undefined
- },
- symbol: {
- type: null,
- default: VBtnToggleSymbol
- },
- flat: Boolean,
- icon: [Boolean, String, Function, Object],
- prependIcon: IconValue,
- appendIcon: IconValue,
- block: Boolean,
- stacked: Boolean,
- ripple: {
- type: [Boolean, Object],
- default: true
- },
- text: String,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeDimensionProps(),
- ...makeElevationProps(),
- ...makeGroupItemProps(),
- ...makeLoaderProps(),
- ...makeLocationProps(),
- ...makePositionProps(),
- ...makeRoundedProps(),
- ...makeRouterProps(),
- ...makeSizeProps(),
- ...makeTagProps({
- tag: 'button'
- }),
- ...makeThemeProps(),
- ...makeVariantProps({
- variant: 'elevated'
- })
- }, 'VBtn');
- const VBtn = genericComponent()({
- name: 'VBtn',
- directives: {
- Ripple
- },
- props: makeVBtnProps(),
- emits: {
- 'group:selected': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- borderClasses
- } = useBorder(props);
- const {
- colorClasses,
- colorStyles,
- variantClasses
- } = useVariant(props);
- const {
- densityClasses
- } = useDensity(props);
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- loaderClasses
- } = useLoader(props);
- const {
- locationStyles
- } = useLocation(props);
- const {
- positionClasses
- } = usePosition(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- sizeClasses,
- sizeStyles
- } = useSize(props);
- const group = useGroupItem(props, props.symbol, false);
- const link = useLink(props, attrs);
- const isActive = vue.computed(() => {
- if (props.active !== undefined) {
- return props.active;
- }
- if (link.isLink.value) {
- return link.isActive?.value;
- }
- return group?.isSelected.value;
- });
- const isDisabled = vue.computed(() => group?.disabled.value || props.disabled);
- const isElevated = vue.computed(() => {
- return props.variant === 'elevated' && !(props.disabled || props.flat || props.border);
- });
- const valueAttr = vue.computed(() => {
- if (props.value === undefined) return undefined;
- return Object(props.value) === props.value ? JSON.stringify(props.value, null, 0) : props.value;
- });
- function onClick(e) {
- if (isDisabled.value || link.isLink.value && (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0 || attrs.target === '_blank')) return;
- link.navigate?.(e);
- group?.toggle();
- }
- useSelectLink(link, group?.select);
- useRender(() => {
- const Tag = link.isLink.value ? 'a' : props.tag;
- const hasPrepend = !!(props.prependIcon || slots.prepend);
- const hasAppend = !!(props.appendIcon || slots.append);
- const hasIcon = !!(props.icon && props.icon !== true);
- const hasColor = group?.isSelected.value && (!link.isLink.value || link.isActive?.value) || !group || link.isActive?.value;
- return vue.withDirectives(vue.createVNode(Tag, {
- "type": Tag === 'a' ? undefined : 'button',
- "class": ['v-btn', group?.selectedClass.value, {
- 'v-btn--active': isActive.value,
- 'v-btn--block': props.block,
- 'v-btn--disabled': isDisabled.value,
- 'v-btn--elevated': isElevated.value,
- 'v-btn--flat': props.flat,
- 'v-btn--icon': !!props.icon,
- 'v-btn--loading': props.loading,
- 'v-btn--stacked': props.stacked
- }, themeClasses.value, borderClasses.value, hasColor ? colorClasses.value : undefined, densityClasses.value, elevationClasses.value, loaderClasses.value, positionClasses.value, roundedClasses.value, sizeClasses.value, variantClasses.value, props.class],
- "style": [hasColor ? colorStyles.value : undefined, dimensionStyles.value, locationStyles.value, sizeStyles.value, props.style],
- "disabled": isDisabled.value || undefined,
- "href": link.href.value,
- "onClick": onClick,
- "value": valueAttr.value
- }, {
- default: () => [genOverlays(true, 'v-btn'), !props.icon && hasPrepend && vue.createVNode("span", {
- "key": "prepend",
- "class": "v-btn__prepend"
- }, [!slots.prepend ? vue.createVNode(VIcon, {
- "key": "prepend-icon",
- "icon": props.prependIcon
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "prepend-defaults",
- "disabled": !props.prependIcon,
- "defaults": {
- VIcon: {
- icon: props.prependIcon
- }
- }
- }, slots.prepend)]), vue.createVNode("span", {
- "class": "v-btn__content",
- "data-no-activator": ""
- }, [!slots.default && hasIcon ? vue.createVNode(VIcon, {
- "key": "content-icon",
- "icon": props.icon
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "content-defaults",
- "disabled": !hasIcon,
- "defaults": {
- VIcon: {
- icon: props.icon
- }
- }
- }, {
- default: () => [slots.default?.() ?? props.text]
- })]), !props.icon && hasAppend && vue.createVNode("span", {
- "key": "append",
- "class": "v-btn__append"
- }, [!slots.append ? vue.createVNode(VIcon, {
- "key": "append-icon",
- "icon": props.appendIcon
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "append-defaults",
- "disabled": !props.appendIcon,
- "defaults": {
- VIcon: {
- icon: props.appendIcon
- }
- }
- }, slots.append)]), !!props.loading && vue.createVNode("span", {
- "key": "loader",
- "class": "v-btn__loader"
- }, [slots.loader?.() ?? vue.createVNode(VProgressCircular, {
- "color": typeof props.loading === 'boolean' ? undefined : props.loading,
- "indeterminate": true,
- "size": "23",
- "width": "2"
- }, null)])]
- }), [[vue.resolveDirective("ripple"), !isDisabled.value && props.ripple, null]]);
- });
- return {};
- }
- });
- // Types
- const makeVAppBarNavIconProps = propsFactory({
- ...makeVBtnProps({
- icon: '$menu',
- variant: 'text'
- })
- }, 'VAppBarNavIcon');
- const VAppBarNavIcon = genericComponent()({
- name: 'VAppBarNavIcon',
- props: makeVAppBarNavIconProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode(VBtn, vue.mergeProps(props, {
- "class": ['v-app-bar-nav-icon']
- }), slots));
- return {};
- }
- });
- // Types
- const VAppBarTitle = genericComponent()({
- name: 'VAppBarTitle',
- props: makeVToolbarTitleProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode(VToolbarTitle, vue.mergeProps(props, {
- "class": "v-app-bar-title"
- }), slots));
- return {};
- }
- });
- // Utilities
- const VAlertTitle = createSimpleFunctional('v-alert-title');
- // Types
- const allowedTypes = ['success', 'info', 'warning', 'error'];
- const makeVAlertProps = propsFactory({
- border: {
- type: [Boolean, String],
- validator: val => {
- return typeof val === 'boolean' || ['top', 'end', 'bottom', 'start'].includes(val);
- }
- },
- borderColor: String,
- closable: Boolean,
- closeIcon: {
- type: IconValue,
- default: '$close'
- },
- closeLabel: {
- type: String,
- default: '$vuetify.close'
- },
- icon: {
- type: [Boolean, String, Function, Object],
- default: null
- },
- modelValue: {
- type: Boolean,
- default: true
- },
- prominent: Boolean,
- title: String,
- text: String,
- type: {
- type: String,
- validator: val => allowedTypes.includes(val)
- },
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeDimensionProps(),
- ...makeElevationProps(),
- ...makeLocationProps(),
- ...makePositionProps(),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeThemeProps(),
- ...makeVariantProps({
- variant: 'flat'
- })
- }, 'VAlert');
- const VAlert = genericComponent()({
- name: 'VAlert',
- props: makeVAlertProps(),
- emits: {
- 'click:close': e => true,
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const isActive = useProxiedModel(props, 'modelValue');
- const icon = vue.computed(() => {
- if (props.icon === false) return undefined;
- if (!props.type) return props.icon;
- return props.icon ?? `$${props.type}`;
- });
- const variantProps = vue.computed(() => ({
- color: props.color ?? props.type,
- variant: props.variant
- }));
- const {
- themeClasses
- } = provideTheme(props);
- const {
- colorClasses,
- colorStyles,
- variantClasses
- } = useVariant(variantProps);
- const {
- densityClasses
- } = useDensity(props);
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- locationStyles
- } = useLocation(props);
- const {
- positionClasses
- } = usePosition(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.toRef(props, 'borderColor'));
- const {
- t
- } = useLocale();
- const closeProps = vue.computed(() => ({
- 'aria-label': t(props.closeLabel),
- onClick(e) {
- isActive.value = false;
- emit('click:close', e);
- }
- }));
- return () => {
- const hasPrepend = !!(slots.prepend || icon.value);
- const hasTitle = !!(slots.title || props.title);
- const hasClose = !!(slots.close || props.closable);
- return isActive.value && vue.createVNode(props.tag, {
- "class": ['v-alert', props.border && {
- 'v-alert--border': !!props.border,
- [`v-alert--border-${props.border === true ? 'start' : props.border}`]: true
- }, {
- 'v-alert--prominent': props.prominent
- }, themeClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, positionClasses.value, roundedClasses.value, variantClasses.value, props.class],
- "style": [colorStyles.value, dimensionStyles.value, locationStyles.value, props.style],
- "role": "alert"
- }, {
- default: () => [genOverlays(false, 'v-alert'), props.border && vue.createVNode("div", {
- "key": "border",
- "class": ['v-alert__border', textColorClasses.value],
- "style": textColorStyles.value
- }, null), hasPrepend && vue.createVNode("div", {
- "key": "prepend",
- "class": "v-alert__prepend"
- }, [!slots.prepend ? vue.createVNode(VIcon, {
- "key": "prepend-icon",
- "density": props.density,
- "icon": icon.value,
- "size": props.prominent ? 44 : 28
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "prepend-defaults",
- "disabled": !icon.value,
- "defaults": {
- VIcon: {
- density: props.density,
- icon: icon.value,
- size: props.prominent ? 44 : 28
- }
- }
- }, slots.prepend)]), vue.createVNode("div", {
- "class": "v-alert__content"
- }, [hasTitle && vue.createVNode(VAlertTitle, {
- "key": "title"
- }, {
- default: () => [slots.title?.() ?? props.title]
- }), slots.text?.() ?? props.text, slots.default?.()]), slots.append && vue.createVNode("div", {
- "key": "append",
- "class": "v-alert__append"
- }, [slots.append()]), hasClose && vue.createVNode("div", {
- "key": "close",
- "class": "v-alert__close"
- }, [!slots.close ? vue.createVNode(VBtn, vue.mergeProps({
- "key": "close-btn",
- "icon": props.closeIcon,
- "size": "x-small",
- "variant": "text"
- }, closeProps.value), null) : vue.createVNode(VDefaultsProvider, {
- "key": "close-defaults",
- "defaults": {
- VBtn: {
- icon: props.closeIcon,
- size: 'x-small',
- variant: 'text'
- }
- }
- }, {
- default: () => [slots.close?.({
- props: closeProps.value
- })]
- })])]
- });
- };
- }
- });
- const makeVLabelProps = propsFactory({
- text: String,
- clickable: Boolean,
- ...makeComponentProps(),
- ...makeThemeProps()
- }, 'VLabel');
- const VLabel = genericComponent()({
- name: 'VLabel',
- props: makeVLabelProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode("label", {
- "class": ['v-label', {
- 'v-label--clickable': props.clickable
- }, props.class],
- "style": props.style
- }, [props.text, slots.default?.()]));
- return {};
- }
- });
- // Types
- const VSelectionControlGroupSymbol = Symbol.for('vuetify:selection-control-group');
- const makeSelectionControlGroupProps = propsFactory({
- color: String,
- disabled: {
- type: Boolean,
- default: null
- },
- defaultsTarget: String,
- error: Boolean,
- id: String,
- inline: Boolean,
- falseIcon: IconValue,
- trueIcon: IconValue,
- ripple: {
- type: Boolean,
- default: true
- },
- multiple: {
- type: Boolean,
- default: null
- },
- name: String,
- readonly: Boolean,
- modelValue: null,
- type: String,
- valueComparator: {
- type: Function,
- default: deepEqual
- },
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeThemeProps()
- }, 'SelectionControlGroup');
- const makeVSelectionControlGroupProps = propsFactory({
- ...makeSelectionControlGroupProps({
- defaultsTarget: 'VSelectionControl'
- })
- }, 'VSelectionControlGroup');
- const VSelectionControlGroup = genericComponent()({
- name: 'VSelectionControlGroup',
- props: makeVSelectionControlGroupProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const modelValue = useProxiedModel(props, 'modelValue');
- const uid = getUid();
- const id = vue.computed(() => props.id || `v-selection-control-group-${uid}`);
- const name = vue.computed(() => props.name || id.value);
- const updateHandlers = new Set();
- vue.provide(VSelectionControlGroupSymbol, {
- modelValue,
- forceUpdate: () => {
- updateHandlers.forEach(fn => fn());
- },
- onForceUpdate: cb => {
- updateHandlers.add(cb);
- vue.onScopeDispose(() => {
- updateHandlers.delete(cb);
- });
- }
- });
- provideDefaults({
- [props.defaultsTarget]: {
- color: vue.toRef(props, 'color'),
- disabled: vue.toRef(props, 'disabled'),
- density: vue.toRef(props, 'density'),
- error: vue.toRef(props, 'error'),
- inline: vue.toRef(props, 'inline'),
- modelValue,
- multiple: vue.computed(() => !!props.multiple || props.multiple == null && Array.isArray(modelValue.value)),
- name,
- falseIcon: vue.toRef(props, 'falseIcon'),
- trueIcon: vue.toRef(props, 'trueIcon'),
- readonly: vue.toRef(props, 'readonly'),
- ripple: vue.toRef(props, 'ripple'),
- type: vue.toRef(props, 'type'),
- valueComparator: vue.toRef(props, 'valueComparator')
- }
- });
- useRender(() => vue.createVNode("div", {
- "class": ['v-selection-control-group', {
- 'v-selection-control-group--inline': props.inline
- }, props.class],
- "style": props.style,
- "role": props.type === 'radio' ? 'radiogroup' : undefined
- }, [slots.default?.()]));
- return {};
- }
- });
- // Types
- const makeVSelectionControlProps = propsFactory({
- label: String,
- trueValue: null,
- falseValue: null,
- value: null,
- ...makeComponentProps(),
- ...makeSelectionControlGroupProps()
- }, 'VSelectionControl');
- function useSelectionControl(props) {
- const group = vue.inject(VSelectionControlGroupSymbol, undefined);
- const {
- densityClasses
- } = useDensity(props);
- const modelValue = useProxiedModel(props, 'modelValue');
- const trueValue = vue.computed(() => props.trueValue !== undefined ? props.trueValue : props.value !== undefined ? props.value : true);
- const falseValue = vue.computed(() => props.falseValue !== undefined ? props.falseValue : false);
- const isMultiple = vue.computed(() => !!props.multiple || props.multiple == null && Array.isArray(modelValue.value));
- const model = vue.computed({
- get() {
- const val = group ? group.modelValue.value : modelValue.value;
- return isMultiple.value ? val.some(v => props.valueComparator(v, trueValue.value)) : props.valueComparator(val, trueValue.value);
- },
- set(val) {
- if (props.readonly) return;
- const currentValue = val ? trueValue.value : falseValue.value;
- let newVal = currentValue;
- if (isMultiple.value) {
- newVal = val ? [...wrapInArray(modelValue.value), currentValue] : wrapInArray(modelValue.value).filter(item => !props.valueComparator(item, trueValue.value));
- }
- if (group) {
- group.modelValue.value = newVal;
- } else {
- modelValue.value = newVal;
- }
- }
- });
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.computed(() => {
- return model.value && !props.error && !props.disabled ? props.color : undefined;
- }));
- const icon = vue.computed(() => model.value ? props.trueIcon : props.falseIcon);
- return {
- group,
- densityClasses,
- trueValue,
- falseValue,
- model,
- textColorClasses,
- textColorStyles,
- icon
- };
- }
- const VSelectionControl = genericComponent()({
- name: 'VSelectionControl',
- directives: {
- Ripple
- },
- inheritAttrs: false,
- props: makeVSelectionControlProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- group,
- densityClasses,
- icon,
- model,
- textColorClasses,
- textColorStyles,
- trueValue
- } = useSelectionControl(props);
- const uid = getUid();
- const id = vue.computed(() => props.id || `input-${uid}`);
- const isFocused = vue.shallowRef(false);
- const isFocusVisible = vue.shallowRef(false);
- const input = vue.ref();
- group?.onForceUpdate(() => {
- if (input.value) {
- input.value.checked = model.value;
- }
- });
- function onFocus(e) {
- isFocused.value = true;
- if (matchesSelector(e.target, ':focus-visible') !== false) {
- isFocusVisible.value = true;
- }
- }
- function onBlur() {
- isFocused.value = false;
- isFocusVisible.value = false;
- }
- function onInput(e) {
- if (props.readonly && group) {
- vue.nextTick(() => group.forceUpdate());
- }
- model.value = e.target.checked;
- }
- useRender(() => {
- const label = slots.label ? slots.label({
- label: props.label,
- props: {
- for: id.value
- }
- }) : props.label;
- const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
- return vue.createVNode("div", vue.mergeProps({
- "class": ['v-selection-control', {
- 'v-selection-control--dirty': model.value,
- 'v-selection-control--disabled': props.disabled,
- 'v-selection-control--error': props.error,
- 'v-selection-control--focused': isFocused.value,
- 'v-selection-control--focus-visible': isFocusVisible.value,
- 'v-selection-control--inline': props.inline
- }, densityClasses.value, props.class]
- }, rootAttrs, {
- "style": props.style
- }), [vue.createVNode("div", {
- "class": ['v-selection-control__wrapper', textColorClasses.value],
- "style": textColorStyles.value
- }, [slots.default?.(), vue.withDirectives(vue.createVNode("div", {
- "class": ['v-selection-control__input']
- }, [icon.value && vue.createVNode(VIcon, {
- "key": "icon",
- "icon": icon.value
- }, null), vue.createVNode("input", vue.mergeProps({
- "ref": input,
- "checked": model.value,
- "disabled": !!(props.readonly || props.disabled),
- "id": id.value,
- "onBlur": onBlur,
- "onFocus": onFocus,
- "onInput": onInput,
- "aria-disabled": !!(props.readonly || props.disabled),
- "type": props.type,
- "value": trueValue.value,
- "name": props.name,
- "aria-checked": props.type === 'checkbox' ? model.value : undefined
- }, inputAttrs), null), slots.input?.({
- model,
- textColorClasses,
- textColorStyles,
- props: {
- onFocus,
- onBlur,
- id: id.value
- }
- })]), [[vue.resolveDirective("ripple"), props.ripple && [!props.disabled && !props.readonly, null, ['center', 'circle']]]])]), label && vue.createVNode(VLabel, {
- "for": id.value,
- "clickable": true
- }, {
- default: () => [label]
- })]);
- });
- return {
- isFocused,
- input
- };
- }
- });
- // Types
- const makeVCheckboxBtnProps = propsFactory({
- indeterminate: Boolean,
- indeterminateIcon: {
- type: IconValue,
- default: '$checkboxIndeterminate'
- },
- ...makeVSelectionControlProps({
- falseIcon: '$checkboxOff',
- trueIcon: '$checkboxOn'
- })
- }, 'VCheckboxBtn');
- const VCheckboxBtn = genericComponent()({
- name: 'VCheckboxBtn',
- props: makeVCheckboxBtnProps(),
- emits: {
- 'update:modelValue': value => true,
- 'update:indeterminate': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const indeterminate = useProxiedModel(props, 'indeterminate');
- const model = useProxiedModel(props, 'modelValue');
- function onChange(v) {
- if (indeterminate.value) {
- indeterminate.value = false;
- }
- }
- const falseIcon = vue.computed(() => {
- return indeterminate.value ? props.indeterminateIcon : props.falseIcon;
- });
- const trueIcon = vue.computed(() => {
- return indeterminate.value ? props.indeterminateIcon : props.trueIcon;
- });
- useRender(() => vue.createVNode(VSelectionControl, vue.mergeProps(props, {
- "modelValue": model.value,
- "onUpdate:modelValue": [$event => model.value = $event, onChange],
- "class": ['v-checkbox-btn', props.class],
- "style": props.style,
- "type": "checkbox",
- "falseIcon": falseIcon.value,
- "trueIcon": trueIcon.value,
- "aria-checked": indeterminate.value ? 'mixed' : undefined
- }), slots));
- return {};
- }
- });
- // Types
- function useInputIcon(props) {
- const {
- t
- } = useLocale();
- function InputIcon(_ref) {
- let {
- name
- } = _ref;
- const localeKey = {
- prepend: 'prependAction',
- prependInner: 'prependAction',
- append: 'appendAction',
- appendInner: 'appendAction',
- clear: 'clear'
- }[name];
- const listener = props[`onClick:${name}`];
- const label = listener && localeKey ? t(`$vuetify.input.${localeKey}`, props.label ?? '') : undefined;
- return vue.createVNode(VIcon, {
- "icon": props[`${name}Icon`],
- "aria-label": label,
- "onClick": listener
- }, null);
- }
- return {
- InputIcon
- };
- }
- // Types
- const makeVMessagesProps = propsFactory({
- active: Boolean,
- color: String,
- messages: {
- type: [Array, String],
- default: () => []
- },
- ...makeComponentProps(),
- ...makeTransitionProps({
- transition: {
- component: VSlideYTransition,
- leaveAbsolute: true,
- group: true
- }
- })
- }, 'VMessages');
- const VMessages = genericComponent()({
- name: 'VMessages',
- props: makeVMessagesProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const messages = vue.computed(() => wrapInArray(props.messages));
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.computed(() => props.color));
- useRender(() => vue.createVNode(MaybeTransition, {
- "transition": props.transition,
- "tag": "div",
- "class": ['v-messages', textColorClasses.value, props.class],
- "style": [textColorStyles.value, props.style],
- "role": "alert",
- "aria-live": "polite"
- }, {
- default: () => [props.active && messages.value.map((message, i) => vue.createVNode("div", {
- "class": "v-messages__message",
- "key": `${i}-${messages.value}`
- }, [slots.message ? slots.message({
- message
- }) : message]))]
- }));
- return {};
- }
- });
- // Composables
- // Types
- // Composables
- const makeFocusProps = propsFactory({
- focused: Boolean,
- 'onUpdate:focused': EventProp()
- }, 'focus');
- function useFocus(props) {
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- const isFocused = useProxiedModel(props, 'focused');
- const focusClasses = vue.computed(() => {
- return {
- [`${name}--focused`]: isFocused.value
- };
- });
- function focus() {
- isFocused.value = true;
- }
- function blur() {
- isFocused.value = false;
- }
- return {
- focusClasses,
- isFocused,
- focus,
- blur
- };
- }
- // Composables
- // Types
- const FormKey = Symbol.for('vuetify:form');
- const makeFormProps = propsFactory({
- disabled: Boolean,
- fastFail: Boolean,
- readonly: Boolean,
- modelValue: {
- type: Boolean,
- default: null
- },
- validateOn: {
- type: String,
- default: 'input'
- }
- }, 'form');
- function createForm(props) {
- const model = useProxiedModel(props, 'modelValue');
- const isDisabled = vue.computed(() => props.disabled);
- const isReadonly = vue.computed(() => props.readonly);
- const isValidating = vue.shallowRef(false);
- const items = vue.ref([]);
- const errors = vue.ref([]);
- async function validate() {
- const results = [];
- let valid = true;
- errors.value = [];
- isValidating.value = true;
- for (const item of items.value) {
- const itemErrorMessages = await item.validate();
- if (itemErrorMessages.length > 0) {
- valid = false;
- results.push({
- id: item.id,
- errorMessages: itemErrorMessages
- });
- }
- if (!valid && props.fastFail) break;
- }
- errors.value = results;
- isValidating.value = false;
- return {
- valid,
- errors: errors.value
- };
- }
- function reset() {
- items.value.forEach(item => item.reset());
- }
- function resetValidation() {
- items.value.forEach(item => item.resetValidation());
- }
- vue.watch(items, () => {
- let valid = 0;
- let invalid = 0;
- const results = [];
- for (const item of items.value) {
- if (item.isValid === false) {
- invalid++;
- results.push({
- id: item.id,
- errorMessages: item.errorMessages
- });
- } else if (item.isValid === true) valid++;
- }
- errors.value = results;
- model.value = invalid > 0 ? false : valid === items.value.length ? true : null;
- }, {
- deep: true
- });
- vue.provide(FormKey, {
- register: _ref => {
- let {
- id,
- validate,
- reset,
- resetValidation
- } = _ref;
- if (items.value.some(item => item.id === id)) {
- consoleWarn(`Duplicate input name "${id}"`);
- }
- items.value.push({
- id,
- validate,
- reset,
- resetValidation,
- isValid: null,
- errorMessages: []
- });
- },
- unregister: id => {
- items.value = items.value.filter(item => {
- return item.id !== id;
- });
- },
- update: (id, isValid, errorMessages) => {
- const found = items.value.find(item => item.id === id);
- if (!found) return;
- found.isValid = isValid;
- found.errorMessages = errorMessages;
- },
- isDisabled,
- isReadonly,
- isValidating,
- isValid: model,
- items,
- validateOn: vue.toRef(props, 'validateOn')
- });
- return {
- errors,
- isDisabled,
- isReadonly,
- isValidating,
- isValid: model,
- items,
- validate,
- reset,
- resetValidation
- };
- }
- function useForm() {
- return vue.inject(FormKey, null);
- }
- // Composables
- // Types
- const makeValidationProps = propsFactory({
- disabled: {
- type: Boolean,
- default: null
- },
- error: Boolean,
- errorMessages: {
- type: [Array, String],
- default: () => []
- },
- maxErrors: {
- type: [Number, String],
- default: 1
- },
- name: String,
- label: String,
- readonly: {
- type: Boolean,
- default: null
- },
- rules: {
- type: Array,
- default: () => []
- },
- modelValue: null,
- validateOn: String,
- validationValue: null,
- ...makeFocusProps()
- }, 'validation');
- function useValidation(props) {
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- let id = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : getUid();
- const model = useProxiedModel(props, 'modelValue');
- const validationModel = vue.computed(() => props.validationValue === undefined ? model.value : props.validationValue);
- const form = useForm();
- const internalErrorMessages = vue.ref([]);
- const isPristine = vue.shallowRef(true);
- const isDirty = vue.computed(() => !!(wrapInArray(model.value === '' ? null : model.value).length || wrapInArray(validationModel.value === '' ? null : validationModel.value).length));
- const isDisabled = vue.computed(() => !!(props.disabled ?? form?.isDisabled.value));
- const isReadonly = vue.computed(() => !!(props.readonly ?? form?.isReadonly.value));
- const errorMessages = vue.computed(() => {
- return props.errorMessages.length ? wrapInArray(props.errorMessages).slice(0, Math.max(0, +props.maxErrors)) : internalErrorMessages.value;
- });
- const validateOn = vue.computed(() => {
- let value = (props.validateOn ?? form?.validateOn.value) || 'input';
- if (value === 'lazy') value = 'input lazy';
- const set = new Set(value?.split(' ') ?? []);
- return {
- blur: set.has('blur') || set.has('input'),
- input: set.has('input'),
- submit: set.has('submit'),
- lazy: set.has('lazy')
- };
- });
- const isValid = vue.computed(() => {
- if (props.error || props.errorMessages.length) return false;
- if (!props.rules.length) return true;
- if (isPristine.value) {
- return internalErrorMessages.value.length || validateOn.value.lazy ? null : true;
- } else {
- return !internalErrorMessages.value.length;
- }
- });
- const isValidating = vue.shallowRef(false);
- const validationClasses = vue.computed(() => {
- return {
- [`${name}--error`]: isValid.value === false,
- [`${name}--dirty`]: isDirty.value,
- [`${name}--disabled`]: isDisabled.value,
- [`${name}--readonly`]: isReadonly.value
- };
- });
- const uid = vue.computed(() => props.name ?? vue.unref(id));
- vue.onBeforeMount(() => {
- form?.register({
- id: uid.value,
- validate,
- reset,
- resetValidation
- });
- });
- vue.onBeforeUnmount(() => {
- form?.unregister(uid.value);
- });
- vue.onMounted(async () => {
- if (!validateOn.value.lazy) {
- await validate(true);
- }
- form?.update(uid.value, isValid.value, errorMessages.value);
- });
- useToggleScope(() => validateOn.value.input, () => {
- vue.watch(validationModel, () => {
- if (validationModel.value != null) {
- validate();
- } else if (props.focused) {
- const unwatch = vue.watch(() => props.focused, val => {
- if (!val) validate();
- unwatch();
- });
- }
- });
- });
- useToggleScope(() => validateOn.value.blur, () => {
- vue.watch(() => props.focused, val => {
- if (!val) validate();
- });
- });
- vue.watch(isValid, () => {
- form?.update(uid.value, isValid.value, errorMessages.value);
- });
- function reset() {
- model.value = null;
- vue.nextTick(resetValidation);
- }
- function resetValidation() {
- isPristine.value = true;
- if (!validateOn.value.lazy) {
- validate(true);
- } else {
- internalErrorMessages.value = [];
- }
- }
- async function validate() {
- let silent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
- const results = [];
- isValidating.value = true;
- for (const rule of props.rules) {
- if (results.length >= +(props.maxErrors ?? 1)) {
- break;
- }
- const handler = typeof rule === 'function' ? rule : () => rule;
- const result = await handler(validationModel.value);
- if (result === true) continue;
- if (result !== false && typeof result !== 'string') {
- // eslint-disable-next-line no-console
- console.warn(`${result} is not a valid value. Rule functions must return boolean true or a string.`);
- continue;
- }
- results.push(result || '');
- }
- internalErrorMessages.value = results;
- isValidating.value = false;
- isPristine.value = silent;
- return internalErrorMessages.value;
- }
- return {
- errorMessages,
- isDirty,
- isDisabled,
- isReadonly,
- isPristine,
- isValid,
- isValidating,
- reset,
- resetValidation,
- validate,
- validationClasses
- };
- }
- // Types
- const makeVInputProps = propsFactory({
- id: String,
- appendIcon: IconValue,
- centerAffix: {
- type: Boolean,
- default: true
- },
- prependIcon: IconValue,
- hideDetails: [Boolean, String],
- hint: String,
- persistentHint: Boolean,
- messages: {
- type: [Array, String],
- default: () => []
- },
- direction: {
- type: String,
- default: 'horizontal',
- validator: v => ['horizontal', 'vertical'].includes(v)
- },
- 'onClick:prepend': EventProp(),
- 'onClick:append': EventProp(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeValidationProps()
- }, 'VInput');
- const VInput = genericComponent()({
- name: 'VInput',
- props: {
- ...makeVInputProps()
- },
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots,
- emit
- } = _ref;
- const {
- densityClasses
- } = useDensity(props);
- const {
- rtlClasses
- } = useRtl();
- const {
- InputIcon
- } = useInputIcon(props);
- const uid = getUid();
- const id = vue.computed(() => props.id || `input-${uid}`);
- const messagesId = vue.computed(() => `${id.value}-messages`);
- const {
- errorMessages,
- isDirty,
- isDisabled,
- isReadonly,
- isPristine,
- isValid,
- isValidating,
- reset,
- resetValidation,
- validate,
- validationClasses
- } = useValidation(props, 'v-input', id);
- const slotProps = vue.computed(() => ({
- id,
- messagesId,
- isDirty,
- isDisabled,
- isReadonly,
- isPristine,
- isValid,
- isValidating,
- reset,
- resetValidation,
- validate
- }));
- const messages = vue.computed(() => {
- if (props.errorMessages?.length || !isPristine.value && errorMessages.value.length) {
- return errorMessages.value;
- } else if (props.hint && (props.persistentHint || props.focused)) {
- return props.hint;
- } else {
- return props.messages;
- }
- });
- useRender(() => {
- const hasPrepend = !!(slots.prepend || props.prependIcon);
- const hasAppend = !!(slots.append || props.appendIcon);
- const hasMessages = messages.value.length > 0;
- const hasDetails = !props.hideDetails || props.hideDetails === 'auto' && (hasMessages || !!slots.details);
- return vue.createVNode("div", {
- "class": ['v-input', `v-input--${props.direction}`, {
- 'v-input--center-affix': props.centerAffix
- }, densityClasses.value, rtlClasses.value, validationClasses.value, props.class],
- "style": props.style
- }, [hasPrepend && vue.createVNode("div", {
- "key": "prepend",
- "class": "v-input__prepend"
- }, [slots.prepend?.(slotProps.value), props.prependIcon && vue.createVNode(InputIcon, {
- "key": "prepend-icon",
- "name": "prepend"
- }, null)]), slots.default && vue.createVNode("div", {
- "class": "v-input__control"
- }, [slots.default?.(slotProps.value)]), hasAppend && vue.createVNode("div", {
- "key": "append",
- "class": "v-input__append"
- }, [props.appendIcon && vue.createVNode(InputIcon, {
- "key": "append-icon",
- "name": "append"
- }, null), slots.append?.(slotProps.value)]), hasDetails && vue.createVNode("div", {
- "class": "v-input__details"
- }, [vue.createVNode(VMessages, {
- "id": messagesId.value,
- "active": hasMessages,
- "messages": messages.value
- }, {
- message: slots.message
- }), slots.details?.(slotProps.value)])]);
- });
- return {
- reset,
- resetValidation,
- validate
- };
- }
- });
- // Types
- const makeVCheckboxProps = propsFactory({
- ...makeVInputProps(),
- ...omit(makeVCheckboxBtnProps(), ['inline'])
- }, 'VCheckbox');
- const VCheckbox = genericComponent()({
- name: 'VCheckbox',
- inheritAttrs: false,
- props: makeVCheckboxProps(),
- emits: {
- 'update:modelValue': value => true,
- 'update:focused': focused => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const {
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const uid = getUid();
- const id = vue.computed(() => props.id || `checkbox-${uid}`);
- useRender(() => {
- const [inputAttrs, controlAttrs] = filterInputAttrs(attrs);
- const [inputProps, _1] = VInput.filterProps(props);
- const [checkboxProps, _2] = VCheckboxBtn.filterProps(props);
- return vue.createVNode(VInput, vue.mergeProps({
- "class": ['v-checkbox', props.class]
- }, inputAttrs, inputProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "id": id.value,
- "focused": isFocused.value,
- "style": props.style
- }), {
- ...slots,
- default: _ref2 => {
- let {
- id,
- messagesId,
- isDisabled,
- isReadonly
- } = _ref2;
- return vue.createVNode(VCheckboxBtn, vue.mergeProps(checkboxProps, {
- "id": id.value,
- "aria-describedby": messagesId.value,
- "disabled": isDisabled.value,
- "readonly": isReadonly.value
- }, controlAttrs, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "onFocus": focus,
- "onBlur": blur
- }), slots);
- }
- });
- });
- return {};
- }
- });
- const makeVAvatarProps = propsFactory({
- start: Boolean,
- end: Boolean,
- icon: IconValue,
- image: String,
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeRoundedProps(),
- ...makeSizeProps(),
- ...makeTagProps(),
- ...makeThemeProps(),
- ...makeVariantProps({
- variant: 'flat'
- })
- }, 'VAvatar');
- const VAvatar = genericComponent()({
- name: 'VAvatar',
- props: makeVAvatarProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- colorClasses,
- colorStyles,
- variantClasses
- } = useVariant(props);
- const {
- densityClasses
- } = useDensity(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- sizeClasses,
- sizeStyles
- } = useSize(props);
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-avatar', {
- 'v-avatar--start': props.start,
- 'v-avatar--end': props.end
- }, themeClasses.value, colorClasses.value, densityClasses.value, roundedClasses.value, sizeClasses.value, variantClasses.value, props.class],
- "style": [colorStyles.value, sizeStyles.value, props.style]
- }, {
- default: () => [props.image ? vue.createVNode(VImg, {
- "key": "image",
- "src": props.image,
- "alt": "",
- "cover": true
- }, null) : props.icon ? vue.createVNode(VIcon, {
- "key": "icon",
- "icon": props.icon
- }, null) : slots.default?.(), genOverlays(false, 'v-avatar')]
- }));
- return {};
- }
- });
- // Types
- const VChipGroupSymbol = Symbol.for('vuetify:v-chip-group');
- const makeVChipGroupProps = propsFactory({
- column: Boolean,
- filter: Boolean,
- valueComparator: {
- type: Function,
- default: deepEqual
- },
- ...makeComponentProps(),
- ...makeGroupProps({
- selectedClass: 'v-chip--selected'
- }),
- ...makeTagProps(),
- ...makeThemeProps(),
- ...makeVariantProps({
- variant: 'tonal'
- })
- }, 'VChipGroup');
- const VChipGroup = genericComponent()({
- name: 'VChipGroup',
- props: makeVChipGroupProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- isSelected,
- select,
- next,
- prev,
- selected
- } = useGroup(props, VChipGroupSymbol);
- provideDefaults({
- VChip: {
- color: vue.toRef(props, 'color'),
- disabled: vue.toRef(props, 'disabled'),
- filter: vue.toRef(props, 'filter'),
- variant: vue.toRef(props, 'variant')
- }
- });
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-chip-group', {
- 'v-chip-group--column': props.column
- }, themeClasses.value, props.class],
- "style": props.style
- }, {
- default: () => [slots.default?.({
- isSelected,
- select,
- next,
- prev,
- selected: selected.value
- })]
- }));
- return {};
- }
- });
- // Types
- const makeVChipProps = propsFactory({
- activeClass: String,
- appendAvatar: String,
- appendIcon: IconValue,
- closable: Boolean,
- closeIcon: {
- type: IconValue,
- default: '$delete'
- },
- closeLabel: {
- type: String,
- default: '$vuetify.close'
- },
- draggable: Boolean,
- filter: Boolean,
- filterIcon: {
- type: String,
- default: '$complete'
- },
- label: Boolean,
- link: {
- type: Boolean,
- default: undefined
- },
- pill: Boolean,
- prependAvatar: String,
- prependIcon: IconValue,
- ripple: {
- type: [Boolean, Object],
- default: true
- },
- text: String,
- modelValue: {
- type: Boolean,
- default: true
- },
- onClick: EventProp(),
- onClickOnce: EventProp(),
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeElevationProps(),
- ...makeGroupItemProps(),
- ...makeRoundedProps(),
- ...makeRouterProps(),
- ...makeSizeProps(),
- ...makeTagProps({
- tag: 'span'
- }),
- ...makeThemeProps(),
- ...makeVariantProps({
- variant: 'tonal'
- })
- }, 'VChip');
- const VChip = genericComponent()({
- name: 'VChip',
- directives: {
- Ripple
- },
- props: makeVChipProps(),
- emits: {
- 'click:close': e => true,
- 'update:modelValue': value => true,
- 'group:selected': val => true,
- click: e => true
- },
- setup(props, _ref) {
- let {
- attrs,
- emit,
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const {
- borderClasses
- } = useBorder(props);
- const {
- colorClasses,
- colorStyles,
- variantClasses
- } = useVariant(props);
- const {
- densityClasses
- } = useDensity(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- sizeClasses
- } = useSize(props);
- const {
- themeClasses
- } = provideTheme(props);
- const isActive = useProxiedModel(props, 'modelValue');
- const group = useGroupItem(props, VChipGroupSymbol, false);
- const link = useLink(props, attrs);
- const isLink = vue.computed(() => props.link !== false && link.isLink.value);
- const isClickable = vue.computed(() => !props.disabled && props.link !== false && (!!group || props.link || link.isClickable.value));
- const closeProps = vue.computed(() => ({
- 'aria-label': t(props.closeLabel),
- onClick(e) {
- isActive.value = false;
- emit('click:close', e);
- }
- }));
- function onClick(e) {
- emit('click', e);
- if (!isClickable.value) return;
- link.navigate?.(e);
- group?.toggle();
- }
- function onKeyDown(e) {
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- onClick(e);
- }
- }
- return () => {
- const Tag = link.isLink.value ? 'a' : props.tag;
- const hasAppendMedia = !!(props.appendIcon || props.appendAvatar);
- const hasAppend = !!(hasAppendMedia || slots.append);
- const hasClose = !!(slots.close || props.closable);
- const hasFilter = !!(slots.filter || props.filter) && group;
- const hasPrependMedia = !!(props.prependIcon || props.prependAvatar);
- const hasPrepend = !!(hasPrependMedia || slots.prepend);
- const hasColor = !group || group.isSelected.value;
- return isActive.value && vue.withDirectives(vue.createVNode(Tag, {
- "class": ['v-chip', {
- 'v-chip--disabled': props.disabled,
- 'v-chip--label': props.label,
- 'v-chip--link': isClickable.value,
- 'v-chip--filter': hasFilter,
- 'v-chip--pill': props.pill
- }, themeClasses.value, borderClasses.value, hasColor ? colorClasses.value : undefined, densityClasses.value, elevationClasses.value, roundedClasses.value, sizeClasses.value, variantClasses.value, group?.selectedClass.value, props.class],
- "style": [hasColor ? colorStyles.value : undefined, props.style],
- "disabled": props.disabled || undefined,
- "draggable": props.draggable,
- "href": link.href.value,
- "tabindex": isClickable.value ? 0 : undefined,
- "onClick": onClick,
- "onKeydown": isClickable.value && !isLink.value && onKeyDown
- }, {
- default: () => [genOverlays(isClickable.value, 'v-chip'), hasFilter && vue.createVNode(VExpandXTransition, {
- "key": "filter"
- }, {
- default: () => [vue.withDirectives(vue.createVNode("div", {
- "class": "v-chip__filter"
- }, [!slots.filter ? vue.createVNode(VIcon, {
- "key": "filter-icon",
- "icon": props.filterIcon
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "filter-defaults",
- "disabled": !props.filterIcon,
- "defaults": {
- VIcon: {
- icon: props.filterIcon
- }
- }
- }, slots.filter)]), [[vue.vShow, group.isSelected.value]])]
- }), hasPrepend && vue.createVNode("div", {
- "key": "prepend",
- "class": "v-chip__prepend"
- }, [!slots.prepend ? vue.createVNode(vue.Fragment, null, [props.prependIcon && vue.createVNode(VIcon, {
- "key": "prepend-icon",
- "icon": props.prependIcon,
- "start": true
- }, null), props.prependAvatar && vue.createVNode(VAvatar, {
- "key": "prepend-avatar",
- "image": props.prependAvatar,
- "start": true
- }, null)]) : vue.createVNode(VDefaultsProvider, {
- "key": "prepend-defaults",
- "disabled": !hasPrependMedia,
- "defaults": {
- VAvatar: {
- image: props.prependAvatar,
- start: true
- },
- VIcon: {
- icon: props.prependIcon,
- start: true
- }
- }
- }, slots.prepend)]), vue.createVNode("div", {
- "class": "v-chip__content"
- }, [slots.default?.({
- isSelected: group?.isSelected.value,
- selectedClass: group?.selectedClass.value,
- select: group?.select,
- toggle: group?.toggle,
- value: group?.value.value,
- disabled: props.disabled
- }) ?? props.text]), hasAppend && vue.createVNode("div", {
- "key": "append",
- "class": "v-chip__append"
- }, [!slots.append ? vue.createVNode(vue.Fragment, null, [props.appendIcon && vue.createVNode(VIcon, {
- "key": "append-icon",
- "end": true,
- "icon": props.appendIcon
- }, null), props.appendAvatar && vue.createVNode(VAvatar, {
- "key": "append-avatar",
- "end": true,
- "image": props.appendAvatar
- }, null)]) : vue.createVNode(VDefaultsProvider, {
- "key": "append-defaults",
- "disabled": !hasAppendMedia,
- "defaults": {
- VAvatar: {
- end: true,
- image: props.appendAvatar
- },
- VIcon: {
- end: true,
- icon: props.appendIcon
- }
- }
- }, slots.append)]), hasClose && vue.createVNode("div", vue.mergeProps({
- "key": "close",
- "class": "v-chip__close"
- }, closeProps.value), [!slots.close ? vue.createVNode(VIcon, {
- "key": "close-icon",
- "icon": props.closeIcon,
- "size": "x-small"
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "close-defaults",
- "defaults": {
- VIcon: {
- icon: props.closeIcon,
- size: 'x-small'
- }
- }
- }, slots.close)])]
- }), [[vue.resolveDirective("ripple"), isClickable.value && props.ripple, null]]);
- };
- }
- });
- // Utilities
- // List
- const ListKey = Symbol.for('vuetify:list');
- function createList() {
- const parent = vue.inject(ListKey, {
- hasPrepend: vue.shallowRef(false),
- updateHasPrepend: () => null
- });
- const data = {
- hasPrepend: vue.shallowRef(false),
- updateHasPrepend: value => {
- if (value) data.hasPrepend.value = value;
- }
- };
- vue.provide(ListKey, data);
- return parent;
- }
- function useList() {
- return vue.inject(ListKey, null);
- }
- const singleOpenStrategy = {
- open: _ref => {
- let {
- id,
- value,
- opened,
- parents
- } = _ref;
- if (value) {
- const newOpened = new Set();
- newOpened.add(id);
- let parent = parents.get(id);
- while (parent != null) {
- newOpened.add(parent);
- parent = parents.get(parent);
- }
- return newOpened;
- } else {
- opened.delete(id);
- return opened;
- }
- },
- select: () => null
- };
- const multipleOpenStrategy = {
- open: _ref2 => {
- let {
- id,
- value,
- opened,
- parents
- } = _ref2;
- if (value) {
- let parent = parents.get(id);
- opened.add(id);
- while (parent != null && parent !== id) {
- opened.add(parent);
- parent = parents.get(parent);
- }
- return opened;
- } else {
- opened.delete(id);
- }
- return opened;
- },
- select: () => null
- };
- const listOpenStrategy = {
- open: multipleOpenStrategy.open,
- select: _ref3 => {
- let {
- id,
- value,
- opened,
- parents
- } = _ref3;
- if (!value) return opened;
- const path = [];
- let parent = parents.get(id);
- while (parent != null) {
- path.push(parent);
- parent = parents.get(parent);
- }
- return new Set(path);
- }
- };
- /* eslint-disable sonarjs/no-identical-functions */
- // Utilities
- const independentSelectStrategy = mandatory => {
- const strategy = {
- select: _ref => {
- let {
- id,
- value,
- selected
- } = _ref;
- id = vue.toRaw(id);
- // When mandatory and we're trying to deselect when id
- // is the only currently selected item then do nothing
- if (mandatory && !value) {
- const on = Array.from(selected.entries()).reduce((arr, _ref2) => {
- let [key, value] = _ref2;
- return value === 'on' ? [...arr, key] : arr;
- }, []);
- if (on.length === 1 && on[0] === id) return selected;
- }
- selected.set(id, value ? 'on' : 'off');
- return selected;
- },
- in: (v, children, parents) => {
- let map = new Map();
- for (const id of v || []) {
- map = strategy.select({
- id,
- value: true,
- selected: new Map(map),
- children,
- parents
- });
- }
- return map;
- },
- out: v => {
- const arr = [];
- for (const [key, value] of v.entries()) {
- if (value === 'on') arr.push(key);
- }
- return arr;
- }
- };
- return strategy;
- };
- const independentSingleSelectStrategy = mandatory => {
- const parentStrategy = independentSelectStrategy(mandatory);
- const strategy = {
- select: _ref3 => {
- let {
- selected,
- id,
- ...rest
- } = _ref3;
- id = vue.toRaw(id);
- const singleSelected = selected.has(id) ? new Map([[id, selected.get(id)]]) : new Map();
- return parentStrategy.select({
- ...rest,
- id,
- selected: singleSelected
- });
- },
- in: (v, children, parents) => {
- let map = new Map();
- if (v?.length) {
- map = parentStrategy.in(v.slice(0, 1), children, parents);
- }
- return map;
- },
- out: (v, children, parents) => {
- return parentStrategy.out(v, children, parents);
- }
- };
- return strategy;
- };
- const leafSelectStrategy = mandatory => {
- const parentStrategy = independentSelectStrategy(mandatory);
- const strategy = {
- select: _ref4 => {
- let {
- id,
- selected,
- children,
- ...rest
- } = _ref4;
- id = vue.toRaw(id);
- if (children.has(id)) return selected;
- return parentStrategy.select({
- id,
- selected,
- children,
- ...rest
- });
- },
- in: parentStrategy.in,
- out: parentStrategy.out
- };
- return strategy;
- };
- const leafSingleSelectStrategy = mandatory => {
- const parentStrategy = independentSingleSelectStrategy(mandatory);
- const strategy = {
- select: _ref5 => {
- let {
- id,
- selected,
- children,
- ...rest
- } = _ref5;
- id = vue.toRaw(id);
- if (children.has(id)) return selected;
- return parentStrategy.select({
- id,
- selected,
- children,
- ...rest
- });
- },
- in: parentStrategy.in,
- out: parentStrategy.out
- };
- return strategy;
- };
- const classicSelectStrategy = mandatory => {
- const strategy = {
- select: _ref6 => {
- let {
- id,
- value,
- selected,
- children,
- parents
- } = _ref6;
- id = vue.toRaw(id);
- const original = new Map(selected);
- const items = [id];
- while (items.length) {
- const item = items.shift();
- selected.set(item, value ? 'on' : 'off');
- if (children.has(item)) {
- items.push(...children.get(item));
- }
- }
- let parent = parents.get(id);
- while (parent) {
- const childrenIds = children.get(parent);
- const everySelected = childrenIds.every(cid => selected.get(cid) === 'on');
- const noneSelected = childrenIds.every(cid => !selected.has(cid) || selected.get(cid) === 'off');
- selected.set(parent, everySelected ? 'on' : noneSelected ? 'off' : 'indeterminate');
- parent = parents.get(parent);
- }
- // If mandatory and planned deselect results in no selected
- // items then we can't do it, so return original state
- if (mandatory && !value) {
- const on = Array.from(selected.entries()).reduce((arr, _ref7) => {
- let [key, value] = _ref7;
- return value === 'on' ? [...arr, key] : arr;
- }, []);
- if (on.length === 0) return original;
- }
- return selected;
- },
- in: (v, children, parents) => {
- let map = new Map();
- for (const id of v || []) {
- map = strategy.select({
- id,
- value: true,
- selected: new Map(map),
- children,
- parents
- });
- }
- return map;
- },
- out: (v, children) => {
- const arr = [];
- for (const [key, value] of v.entries()) {
- if (value === 'on' && !children.has(key)) arr.push(key);
- }
- return arr;
- }
- };
- return strategy;
- };
- // Composables
- // Types
- const VNestedSymbol = Symbol.for('vuetify:nested');
- const emptyNested = {
- id: vue.shallowRef(),
- root: {
- register: () => null,
- unregister: () => null,
- parents: vue.ref(new Map()),
- children: vue.ref(new Map()),
- open: () => null,
- openOnSelect: () => null,
- select: () => null,
- opened: vue.ref(new Set()),
- selected: vue.ref(new Map()),
- selectedValues: vue.ref([])
- }
- };
- const makeNestedProps = propsFactory({
- selectStrategy: [String, Function],
- openStrategy: [String, Object],
- opened: Array,
- selected: Array,
- mandatory: Boolean
- }, 'nested');
- const useNested = props => {
- let isUnmounted = false;
- const children = vue.ref(new Map());
- const parents = vue.ref(new Map());
- const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(v), v => [...v.values()]);
- const selectStrategy = vue.computed(() => {
- if (typeof props.selectStrategy === 'object') return props.selectStrategy;
- switch (props.selectStrategy) {
- case 'single-leaf':
- return leafSingleSelectStrategy(props.mandatory);
- case 'leaf':
- return leafSelectStrategy(props.mandatory);
- case 'independent':
- return independentSelectStrategy(props.mandatory);
- case 'single-independent':
- return independentSingleSelectStrategy(props.mandatory);
- case 'classic':
- default:
- return classicSelectStrategy(props.mandatory);
- }
- });
- const openStrategy = vue.computed(() => {
- if (typeof props.openStrategy === 'object') return props.openStrategy;
- switch (props.openStrategy) {
- case 'list':
- return listOpenStrategy;
- case 'single':
- return singleOpenStrategy;
- case 'multiple':
- default:
- return multipleOpenStrategy;
- }
- });
- const selected = useProxiedModel(props, 'selected', props.selected, v => selectStrategy.value.in(v, children.value, parents.value), v => selectStrategy.value.out(v, children.value, parents.value));
- vue.onBeforeUnmount(() => {
- isUnmounted = true;
- });
- function getPath(id) {
- const path = [];
- let parent = id;
- while (parent != null) {
- path.unshift(parent);
- parent = parents.value.get(parent);
- }
- return path;
- }
- const vm = getCurrentInstance('nested');
- const nested = {
- id: vue.shallowRef(),
- root: {
- opened,
- selected,
- selectedValues: vue.computed(() => {
- const arr = [];
- for (const [key, value] of selected.value.entries()) {
- if (value === 'on') arr.push(key);
- }
- return arr;
- }),
- register: (id, parentId, isGroup) => {
- parentId && id !== parentId && parents.value.set(id, parentId);
- isGroup && children.value.set(id, []);
- if (parentId != null) {
- children.value.set(parentId, [...(children.value.get(parentId) || []), id]);
- }
- },
- unregister: id => {
- if (isUnmounted) return;
- children.value.delete(id);
- const parent = parents.value.get(id);
- if (parent) {
- const list = children.value.get(parent) ?? [];
- children.value.set(parent, list.filter(child => child !== id));
- }
- parents.value.delete(id);
- opened.value.delete(id);
- },
- open: (id, value, event) => {
- vm.emit('click:open', {
- id,
- value,
- path: getPath(id),
- event
- });
- const newOpened = openStrategy.value.open({
- id,
- value,
- opened: new Set(opened.value),
- children: children.value,
- parents: parents.value,
- event
- });
- newOpened && (opened.value = newOpened);
- },
- openOnSelect: (id, value, event) => {
- const newOpened = openStrategy.value.select({
- id,
- value,
- selected: new Map(selected.value),
- opened: new Set(opened.value),
- children: children.value,
- parents: parents.value,
- event
- });
- newOpened && (opened.value = newOpened);
- },
- select: (id, value, event) => {
- vm.emit('click:select', {
- id,
- value,
- path: getPath(id),
- event
- });
- const newSelected = selectStrategy.value.select({
- id,
- value,
- selected: new Map(selected.value),
- children: children.value,
- parents: parents.value,
- event
- });
- newSelected && (selected.value = newSelected);
- nested.root.openOnSelect(id, value, event);
- },
- children,
- parents
- }
- };
- vue.provide(VNestedSymbol, nested);
- return nested.root;
- };
- const useNestedItem = (id, isGroup) => {
- const parent = vue.inject(VNestedSymbol, emptyNested);
- const uidSymbol = Symbol(getUid());
- const computedId = vue.computed(() => id.value !== undefined ? id.value : uidSymbol);
- const item = {
- ...parent,
- id: computedId,
- open: (open, e) => parent.root.open(computedId.value, open, e),
- openOnSelect: (open, e) => parent.root.openOnSelect(computedId.value, open, e),
- isOpen: vue.computed(() => parent.root.opened.value.has(computedId.value)),
- parent: vue.computed(() => parent.root.parents.value.get(computedId.value)),
- select: (selected, e) => parent.root.select(computedId.value, selected, e),
- isSelected: vue.computed(() => parent.root.selected.value.get(vue.toRaw(computedId.value)) === 'on'),
- isIndeterminate: vue.computed(() => parent.root.selected.value.get(computedId.value) === 'indeterminate'),
- isLeaf: vue.computed(() => !parent.root.children.value.get(computedId.value)),
- isGroupActivator: parent.isGroupActivator
- };
- !parent.isGroupActivator && parent.root.register(computedId.value, parent.id.value, isGroup);
- vue.onBeforeUnmount(() => {
- !parent.isGroupActivator && parent.root.unregister(computedId.value);
- });
- isGroup && vue.provide(VNestedSymbol, item);
- return item;
- };
- const useNestedGroupActivator = () => {
- const parent = vue.inject(VNestedSymbol, emptyNested);
- vue.provide(VNestedSymbol, {
- ...parent,
- isGroupActivator: true
- });
- };
- const VListGroupActivator = defineComponent({
- name: 'VListGroupActivator',
- setup(_, _ref) {
- let {
- slots
- } = _ref;
- useNestedGroupActivator();
- return () => slots.default?.();
- }
- });
- const makeVListGroupProps = propsFactory({
- /* @deprecated */
- activeColor: String,
- baseColor: String,
- color: String,
- collapseIcon: {
- type: IconValue,
- default: '$collapse'
- },
- expandIcon: {
- type: IconValue,
- default: '$expand'
- },
- prependIcon: IconValue,
- appendIcon: IconValue,
- fluid: Boolean,
- subgroup: Boolean,
- title: String,
- value: null,
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VListGroup');
- const VListGroup = genericComponent()({
- name: 'VListGroup',
- props: makeVListGroupProps(),
- setup(props, _ref2) {
- let {
- slots
- } = _ref2;
- const {
- isOpen,
- open,
- id: _id
- } = useNestedItem(vue.toRef(props, 'value'), true);
- const id = vue.computed(() => `v-list-group--id-${String(_id.value)}`);
- const list = useList();
- const {
- isBooted
- } = useSsrBoot();
- function onClick(e) {
- open(!isOpen.value, e);
- }
- const activatorProps = vue.computed(() => ({
- onClick,
- class: 'v-list-group__header',
- id: id.value
- }));
- const toggleIcon = vue.computed(() => isOpen.value ? props.collapseIcon : props.expandIcon);
- const activatorDefaults = vue.computed(() => ({
- VListItem: {
- active: isOpen.value,
- activeColor: props.activeColor,
- baseColor: props.baseColor,
- color: props.color,
- prependIcon: props.prependIcon || props.subgroup && toggleIcon.value,
- appendIcon: props.appendIcon || !props.subgroup && toggleIcon.value,
- title: props.title,
- value: props.value
- }
- }));
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-list-group', {
- 'v-list-group--prepend': list?.hasPrepend.value,
- 'v-list-group--fluid': props.fluid,
- 'v-list-group--subgroup': props.subgroup,
- 'v-list-group--open': isOpen.value
- }, props.class],
- "style": props.style
- }, {
- default: () => [slots.activator && vue.createVNode(VDefaultsProvider, {
- "defaults": activatorDefaults.value
- }, {
- default: () => [vue.createVNode(VListGroupActivator, null, {
- default: () => [slots.activator({
- props: activatorProps.value,
- isOpen: isOpen.value
- })]
- })]
- }), vue.createVNode(MaybeTransition, {
- "transition": {
- component: VExpandTransition
- },
- "disabled": !isBooted.value
- }, {
- default: () => [vue.withDirectives(vue.createVNode("div", {
- "class": "v-list-group__items",
- "role": "group",
- "aria-labelledby": id.value
- }, [slots.default?.()]), [[vue.vShow, isOpen.value]])]
- })]
- }));
- return {};
- }
- });
- // Utilities
- const VListItemSubtitle = createSimpleFunctional('v-list-item-subtitle');
- // Utilities
- const VListItemTitle = createSimpleFunctional('v-list-item-title');
- // Types
- const makeVListItemProps = propsFactory({
- active: {
- type: Boolean,
- default: undefined
- },
- activeClass: String,
- /* @deprecated */
- activeColor: String,
- appendAvatar: String,
- appendIcon: IconValue,
- baseColor: String,
- disabled: Boolean,
- lines: String,
- link: {
- type: Boolean,
- default: undefined
- },
- nav: Boolean,
- prependAvatar: String,
- prependIcon: IconValue,
- ripple: {
- type: [Boolean, Object],
- default: true
- },
- subtitle: [String, Number, Boolean],
- title: [String, Number, Boolean],
- value: null,
- onClick: EventProp(),
- onClickOnce: EventProp(),
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeDimensionProps(),
- ...makeElevationProps(),
- ...makeRoundedProps(),
- ...makeRouterProps(),
- ...makeTagProps(),
- ...makeThemeProps(),
- ...makeVariantProps({
- variant: 'text'
- })
- }, 'VListItem');
- const VListItem = genericComponent()({
- name: 'VListItem',
- directives: {
- Ripple
- },
- props: makeVListItemProps(),
- emits: {
- click: e => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots,
- emit
- } = _ref;
- const link = useLink(props, attrs);
- const id = vue.computed(() => props.value === undefined ? link.href.value : props.value);
- const {
- select,
- isSelected,
- isIndeterminate,
- isGroupActivator,
- root,
- parent,
- openOnSelect
- } = useNestedItem(id, false);
- const list = useList();
- const isActive = vue.computed(() => props.active !== false && (props.active || link.isActive?.value || isSelected.value));
- const isLink = vue.computed(() => props.link !== false && link.isLink.value);
- const isClickable = vue.computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value || props.value != null && !!list));
- const roundedProps = vue.computed(() => props.rounded || props.nav);
- const color = vue.computed(() => props.color ?? props.activeColor);
- const variantProps = vue.computed(() => ({
- color: isActive.value ? color.value ?? props.baseColor : props.baseColor,
- variant: props.variant
- }));
- vue.watch(() => link.isActive?.value, val => {
- if (val && parent.value != null) {
- root.open(parent.value, true);
- }
- if (val) {
- openOnSelect(val);
- }
- }, {
- immediate: true
- });
- const {
- themeClasses
- } = provideTheme(props);
- const {
- borderClasses
- } = useBorder(props);
- const {
- colorClasses,
- colorStyles,
- variantClasses
- } = useVariant(variantProps);
- const {
- densityClasses
- } = useDensity(props);
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- roundedClasses
- } = useRounded(roundedProps);
- const lineClasses = vue.computed(() => props.lines ? `v-list-item--${props.lines}-line` : undefined);
- const slotProps = vue.computed(() => ({
- isActive: isActive.value,
- select,
- isSelected: isSelected.value,
- isIndeterminate: isIndeterminate.value
- }));
- function onClick(e) {
- emit('click', e);
- if (isGroupActivator || !isClickable.value) return;
- link.navigate?.(e);
- props.value != null && select(!isSelected.value, e);
- }
- function onKeyDown(e) {
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- onClick(e);
- }
- }
- useRender(() => {
- const Tag = isLink.value ? 'a' : props.tag;
- const hasTitle = slots.title || props.title;
- const hasSubtitle = slots.subtitle || props.subtitle;
- const hasAppendMedia = !!(props.appendAvatar || props.appendIcon);
- const hasAppend = !!(hasAppendMedia || slots.append);
- const hasPrependMedia = !!(props.prependAvatar || props.prependIcon);
- const hasPrepend = !!(hasPrependMedia || slots.prepend);
- list?.updateHasPrepend(hasPrepend);
- if (props.activeColor) {
- deprecate('active-color', ['color', 'base-color']);
- }
- return vue.withDirectives(vue.createVNode(Tag, {
- "class": ['v-list-item', {
- 'v-list-item--active': isActive.value,
- 'v-list-item--disabled': props.disabled,
- 'v-list-item--link': isClickable.value,
- 'v-list-item--nav': props.nav,
- 'v-list-item--prepend': !hasPrepend && list?.hasPrepend.value,
- [`${props.activeClass}`]: props.activeClass && isActive.value
- }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, variantClasses.value, props.class],
- "style": [colorStyles.value, dimensionStyles.value, props.style],
- "href": link.href.value,
- "tabindex": isClickable.value ? list ? -2 : 0 : undefined,
- "onClick": onClick,
- "onKeydown": isClickable.value && !isLink.value && onKeyDown
- }, {
- default: () => [genOverlays(isClickable.value || isActive.value, 'v-list-item'), hasPrepend && vue.createVNode("div", {
- "key": "prepend",
- "class": "v-list-item__prepend"
- }, [!slots.prepend ? vue.createVNode(vue.Fragment, null, [props.prependAvatar && vue.createVNode(VAvatar, {
- "key": "prepend-avatar",
- "density": props.density,
- "image": props.prependAvatar
- }, null), props.prependIcon && vue.createVNode(VIcon, {
- "key": "prepend-icon",
- "density": props.density,
- "icon": props.prependIcon
- }, null)]) : vue.createVNode(VDefaultsProvider, {
- "key": "prepend-defaults",
- "disabled": !hasPrependMedia,
- "defaults": {
- VAvatar: {
- density: props.density,
- image: props.prependAvatar
- },
- VIcon: {
- density: props.density,
- icon: props.prependIcon
- },
- VListItemAction: {
- start: true
- }
- }
- }, {
- default: () => [slots.prepend?.(slotProps.value)]
- })]), vue.createVNode("div", {
- "class": "v-list-item__content",
- "data-no-activator": ""
- }, [hasTitle && vue.createVNode(VListItemTitle, {
- "key": "title"
- }, {
- default: () => [slots.title?.({
- title: props.title
- }) ?? props.title]
- }), hasSubtitle && vue.createVNode(VListItemSubtitle, {
- "key": "subtitle"
- }, {
- default: () => [slots.subtitle?.({
- subtitle: props.subtitle
- }) ?? props.subtitle]
- }), slots.default?.(slotProps.value)]), hasAppend && vue.createVNode("div", {
- "key": "append",
- "class": "v-list-item__append"
- }, [!slots.append ? vue.createVNode(vue.Fragment, null, [props.appendIcon && vue.createVNode(VIcon, {
- "key": "append-icon",
- "density": props.density,
- "icon": props.appendIcon
- }, null), props.appendAvatar && vue.createVNode(VAvatar, {
- "key": "append-avatar",
- "density": props.density,
- "image": props.appendAvatar
- }, null)]) : vue.createVNode(VDefaultsProvider, {
- "key": "append-defaults",
- "disabled": !hasAppendMedia,
- "defaults": {
- VAvatar: {
- density: props.density,
- image: props.appendAvatar
- },
- VIcon: {
- density: props.density,
- icon: props.appendIcon
- },
- VListItemAction: {
- end: true
- }
- }
- }, {
- default: () => [slots.append?.(slotProps.value)]
- })])]
- }), [[vue.resolveDirective("ripple"), isClickable.value && props.ripple]]);
- });
- return {};
- }
- });
- const makeVListSubheaderProps = propsFactory({
- color: String,
- inset: Boolean,
- sticky: Boolean,
- title: String,
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VListSubheader');
- const VListSubheader = genericComponent()({
- name: 'VListSubheader',
- props: makeVListSubheaderProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.toRef(props, 'color'));
- useRender(() => {
- const hasText = !!(slots.default || props.title);
- return vue.createVNode(props.tag, {
- "class": ['v-list-subheader', {
- 'v-list-subheader--inset': props.inset,
- 'v-list-subheader--sticky': props.sticky
- }, textColorClasses.value, props.class],
- "style": [{
- textColorStyles
- }, props.style]
- }, {
- default: () => [hasText && vue.createVNode("div", {
- "class": "v-list-subheader__text"
- }, [slots.default?.() ?? props.title])]
- });
- });
- return {};
- }
- });
- const makeVDividerProps = propsFactory({
- color: String,
- inset: Boolean,
- length: [Number, String],
- thickness: [Number, String],
- vertical: Boolean,
- ...makeComponentProps(),
- ...makeThemeProps()
- }, 'VDivider');
- const VDivider = genericComponent()({
- name: 'VDivider',
- props: makeVDividerProps(),
- setup(props, _ref) {
- let {
- attrs
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.toRef(props, 'color'));
- const dividerStyles = vue.computed(() => {
- const styles = {};
- if (props.length) {
- styles[props.vertical ? 'maxHeight' : 'maxWidth'] = convertToUnit(props.length);
- }
- if (props.thickness) {
- styles[props.vertical ? 'borderRightWidth' : 'borderTopWidth'] = convertToUnit(props.thickness);
- }
- return styles;
- });
- useRender(() => vue.createVNode("hr", {
- "class": [{
- 'v-divider': true,
- 'v-divider--inset': props.inset,
- 'v-divider--vertical': props.vertical
- }, themeClasses.value, textColorClasses.value, props.class],
- "style": [dividerStyles.value, textColorStyles.value, props.style],
- "aria-orientation": !attrs.role || attrs.role === 'separator' ? props.vertical ? 'vertical' : 'horizontal' : undefined,
- "role": `${attrs.role || 'separator'}`
- }, null));
- return {};
- }
- });
- // Types
- const makeVListChildrenProps = propsFactory({
- items: Array
- }, 'VListChildren');
- const VListChildren = genericComponent()({
- name: 'VListChildren',
- props: makeVListChildrenProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- createList();
- return () => slots.default?.() ?? props.items?.map(_ref2 => {
- let {
- children,
- props: itemProps,
- type,
- raw: item
- } = _ref2;
- if (type === 'divider') {
- return slots.divider?.({
- props: itemProps
- }) ?? vue.createVNode(VDivider, itemProps, null);
- }
- if (type === 'subheader') {
- return slots.subheader?.({
- props: itemProps
- }) ?? vue.createVNode(VListSubheader, itemProps, null);
- }
- const slotsWithItem = {
- subtitle: slots.subtitle ? slotProps => slots.subtitle?.({
- ...slotProps,
- item
- }) : undefined,
- prepend: slots.prepend ? slotProps => slots.prepend?.({
- ...slotProps,
- item
- }) : undefined,
- append: slots.append ? slotProps => slots.append?.({
- ...slotProps,
- item
- }) : undefined,
- title: slots.title ? slotProps => slots.title?.({
- ...slotProps,
- item
- }) : undefined
- };
- const [listGroupProps, _1] = VListGroup.filterProps(itemProps);
- return children ? vue.createVNode(VListGroup, vue.mergeProps({
- "value": itemProps?.value
- }, listGroupProps), {
- activator: _ref3 => {
- let {
- props: activatorProps
- } = _ref3;
- return slots.header ? slots.header({
- props: {
- ...itemProps,
- ...activatorProps
- }
- }) : vue.createVNode(VListItem, vue.mergeProps(itemProps, activatorProps), slotsWithItem);
- },
- default: () => vue.createVNode(VListChildren, {
- "items": children
- }, slots)
- }) : slots.item ? slots.item({
- props: itemProps
- }) : vue.createVNode(VListItem, itemProps, slotsWithItem);
- });
- }
- });
- // Utilities
- // Types
- // Composables
- const makeItemsProps = propsFactory({
- items: {
- type: Array,
- default: () => []
- },
- itemTitle: {
- type: [String, Array, Function],
- default: 'title'
- },
- itemValue: {
- type: [String, Array, Function],
- default: 'value'
- },
- itemChildren: {
- type: [Boolean, String, Array, Function],
- default: 'children'
- },
- itemProps: {
- type: [Boolean, String, Array, Function],
- default: 'props'
- },
- returnObject: Boolean
- }, 'list-items');
- function transformItem$1(props, item) {
- const title = getPropertyFromItem(item, props.itemTitle, item);
- const value = props.returnObject ? item : getPropertyFromItem(item, props.itemValue, title);
- const children = getPropertyFromItem(item, props.itemChildren);
- const itemProps = props.itemProps === true ? typeof item === 'object' && item != null && !Array.isArray(item) ? 'children' in item ? pick(item, ['children'])[1] : item : undefined : getPropertyFromItem(item, props.itemProps);
- const _props = {
- title,
- value,
- ...itemProps
- };
- return {
- title: String(_props.title ?? ''),
- value: _props.value,
- props: _props,
- children: Array.isArray(children) ? transformItems$1(props, children) : undefined,
- raw: item
- };
- }
- function transformItems$1(props, items) {
- const array = [];
- for (const item of items) {
- array.push(transformItem$1(props, item));
- }
- return array;
- }
- function useItems(props) {
- const items = vue.computed(() => transformItems$1(props, props.items));
- return useTransformItems(items, value => transformItem$1(props, value));
- }
- function useTransformItems(items, transform) {
- function transformIn(value) {
- return value
- // When the model value is null, returns an InternalItem based on null
- // only if null is one of the items
- .filter(v => v !== null || items.value.some(item => item.value === null)).map(v => {
- const existingItem = items.value.find(item => deepEqual(v, item.value));
- // Nullish existingItem means value is a custom input value from combobox
- // In this case, use transformItem to create an InternalItem based on value
- return existingItem ?? transform(v);
- });
- }
- function transformOut(value) {
- return value.map(_ref => {
- let {
- value
- } = _ref;
- return value;
- });
- }
- return {
- items,
- transformIn,
- transformOut
- };
- }
- // Types
- function isPrimitive(value) {
- return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
- }
- function transformItem(props, item) {
- const type = getPropertyFromItem(item, props.itemType, 'item');
- const title = isPrimitive(item) ? item : getPropertyFromItem(item, props.itemTitle);
- const value = getPropertyFromItem(item, props.itemValue, undefined);
- const children = getPropertyFromItem(item, props.itemChildren);
- const itemProps = props.itemProps === true ? pick(item, ['children'])[1] : getPropertyFromItem(item, props.itemProps);
- const _props = {
- title,
- value,
- ...itemProps
- };
- return {
- type,
- title: _props.title,
- value: _props.value,
- props: _props,
- children: type === 'item' && children ? transformItems(props, children) : undefined,
- raw: item
- };
- }
- function transformItems(props, items) {
- const array = [];
- for (const item of items) {
- array.push(transformItem(props, item));
- }
- return array;
- }
- function useListItems(props) {
- const items = vue.computed(() => transformItems(props, props.items));
- return {
- items
- };
- }
- const makeVListProps = propsFactory({
- baseColor: String,
- /* @deprecated */
- activeColor: String,
- activeClass: String,
- bgColor: String,
- disabled: Boolean,
- lines: {
- type: [Boolean, String],
- default: 'one'
- },
- nav: Boolean,
- ...makeNestedProps({
- selectStrategy: 'single-leaf',
- openStrategy: 'list'
- }),
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeDimensionProps(),
- ...makeElevationProps(),
- itemType: {
- type: String,
- default: 'type'
- },
- ...makeItemsProps(),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeThemeProps(),
- ...makeVariantProps({
- variant: 'text'
- })
- }, 'VList');
- const VList = genericComponent()({
- name: 'VList',
- props: makeVListProps(),
- emits: {
- 'update:selected': val => true,
- 'update:opened': val => true,
- 'click:open': value => true,
- 'click:select': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- items
- } = useListItems(props);
- const {
- themeClasses
- } = provideTheme(props);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'bgColor'));
- const {
- borderClasses
- } = useBorder(props);
- const {
- densityClasses
- } = useDensity(props);
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- open,
- select
- } = useNested(props);
- const lineClasses = vue.computed(() => props.lines ? `v-list--${props.lines}-line` : undefined);
- const activeColor = vue.toRef(props, 'activeColor');
- const baseColor = vue.toRef(props, 'baseColor');
- const color = vue.toRef(props, 'color');
- createList();
- provideDefaults({
- VListGroup: {
- activeColor,
- baseColor,
- color
- },
- VListItem: {
- activeClass: vue.toRef(props, 'activeClass'),
- activeColor,
- baseColor,
- color,
- density: vue.toRef(props, 'density'),
- disabled: vue.toRef(props, 'disabled'),
- lines: vue.toRef(props, 'lines'),
- nav: vue.toRef(props, 'nav'),
- variant: vue.toRef(props, 'variant')
- }
- });
- const isFocused = vue.shallowRef(false);
- const contentRef = vue.ref();
- function onFocusin(e) {
- isFocused.value = true;
- }
- function onFocusout(e) {
- isFocused.value = false;
- }
- function onFocus(e) {
- if (!isFocused.value && !(e.relatedTarget && contentRef.value?.contains(e.relatedTarget))) focus();
- }
- function onKeydown(e) {
- if (!contentRef.value) return;
- if (e.key === 'ArrowDown') {
- focus('next');
- } else if (e.key === 'ArrowUp') {
- focus('prev');
- } else if (e.key === 'Home') {
- focus('first');
- } else if (e.key === 'End') {
- focus('last');
- } else {
- return;
- }
- e.preventDefault();
- }
- function focus(location) {
- if (contentRef.value) {
- return focusChild(contentRef.value, location);
- }
- }
- useRender(() => {
- return vue.createVNode(props.tag, {
- "ref": contentRef,
- "class": ['v-list', {
- 'v-list--disabled': props.disabled,
- 'v-list--nav': props.nav
- }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, lineClasses.value, roundedClasses.value, props.class],
- "style": [backgroundColorStyles.value, dimensionStyles.value, props.style],
- "tabindex": props.disabled || isFocused.value ? -1 : 0,
- "role": "listbox",
- "aria-activedescendant": undefined,
- "onFocusin": onFocusin,
- "onFocusout": onFocusout,
- "onFocus": onFocus,
- "onKeydown": onKeydown
- }, {
- default: () => [vue.createVNode(VListChildren, {
- "items": items.value
- }, slots)]
- });
- });
- return {
- open,
- select,
- focus
- };
- }
- });
- // Utilities
- const VListImg = createSimpleFunctional('v-list-img');
- const makeVListItemActionProps = propsFactory({
- start: Boolean,
- end: Boolean,
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VListItemAction');
- const VListItemAction = genericComponent()({
- name: 'VListItemAction',
- props: makeVListItemActionProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-list-item-action', {
- 'v-list-item-action--start': props.start,
- 'v-list-item-action--end': props.end
- }, props.class],
- "style": props.style
- }, slots));
- return {};
- }
- });
- const makeVListItemMediaProps = propsFactory({
- start: Boolean,
- end: Boolean,
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VListItemMedia');
- const VListItemMedia = genericComponent()({
- name: 'VListItemMedia',
- props: makeVListItemMediaProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => {
- return vue.createVNode(props.tag, {
- "class": ['v-list-item-media', {
- 'v-list-item-media--start': props.start,
- 'v-list-item-media--end': props.end
- }, props.class],
- "style": props.style
- }, slots);
- });
- return {};
- }
- });
- // Types
- /** Convert a point in local space to viewport space */
- function elementToViewport(point, offset) {
- return {
- x: point.x + offset.x,
- y: point.y + offset.y
- };
- }
- /** Get the difference between two points */
- function getOffset$1(a, b) {
- return {
- x: a.x - b.x,
- y: a.y - b.y
- };
- }
- /** Convert an anchor object to a point in local space */
- function anchorToPoint(anchor, box) {
- if (anchor.side === 'top' || anchor.side === 'bottom') {
- const {
- side,
- align
- } = anchor;
- const x = align === 'left' ? 0 : align === 'center' ? box.width / 2 : align === 'right' ? box.width : align;
- const y = side === 'top' ? 0 : side === 'bottom' ? box.height : side;
- return elementToViewport({
- x,
- y
- }, box);
- } else if (anchor.side === 'left' || anchor.side === 'right') {
- const {
- side,
- align
- } = anchor;
- const x = side === 'left' ? 0 : side === 'right' ? box.width : side;
- const y = align === 'top' ? 0 : align === 'center' ? box.height / 2 : align === 'bottom' ? box.height : align;
- return elementToViewport({
- x,
- y
- }, box);
- }
- return elementToViewport({
- x: box.width / 2,
- y: box.height / 2
- }, box);
- }
- // Composables
- // Types
- const locationStrategies = {
- static: staticLocationStrategy,
- // specific viewport position, usually centered
- connected: connectedLocationStrategy // connected to a certain element
- };
- const makeLocationStrategyProps = propsFactory({
- locationStrategy: {
- type: [String, Function],
- default: 'static',
- validator: val => typeof val === 'function' || val in locationStrategies
- },
- location: {
- type: String,
- default: 'bottom'
- },
- origin: {
- type: String,
- default: 'auto'
- },
- offset: [Number, String, Array]
- }, 'VOverlay-location-strategies');
- function useLocationStrategies(props, data) {
- const contentStyles = vue.ref({});
- const updateLocation = vue.ref();
- if (IN_BROWSER) {
- useToggleScope(() => !!(data.isActive.value && props.locationStrategy), reset => {
- vue.watch(() => props.locationStrategy, reset);
- vue.onScopeDispose(() => {
- updateLocation.value = undefined;
- });
- if (typeof props.locationStrategy === 'function') {
- updateLocation.value = props.locationStrategy(data, props, contentStyles)?.updateLocation;
- } else {
- updateLocation.value = locationStrategies[props.locationStrategy](data, props, contentStyles)?.updateLocation;
- }
- });
- window.addEventListener('resize', onResize, {
- passive: true
- });
- vue.onScopeDispose(() => {
- window.removeEventListener('resize', onResize);
- updateLocation.value = undefined;
- });
- }
- function onResize(e) {
- updateLocation.value?.(e);
- }
- return {
- contentStyles,
- updateLocation
- };
- }
- function staticLocationStrategy() {
- // TODO
- }
- /** Get size of element ignoring max-width/max-height */
- function getIntrinsicSize(el, isRtl) {
- // const scrollables = new Map<Element, [number, number]>()
- // el.querySelectorAll('*').forEach(el => {
- // const x = el.scrollLeft
- // const y = el.scrollTop
- // if (x || y) {
- // scrollables.set(el, [x, y])
- // }
- // })
- // const initialMaxWidth = el.style.maxWidth
- // const initialMaxHeight = el.style.maxHeight
- // el.style.removeProperty('max-width')
- // el.style.removeProperty('max-height')
- if (isRtl) {
- el.style.removeProperty('left');
- } else {
- el.style.removeProperty('right');
- }
- /* eslint-disable-next-line sonarjs/prefer-immediate-return */
- const contentBox = nullifyTransforms(el);
- if (isRtl) {
- contentBox.x += parseFloat(el.style.right || 0);
- } else {
- contentBox.x -= parseFloat(el.style.left || 0);
- }
- contentBox.y -= parseFloat(el.style.top || 0);
- // el.style.maxWidth = initialMaxWidth
- // el.style.maxHeight = initialMaxHeight
- // scrollables.forEach((position, el) => {
- // el.scrollTo(...position)
- // })
- return contentBox;
- }
- function connectedLocationStrategy(data, props, contentStyles) {
- const activatorFixed = isFixedPosition(data.activatorEl.value);
- if (activatorFixed) {
- Object.assign(contentStyles.value, {
- position: 'fixed',
- top: 0,
- [data.isRtl.value ? 'right' : 'left']: 0
- });
- }
- const {
- preferredAnchor,
- preferredOrigin
- } = destructComputed(() => {
- const parsedAnchor = parseAnchor(props.location, data.isRtl.value);
- const parsedOrigin = props.origin === 'overlap' ? parsedAnchor : props.origin === 'auto' ? flipSide(parsedAnchor) : parseAnchor(props.origin, data.isRtl.value);
- // Some combinations of props may produce an invalid origin
- if (parsedAnchor.side === parsedOrigin.side && parsedAnchor.align === flipAlign(parsedOrigin).align) {
- return {
- preferredAnchor: flipCorner(parsedAnchor),
- preferredOrigin: flipCorner(parsedOrigin)
- };
- } else {
- return {
- preferredAnchor: parsedAnchor,
- preferredOrigin: parsedOrigin
- };
- }
- });
- const [minWidth, minHeight, maxWidth, maxHeight] = ['minWidth', 'minHeight', 'maxWidth', 'maxHeight'].map(key => {
- return vue.computed(() => {
- const val = parseFloat(props[key]);
- return isNaN(val) ? Infinity : val;
- });
- });
- const offset = vue.computed(() => {
- if (Array.isArray(props.offset)) {
- return props.offset;
- }
- if (typeof props.offset === 'string') {
- const offset = props.offset.split(' ').map(parseFloat);
- if (offset.length < 2) offset.push(0);
- return offset;
- }
- return typeof props.offset === 'number' ? [props.offset, 0] : [0, 0];
- });
- let observe = false;
- const observer = new ResizeObserver(() => {
- if (observe) updateLocation();
- });
- vue.watch([data.activatorEl, data.contentEl], (_ref, _ref2) => {
- let [newActivatorEl, newContentEl] = _ref;
- let [oldActivatorEl, oldContentEl] = _ref2;
- if (oldActivatorEl) observer.unobserve(oldActivatorEl);
- if (newActivatorEl) observer.observe(newActivatorEl);
- if (oldContentEl) observer.unobserve(oldContentEl);
- if (newContentEl) observer.observe(newContentEl);
- }, {
- immediate: true
- });
- vue.onScopeDispose(() => {
- observer.disconnect();
- });
- // eslint-disable-next-line max-statements
- function updateLocation() {
- observe = false;
- requestAnimationFrame(() => {
- requestAnimationFrame(() => observe = true);
- });
- if (!data.activatorEl.value || !data.contentEl.value) return;
- const targetBox = data.activatorEl.value.getBoundingClientRect();
- const contentBox = getIntrinsicSize(data.contentEl.value, data.isRtl.value);
- const scrollParents = getScrollParents(data.contentEl.value);
- const viewportMargin = 12;
- if (!scrollParents.length) {
- scrollParents.push(document.documentElement);
- if (!(data.contentEl.value.style.top && data.contentEl.value.style.left)) {
- contentBox.x -= parseFloat(document.documentElement.style.getPropertyValue('--v-body-scroll-x') || 0);
- contentBox.y -= parseFloat(document.documentElement.style.getPropertyValue('--v-body-scroll-y') || 0);
- }
- }
- const viewport = scrollParents.reduce((box, el) => {
- const rect = el.getBoundingClientRect();
- const scrollBox = new Box({
- x: el === document.documentElement ? 0 : rect.x,
- y: el === document.documentElement ? 0 : rect.y,
- width: el.clientWidth,
- height: el.clientHeight
- });
- if (box) {
- return new Box({
- x: Math.max(box.left, scrollBox.left),
- y: Math.max(box.top, scrollBox.top),
- width: Math.min(box.right, scrollBox.right) - Math.max(box.left, scrollBox.left),
- height: Math.min(box.bottom, scrollBox.bottom) - Math.max(box.top, scrollBox.top)
- });
- }
- return scrollBox;
- }, undefined);
- viewport.x += viewportMargin;
- viewport.y += viewportMargin;
- viewport.width -= viewportMargin * 2;
- viewport.height -= viewportMargin * 2;
- let placement = {
- anchor: preferredAnchor.value,
- origin: preferredOrigin.value
- };
- function checkOverflow(_placement) {
- const box = new Box(contentBox);
- const targetPoint = anchorToPoint(_placement.anchor, targetBox);
- const contentPoint = anchorToPoint(_placement.origin, box);
- let {
- x,
- y
- } = getOffset$1(targetPoint, contentPoint);
- switch (_placement.anchor.side) {
- case 'top':
- y -= offset.value[0];
- break;
- case 'bottom':
- y += offset.value[0];
- break;
- case 'left':
- x -= offset.value[0];
- break;
- case 'right':
- x += offset.value[0];
- break;
- }
- switch (_placement.anchor.align) {
- case 'top':
- y -= offset.value[1];
- break;
- case 'bottom':
- y += offset.value[1];
- break;
- case 'left':
- x -= offset.value[1];
- break;
- case 'right':
- x += offset.value[1];
- break;
- }
- box.x += x;
- box.y += y;
- box.width = Math.min(box.width, maxWidth.value);
- box.height = Math.min(box.height, maxHeight.value);
- const overflows = getOverflow(box, viewport);
- return {
- overflows,
- x,
- y
- };
- }
- let x = 0;
- let y = 0;
- const available = {
- x: 0,
- y: 0
- };
- const flipped = {
- x: false,
- y: false
- };
- let resets = -1;
- while (true) {
- if (resets++ > 10) {
- consoleError('Infinite loop detected in connectedLocationStrategy');
- break;
- }
- const {
- x: _x,
- y: _y,
- overflows
- } = checkOverflow(placement);
- x += _x;
- y += _y;
- contentBox.x += _x;
- contentBox.y += _y;
- // flip
- {
- const axis = getAxis(placement.anchor);
- const hasOverflowX = overflows.x.before || overflows.x.after;
- const hasOverflowY = overflows.y.before || overflows.y.after;
- let reset = false;
- ['x', 'y'].forEach(key => {
- if (key === 'x' && hasOverflowX && !flipped.x || key === 'y' && hasOverflowY && !flipped.y) {
- const newPlacement = {
- anchor: {
- ...placement.anchor
- },
- origin: {
- ...placement.origin
- }
- };
- const flip = key === 'x' ? axis === 'y' ? flipAlign : flipSide : axis === 'y' ? flipSide : flipAlign;
- newPlacement.anchor = flip(newPlacement.anchor);
- newPlacement.origin = flip(newPlacement.origin);
- const {
- overflows: newOverflows
- } = checkOverflow(newPlacement);
- if (newOverflows[key].before <= overflows[key].before && newOverflows[key].after <= overflows[key].after || newOverflows[key].before + newOverflows[key].after < (overflows[key].before + overflows[key].after) / 2) {
- placement = newPlacement;
- reset = flipped[key] = true;
- }
- }
- });
- if (reset) continue;
- }
- // shift
- if (overflows.x.before) {
- x += overflows.x.before;
- contentBox.x += overflows.x.before;
- }
- if (overflows.x.after) {
- x -= overflows.x.after;
- contentBox.x -= overflows.x.after;
- }
- if (overflows.y.before) {
- y += overflows.y.before;
- contentBox.y += overflows.y.before;
- }
- if (overflows.y.after) {
- y -= overflows.y.after;
- contentBox.y -= overflows.y.after;
- }
- // size
- {
- const overflows = getOverflow(contentBox, viewport);
- available.x = viewport.width - overflows.x.before - overflows.x.after;
- available.y = viewport.height - overflows.y.before - overflows.y.after;
- x += overflows.x.before;
- contentBox.x += overflows.x.before;
- y += overflows.y.before;
- contentBox.y += overflows.y.before;
- }
- break;
- }
- const axis = getAxis(placement.anchor);
- Object.assign(contentStyles.value, {
- '--v-overlay-anchor-origin': `${placement.anchor.side} ${placement.anchor.align}`,
- transformOrigin: `${placement.origin.side} ${placement.origin.align}`,
- // transform: `translate(${pixelRound(x)}px, ${pixelRound(y)}px)`,
- top: convertToUnit(pixelRound(y)),
- left: data.isRtl.value ? undefined : convertToUnit(pixelRound(x)),
- right: data.isRtl.value ? convertToUnit(pixelRound(-x)) : undefined,
- minWidth: convertToUnit(axis === 'y' ? Math.min(minWidth.value, targetBox.width) : minWidth.value),
- maxWidth: convertToUnit(pixelCeil(clamp(available.x, minWidth.value === Infinity ? 0 : minWidth.value, maxWidth.value))),
- maxHeight: convertToUnit(pixelCeil(clamp(available.y, minHeight.value === Infinity ? 0 : minHeight.value, maxHeight.value)))
- });
- return {
- available,
- contentBox
- };
- }
- vue.watch(() => [preferredAnchor.value, preferredOrigin.value, props.offset, props.minWidth, props.minHeight, props.maxWidth, props.maxHeight], () => updateLocation());
- vue.nextTick(() => {
- const result = updateLocation();
- // TODO: overflowing content should only require a single updateLocation call
- // Icky hack to make sure the content is positioned consistently
- if (!result) return;
- const {
- available,
- contentBox
- } = result;
- if (contentBox.height > available.y) {
- requestAnimationFrame(() => {
- updateLocation();
- requestAnimationFrame(() => {
- updateLocation();
- });
- });
- }
- });
- return {
- updateLocation
- };
- }
- function pixelRound(val) {
- return Math.round(val * devicePixelRatio) / devicePixelRatio;
- }
- function pixelCeil(val) {
- return Math.ceil(val * devicePixelRatio) / devicePixelRatio;
- }
- let clean = true;
- const frames = [];
- /**
- * Schedule a task to run in an animation frame on its own
- * This is useful for heavy tasks that may cause jank if all ran together
- */
- function requestNewFrame(cb) {
- if (!clean || frames.length) {
- frames.push(cb);
- run();
- } else {
- clean = false;
- cb();
- run();
- }
- }
- let raf = -1;
- function run() {
- cancelAnimationFrame(raf);
- raf = requestAnimationFrame(() => {
- const frame = frames.shift();
- if (frame) frame();
- if (frames.length) run();else clean = true;
- });
- }
- // Utilities
- // Types
- const scrollStrategies = {
- none: null,
- close: closeScrollStrategy,
- block: blockScrollStrategy,
- reposition: repositionScrollStrategy
- };
- const makeScrollStrategyProps = propsFactory({
- scrollStrategy: {
- type: [String, Function],
- default: 'block',
- validator: val => typeof val === 'function' || val in scrollStrategies
- }
- }, 'VOverlay-scroll-strategies');
- function useScrollStrategies(props, data) {
- if (!IN_BROWSER) return;
- let scope;
- vue.watchEffect(async () => {
- scope?.stop();
- if (!(data.isActive.value && props.scrollStrategy)) return;
- scope = vue.effectScope();
- await vue.nextTick();
- scope.active && scope.run(() => {
- if (typeof props.scrollStrategy === 'function') {
- props.scrollStrategy(data, props, scope);
- } else {
- scrollStrategies[props.scrollStrategy]?.(data, props, scope);
- }
- });
- });
- vue.onScopeDispose(() => {
- scope?.stop();
- });
- }
- function closeScrollStrategy(data) {
- function onScroll(e) {
- data.isActive.value = false;
- }
- bindScroll(data.activatorEl.value ?? data.contentEl.value, onScroll);
- }
- function blockScrollStrategy(data, props) {
- const offsetParent = data.root.value?.offsetParent;
- const scrollElements = [...new Set([...getScrollParents(data.activatorEl.value, props.contained ? offsetParent : undefined), ...getScrollParents(data.contentEl.value, props.contained ? offsetParent : undefined)])].filter(el => !el.classList.contains('v-overlay-scroll-blocked'));
- const scrollbarWidth = window.innerWidth - document.documentElement.offsetWidth;
- const scrollableParent = (el => hasScrollbar(el) && el)(offsetParent || document.documentElement);
- if (scrollableParent) {
- data.root.value.classList.add('v-overlay--scroll-blocked');
- }
- scrollElements.forEach((el, i) => {
- el.style.setProperty('--v-body-scroll-x', convertToUnit(-el.scrollLeft));
- el.style.setProperty('--v-body-scroll-y', convertToUnit(-el.scrollTop));
- if (el !== document.documentElement) {
- el.style.setProperty('--v-scrollbar-offset', convertToUnit(scrollbarWidth));
- }
- el.classList.add('v-overlay-scroll-blocked');
- });
- vue.onScopeDispose(() => {
- scrollElements.forEach((el, i) => {
- const x = parseFloat(el.style.getPropertyValue('--v-body-scroll-x'));
- const y = parseFloat(el.style.getPropertyValue('--v-body-scroll-y'));
- el.style.removeProperty('--v-body-scroll-x');
- el.style.removeProperty('--v-body-scroll-y');
- el.style.removeProperty('--v-scrollbar-offset');
- el.classList.remove('v-overlay-scroll-blocked');
- el.scrollLeft = -x;
- el.scrollTop = -y;
- });
- if (scrollableParent) {
- data.root.value.classList.remove('v-overlay--scroll-blocked');
- }
- });
- }
- function repositionScrollStrategy(data, props, scope) {
- let slow = false;
- let raf = -1;
- let ric = -1;
- function update(e) {
- requestNewFrame(() => {
- const start = performance.now();
- data.updateLocation.value?.(e);
- const time = performance.now() - start;
- slow = time / (1000 / 60) > 2;
- });
- }
- ric = (typeof requestIdleCallback === 'undefined' ? cb => cb() : requestIdleCallback)(() => {
- scope.run(() => {
- bindScroll(data.activatorEl.value ?? data.contentEl.value, e => {
- if (slow) {
- // If the position calculation is slow,
- // defer updates until scrolling is finished.
- // Browsers usually fire one scroll event per frame so
- // we just wait until we've got two frames without an event
- cancelAnimationFrame(raf);
- raf = requestAnimationFrame(() => {
- raf = requestAnimationFrame(() => {
- update(e);
- });
- });
- } else {
- update(e);
- }
- });
- });
- });
- vue.onScopeDispose(() => {
- typeof cancelIdleCallback !== 'undefined' && cancelIdleCallback(ric);
- cancelAnimationFrame(raf);
- });
- }
- /** @private */
- function bindScroll(el, onScroll) {
- const scrollElements = [document, ...getScrollParents(el)];
- scrollElements.forEach(el => {
- el.addEventListener('scroll', onScroll, {
- passive: true
- });
- });
- vue.onScopeDispose(() => {
- scrollElements.forEach(el => {
- el.removeEventListener('scroll', onScroll);
- });
- });
- }
- // Types
- const VMenuSymbol = Symbol.for('vuetify:v-menu');
- // Utilities
- // Types
- // Composables
- const makeDelayProps = propsFactory({
- closeDelay: [Number, String],
- openDelay: [Number, String]
- }, 'delay');
- function useDelay(props, cb) {
- const delays = {};
- const runDelayFactory = prop => () => {
- // istanbul ignore next
- if (!IN_BROWSER) return Promise.resolve(true);
- const active = prop === 'openDelay';
- delays.closeDelay && window.clearTimeout(delays.closeDelay);
- delete delays.closeDelay;
- delays.openDelay && window.clearTimeout(delays.openDelay);
- delete delays.openDelay;
- return new Promise(resolve => {
- const delay = parseInt(props[prop] ?? 0, 10);
- delays[prop] = window.setTimeout(() => {
- cb?.(active);
- resolve(active);
- }, delay);
- });
- };
- return {
- runCloseDelay: runDelayFactory('closeDelay'),
- runOpenDelay: runDelayFactory('openDelay')
- };
- }
- // Components
- // Types
- const makeActivatorProps = propsFactory({
- activator: [String, Object],
- activatorProps: {
- type: Object,
- default: () => ({})
- },
- openOnClick: {
- type: Boolean,
- default: undefined
- },
- openOnHover: Boolean,
- openOnFocus: {
- type: Boolean,
- default: undefined
- },
- closeOnContentClick: Boolean,
- ...makeDelayProps()
- }, 'VOverlay-activator');
- function useActivator(props, _ref) {
- let {
- isActive,
- isTop
- } = _ref;
- const activatorEl = vue.ref();
- let isHovered = false;
- let isFocused = false;
- let firstEnter = true;
- const openOnFocus = vue.computed(() => props.openOnFocus || props.openOnFocus == null && props.openOnHover);
- const openOnClick = vue.computed(() => props.openOnClick || props.openOnClick == null && !props.openOnHover && !openOnFocus.value);
- const {
- runOpenDelay,
- runCloseDelay
- } = useDelay(props, value => {
- if (value === (props.openOnHover && isHovered || openOnFocus.value && isFocused) && !(props.openOnHover && isActive.value && !isTop.value)) {
- if (isActive.value !== value) {
- firstEnter = true;
- }
- isActive.value = value;
- }
- });
- const availableEvents = {
- onClick: e => {
- e.stopPropagation();
- activatorEl.value = e.currentTarget || e.target;
- isActive.value = !isActive.value;
- },
- onMouseenter: e => {
- if (e.sourceCapabilities?.firesTouchEvents) return;
- isHovered = true;
- activatorEl.value = e.currentTarget || e.target;
- runOpenDelay();
- },
- onMouseleave: e => {
- isHovered = false;
- runCloseDelay();
- },
- onFocus: e => {
- if (matchesSelector(e.target, ':focus-visible') === false) return;
- isFocused = true;
- e.stopPropagation();
- activatorEl.value = e.currentTarget || e.target;
- runOpenDelay();
- },
- onBlur: e => {
- isFocused = false;
- e.stopPropagation();
- runCloseDelay();
- }
- };
- const activatorEvents = vue.computed(() => {
- const events = {};
- if (openOnClick.value) {
- events.onClick = availableEvents.onClick;
- }
- if (props.openOnHover) {
- events.onMouseenter = availableEvents.onMouseenter;
- events.onMouseleave = availableEvents.onMouseleave;
- }
- if (openOnFocus.value) {
- events.onFocus = availableEvents.onFocus;
- events.onBlur = availableEvents.onBlur;
- }
- return events;
- });
- const contentEvents = vue.computed(() => {
- const events = {};
- if (props.openOnHover) {
- events.onMouseenter = () => {
- isHovered = true;
- runOpenDelay();
- };
- events.onMouseleave = () => {
- isHovered = false;
- runCloseDelay();
- };
- }
- if (openOnFocus.value) {
- events.onFocusin = () => {
- isFocused = true;
- runOpenDelay();
- };
- events.onFocusout = () => {
- isFocused = false;
- runCloseDelay();
- };
- }
- if (props.closeOnContentClick) {
- const menu = vue.inject(VMenuSymbol, null);
- events.onClick = () => {
- isActive.value = false;
- menu?.closeParents();
- };
- }
- return events;
- });
- const scrimEvents = vue.computed(() => {
- const events = {};
- if (props.openOnHover) {
- events.onMouseenter = () => {
- if (firstEnter) {
- isHovered = true;
- firstEnter = false;
- runOpenDelay();
- }
- };
- events.onMouseleave = () => {
- isHovered = false;
- runCloseDelay();
- };
- }
- return events;
- });
- vue.watch(isTop, val => {
- if (val && (props.openOnHover && !isHovered && (!openOnFocus.value || !isFocused) || openOnFocus.value && !isFocused && (!props.openOnHover || !isHovered))) {
- isActive.value = false;
- }
- });
- const activatorRef = vue.ref();
- vue.watchEffect(() => {
- if (!activatorRef.value) return;
- vue.nextTick(() => {
- activatorEl.value = refElement(activatorRef.value);
- });
- });
- const vm = getCurrentInstance('useActivator');
- let scope;
- vue.watch(() => !!props.activator, val => {
- if (val && IN_BROWSER) {
- scope = vue.effectScope();
- scope.run(() => {
- _useActivator(props, vm, {
- activatorEl,
- activatorEvents
- });
- });
- } else if (scope) {
- scope.stop();
- }
- }, {
- flush: 'post',
- immediate: true
- });
- vue.onScopeDispose(() => {
- scope?.stop();
- });
- return {
- activatorEl,
- activatorRef,
- activatorEvents,
- contentEvents,
- scrimEvents
- };
- }
- function _useActivator(props, vm, _ref2) {
- let {
- activatorEl,
- activatorEvents
- } = _ref2;
- vue.watch(() => props.activator, (val, oldVal) => {
- if (oldVal && val !== oldVal) {
- const activator = getActivator(oldVal);
- activator && unbindActivatorProps(activator);
- }
- if (val) {
- vue.nextTick(() => bindActivatorProps());
- }
- }, {
- immediate: true
- });
- vue.watch(() => props.activatorProps, () => {
- bindActivatorProps();
- });
- vue.onScopeDispose(() => {
- unbindActivatorProps();
- });
- function bindActivatorProps() {
- let el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getActivator();
- let _props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : props.activatorProps;
- if (!el) return;
- bindProps(el, vue.mergeProps(activatorEvents.value, _props));
- }
- function unbindActivatorProps() {
- let el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getActivator();
- let _props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : props.activatorProps;
- if (!el) return;
- unbindProps(el, vue.mergeProps(activatorEvents.value, _props));
- }
- function getActivator() {
- let selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : props.activator;
- let activator;
- if (selector) {
- if (selector === 'parent') {
- let el = vm?.proxy?.$el?.parentNode;
- while (el.hasAttribute('data-no-activator')) {
- el = el.parentNode;
- }
- activator = el;
- } else if (typeof selector === 'string') {
- // Selector
- activator = document.querySelector(selector);
- } else if ('$el' in selector) {
- // Component (ref)
- activator = selector.$el;
- } else {
- // HTMLElement | Element
- activator = selector;
- }
- }
- // The activator should only be a valid element (Ignore comments and text nodes)
- activatorEl.value = activator?.nodeType === Node.ELEMENT_NODE ? activator : null;
- return activatorEl.value;
- }
- }
- // Utilities
- // Types
- const breakpoints = ['sm', 'md', 'lg', 'xl', 'xxl']; // no xs
- const DisplaySymbol = Symbol.for('vuetify:display');
- const defaultDisplayOptions = {
- mobileBreakpoint: 'lg',
- thresholds: {
- xs: 0,
- sm: 600,
- md: 960,
- lg: 1280,
- xl: 1920,
- xxl: 2560
- }
- };
- const parseDisplayOptions = function () {
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultDisplayOptions;
- return mergeDeep(defaultDisplayOptions, options);
- };
- function getClientWidth(ssr) {
- return IN_BROWSER && !ssr ? window.innerWidth : typeof ssr === 'object' && ssr.clientWidth || 0;
- }
- function getClientHeight(ssr) {
- return IN_BROWSER && !ssr ? window.innerHeight : typeof ssr === 'object' && ssr.clientHeight || 0;
- }
- function getPlatform(ssr) {
- const userAgent = IN_BROWSER && !ssr ? window.navigator.userAgent : 'ssr';
- function match(regexp) {
- return Boolean(userAgent.match(regexp));
- }
- const android = match(/android/i);
- const ios = match(/iphone|ipad|ipod/i);
- const cordova = match(/cordova/i);
- const electron = match(/electron/i);
- const chrome = match(/chrome/i);
- const edge = match(/edge/i);
- const firefox = match(/firefox/i);
- const opera = match(/opera/i);
- const win = match(/win/i);
- const mac = match(/mac/i);
- const linux = match(/linux/i);
- return {
- android,
- ios,
- cordova,
- electron,
- chrome,
- edge,
- firefox,
- opera,
- win,
- mac,
- linux,
- touch: SUPPORTS_TOUCH,
- ssr: userAgent === 'ssr'
- };
- }
- function createDisplay(options, ssr) {
- const {
- thresholds,
- mobileBreakpoint
- } = parseDisplayOptions(options);
- const height = vue.shallowRef(getClientHeight(ssr));
- const platform = vue.shallowRef(getPlatform(ssr));
- const state = vue.reactive({});
- const width = vue.shallowRef(getClientWidth(ssr));
- function updateSize() {
- height.value = getClientHeight();
- width.value = getClientWidth();
- }
- function update() {
- updateSize();
- platform.value = getPlatform();
- }
- // eslint-disable-next-line max-statements
- vue.watchEffect(() => {
- const xs = width.value < thresholds.sm;
- const sm = width.value < thresholds.md && !xs;
- const md = width.value < thresholds.lg && !(sm || xs);
- const lg = width.value < thresholds.xl && !(md || sm || xs);
- const xl = width.value < thresholds.xxl && !(lg || md || sm || xs);
- const xxl = width.value >= thresholds.xxl;
- const name = xs ? 'xs' : sm ? 'sm' : md ? 'md' : lg ? 'lg' : xl ? 'xl' : 'xxl';
- const breakpointValue = typeof mobileBreakpoint === 'number' ? mobileBreakpoint : thresholds[mobileBreakpoint];
- const mobile = width.value < breakpointValue;
- state.xs = xs;
- state.sm = sm;
- state.md = md;
- state.lg = lg;
- state.xl = xl;
- state.xxl = xxl;
- state.smAndUp = !xs;
- state.mdAndUp = !(xs || sm);
- state.lgAndUp = !(xs || sm || md);
- state.xlAndUp = !(xs || sm || md || lg);
- state.smAndDown = !(md || lg || xl || xxl);
- state.mdAndDown = !(lg || xl || xxl);
- state.lgAndDown = !(xl || xxl);
- state.xlAndDown = !xxl;
- state.name = name;
- state.height = height.value;
- state.width = width.value;
- state.mobile = mobile;
- state.mobileBreakpoint = mobileBreakpoint;
- state.platform = platform.value;
- state.thresholds = thresholds;
- });
- if (IN_BROWSER) {
- window.addEventListener('resize', updateSize, {
- passive: true
- });
- }
- return {
- ...vue.toRefs(state),
- update,
- ssr: !!ssr
- };
- }
- function useDisplay() {
- const display = vue.inject(DisplaySymbol);
- if (!display) throw new Error('Could not find Vuetify display injection');
- return display;
- }
- // Composables
- function useHydration() {
- if (!IN_BROWSER) return vue.shallowRef(false);
- const {
- ssr
- } = useDisplay();
- if (ssr) {
- const isMounted = vue.shallowRef(false);
- vue.onMounted(() => {
- isMounted.value = true;
- });
- return isMounted;
- } else {
- return vue.shallowRef(true);
- }
- }
- // Utilities
- // Types
- const makeLazyProps = propsFactory({
- eager: Boolean
- }, 'lazy');
- function useLazy(props, active) {
- const isBooted = vue.shallowRef(false);
- const hasContent = vue.computed(() => isBooted.value || props.eager || active.value);
- vue.watch(active, () => isBooted.value = true);
- function onAfterLeave() {
- if (!props.eager) isBooted.value = false;
- }
- return {
- isBooted,
- hasContent,
- onAfterLeave
- };
- }
- // Utilities
- function useScopeId() {
- const vm = getCurrentInstance('useScopeId');
- const scopeId = vm.vnode.scopeId;
- return {
- scopeId: scopeId ? {
- [scopeId]: ''
- } : undefined
- };
- }
- // Composables
- // Types
- const StackSymbol = Symbol.for('vuetify:stack');
- const globalStack = vue.reactive([]);
- function useStack(isActive, zIndex, disableGlobalStack) {
- const vm = getCurrentInstance('useStack');
- const createStackEntry = !disableGlobalStack;
- const parent = vue.inject(StackSymbol, undefined);
- const stack = vue.reactive({
- activeChildren: new Set()
- });
- vue.provide(StackSymbol, stack);
- const _zIndex = vue.shallowRef(+zIndex.value);
- useToggleScope(isActive, () => {
- const lastZIndex = globalStack.at(-1)?.[1];
- _zIndex.value = lastZIndex ? lastZIndex + 10 : +zIndex.value;
- if (createStackEntry) {
- globalStack.push([vm.uid, _zIndex.value]);
- }
- parent?.activeChildren.add(vm.uid);
- vue.onScopeDispose(() => {
- if (createStackEntry) {
- const idx = vue.toRaw(globalStack).findIndex(v => v[0] === vm.uid);
- globalStack.splice(idx, 1);
- }
- parent?.activeChildren.delete(vm.uid);
- });
- });
- const globalTop = vue.shallowRef(true);
- if (createStackEntry) {
- vue.watchEffect(() => {
- const _isTop = globalStack.at(-1)?.[0] === vm.uid;
- setTimeout(() => globalTop.value = _isTop);
- });
- }
- const localTop = vue.computed(() => !stack.activeChildren.size);
- return {
- globalTop: vue.readonly(globalTop),
- localTop,
- stackStyles: vue.computed(() => ({
- zIndex: _zIndex.value
- }))
- };
- }
- // Utilities
- // Types
- function useTeleport(target) {
- const teleportTarget = vue.computed(() => {
- const _target = target.value;
- if (_target === true || !IN_BROWSER) return undefined;
- const targetElement = _target === false ? document.body : typeof _target === 'string' ? document.querySelector(_target) : _target;
- if (targetElement == null) {
- vue.warn(`Unable to locate target ${_target}`);
- return undefined;
- }
- let container = targetElement.querySelector(':scope > .v-overlay-container');
- if (!container) {
- container = document.createElement('div');
- container.className = 'v-overlay-container';
- targetElement.appendChild(container);
- }
- return container;
- });
- return {
- teleportTarget
- };
- }
- // Utilities
- // Types
- function defaultConditional() {
- return true;
- }
- function checkEvent(e, el, binding) {
- // The include element callbacks below can be expensive
- // so we should avoid calling them when we're not active.
- // Explicitly check for false to allow fallback compatibility
- // with non-toggleable components
- if (!e || checkIsActive(e, binding) === false) return false;
- // If we're clicking inside the shadowroot, then the app root doesn't get the same
- // level of introspection as to _what_ we're clicking. We want to check to see if
- // our target is the shadowroot parent container, and if it is, ignore.
- const root = attachedRoot(el);
- if (typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot && root.host === e.target) return false;
- // Check if additional elements were passed to be included in check
- // (click must be outside all included elements, if any)
- const elements = (typeof binding.value === 'object' && binding.value.include || (() => []))();
- // Add the root element for the component this directive was defined on
- elements.push(el);
- // Check if it's a click outside our elements, and then if our callback returns true.
- // Non-toggleable components should take action in their callback and return falsy.
- // Toggleable can return true if it wants to deactivate.
- // Note that, because we're in the capture phase, this callback will occur before
- // the bubbling click event on any outside elements.
- return !elements.some(el => el?.contains(e.target));
- }
- function checkIsActive(e, binding) {
- const isActive = typeof binding.value === 'object' && binding.value.closeConditional || defaultConditional;
- return isActive(e);
- }
- function directive(e, el, binding) {
- const handler = typeof binding.value === 'function' ? binding.value : binding.value.handler;
- el._clickOutside.lastMousedownWasOutside && checkEvent(e, el, binding) && setTimeout(() => {
- checkIsActive(e, binding) && handler && handler(e);
- }, 0);
- }
- function handleShadow(el, callback) {
- const root = attachedRoot(el);
- callback(document);
- if (typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot) {
- callback(root);
- }
- }
- const ClickOutside = {
- // [data-app] may not be found
- // if using bind, inserted makes
- // sure that the root element is
- // available, iOS does not support
- // clicks on body
- mounted(el, binding) {
- const onClick = e => directive(e, el, binding);
- const onMousedown = e => {
- el._clickOutside.lastMousedownWasOutside = checkEvent(e, el, binding);
- };
- handleShadow(el, app => {
- app.addEventListener('click', onClick, true);
- app.addEventListener('mousedown', onMousedown, true);
- });
- if (!el._clickOutside) {
- el._clickOutside = {
- lastMousedownWasOutside: false
- };
- }
- el._clickOutside[binding.instance.$.uid] = {
- onClick,
- onMousedown
- };
- },
- unmounted(el, binding) {
- if (!el._clickOutside) return;
- handleShadow(el, app => {
- if (!app || !el._clickOutside?.[binding.instance.$.uid]) return;
- const {
- onClick,
- onMousedown
- } = el._clickOutside[binding.instance.$.uid];
- app.removeEventListener('click', onClick, true);
- app.removeEventListener('mousedown', onMousedown, true);
- });
- delete el._clickOutside[binding.instance.$.uid];
- }
- };
- // Types
- function Scrim(props) {
- const {
- modelValue,
- color,
- ...rest
- } = props;
- return vue.createVNode(vue.Transition, {
- "name": "fade-transition",
- "appear": true
- }, {
- default: () => [props.modelValue && vue.createVNode("div", vue.mergeProps({
- "class": ['v-overlay__scrim', props.color.backgroundColorClasses.value],
- "style": props.color.backgroundColorStyles.value
- }, rest), null)]
- });
- }
- const makeVOverlayProps = propsFactory({
- absolute: Boolean,
- attach: [Boolean, String, Object],
- closeOnBack: {
- type: Boolean,
- default: true
- },
- contained: Boolean,
- contentClass: null,
- contentProps: null,
- disabled: Boolean,
- noClickAnimation: Boolean,
- modelValue: Boolean,
- persistent: Boolean,
- scrim: {
- type: [Boolean, String],
- default: true
- },
- zIndex: {
- type: [Number, String],
- default: 2000
- },
- ...makeActivatorProps(),
- ...makeComponentProps(),
- ...makeDimensionProps(),
- ...makeLazyProps(),
- ...makeLocationStrategyProps(),
- ...makeScrollStrategyProps(),
- ...makeThemeProps(),
- ...makeTransitionProps()
- }, 'VOverlay');
- const VOverlay = genericComponent()({
- name: 'VOverlay',
- directives: {
- ClickOutside
- },
- inheritAttrs: false,
- props: {
- _disableGlobalStack: Boolean,
- ...makeVOverlayProps()
- },
- emits: {
- 'click:outside': e => true,
- 'update:modelValue': value => true,
- afterLeave: () => true
- },
- setup(props, _ref) {
- let {
- slots,
- attrs,
- emit
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const isActive = vue.computed({
- get: () => model.value,
- set: v => {
- if (!(v && props.disabled)) model.value = v;
- }
- });
- const {
- teleportTarget
- } = useTeleport(vue.computed(() => props.attach || props.contained));
- const {
- themeClasses
- } = provideTheme(props);
- const {
- rtlClasses,
- isRtl
- } = useRtl();
- const {
- hasContent,
- onAfterLeave
- } = useLazy(props, isActive);
- const scrimColor = useBackgroundColor(vue.computed(() => {
- return typeof props.scrim === 'string' ? props.scrim : null;
- }));
- const {
- globalTop,
- localTop,
- stackStyles
- } = useStack(isActive, vue.toRef(props, 'zIndex'), props._disableGlobalStack);
- const {
- activatorEl,
- activatorRef,
- activatorEvents,
- contentEvents,
- scrimEvents
- } = useActivator(props, {
- isActive,
- isTop: localTop
- });
- const {
- dimensionStyles
- } = useDimension(props);
- const isMounted = useHydration();
- const {
- scopeId
- } = useScopeId();
- vue.watch(() => props.disabled, v => {
- if (v) isActive.value = false;
- });
- const root = vue.ref();
- const contentEl = vue.ref();
- const {
- contentStyles,
- updateLocation
- } = useLocationStrategies(props, {
- isRtl,
- contentEl,
- activatorEl,
- isActive
- });
- useScrollStrategies(props, {
- root,
- contentEl,
- activatorEl,
- isActive,
- updateLocation
- });
- function onClickOutside(e) {
- emit('click:outside', e);
- if (!props.persistent) isActive.value = false;else animateClick();
- }
- function closeConditional() {
- return isActive.value && globalTop.value;
- }
- IN_BROWSER && vue.watch(isActive, val => {
- if (val) {
- window.addEventListener('keydown', onKeydown);
- } else {
- window.removeEventListener('keydown', onKeydown);
- }
- }, {
- immediate: true
- });
- function onKeydown(e) {
- if (e.key === 'Escape' && globalTop.value) {
- if (!props.persistent) {
- isActive.value = false;
- if (contentEl.value?.contains(document.activeElement)) {
- activatorEl.value?.focus();
- }
- } else animateClick();
- }
- }
- const router = useRouter();
- useToggleScope(() => props.closeOnBack, () => {
- useBackButton(router, next => {
- if (globalTop.value && isActive.value) {
- next(false);
- if (!props.persistent) isActive.value = false;else animateClick();
- } else {
- next();
- }
- });
- });
- const top = vue.ref();
- vue.watch(() => isActive.value && (props.absolute || props.contained) && teleportTarget.value == null, val => {
- if (val) {
- const scrollParent = getScrollParent(root.value);
- if (scrollParent && scrollParent !== document.scrollingElement) {
- top.value = scrollParent.scrollTop;
- }
- }
- });
- // Add a quick "bounce" animation to the content
- function animateClick() {
- if (props.noClickAnimation) return;
- contentEl.value && animate(contentEl.value, [{
- transformOrigin: 'center'
- }, {
- transform: 'scale(1.03)'
- }, {
- transformOrigin: 'center'
- }], {
- duration: 150,
- easing: standardEasing
- });
- }
- useRender(() => vue.createVNode(vue.Fragment, null, [slots.activator?.({
- isActive: isActive.value,
- props: vue.mergeProps({
- ref: activatorRef
- }, activatorEvents.value, props.activatorProps)
- }), isMounted.value && hasContent.value && vue.createVNode(vue.Teleport, {
- "disabled": !teleportTarget.value,
- "to": teleportTarget.value
- }, {
- default: () => [vue.createVNode("div", vue.mergeProps({
- "class": ['v-overlay', {
- 'v-overlay--absolute': props.absolute || props.contained,
- 'v-overlay--active': isActive.value,
- 'v-overlay--contained': props.contained
- }, themeClasses.value, rtlClasses.value, props.class],
- "style": [stackStyles.value, {
- top: convertToUnit(top.value)
- }, props.style],
- "ref": root
- }, scopeId, attrs), [vue.createVNode(Scrim, vue.mergeProps({
- "color": scrimColor,
- "modelValue": isActive.value && !!props.scrim
- }, scrimEvents.value), null), vue.createVNode(MaybeTransition, {
- "appear": true,
- "persisted": true,
- "transition": props.transition,
- "target": activatorEl.value,
- "onAfterLeave": () => {
- onAfterLeave();
- emit('afterLeave');
- }
- }, {
- default: () => [vue.withDirectives(vue.createVNode("div", vue.mergeProps({
- "ref": contentEl,
- "class": ['v-overlay__content', props.contentClass],
- "style": [dimensionStyles.value, contentStyles.value]
- }, contentEvents.value, props.contentProps), [slots.default?.({
- isActive
- })]), [[vue.vShow, isActive.value], [vue.resolveDirective("click-outside"), {
- handler: onClickOutside,
- closeConditional,
- include: () => [activatorEl.value]
- }]])]
- })])]
- })]));
- return {
- activatorEl,
- animateClick,
- contentEl,
- globalTop,
- localTop,
- updateLocation
- };
- }
- });
- // Types
- const Refs = Symbol('Forwarded refs');
- /** Omit properties starting with P */
- function getDescriptor(obj, key) {
- let currentObj = obj;
- while (currentObj) {
- const descriptor = Reflect.getOwnPropertyDescriptor(currentObj, key);
- if (descriptor) return descriptor;
- currentObj = Object.getPrototypeOf(currentObj);
- }
- return undefined;
- }
- function forwardRefs(target) {
- for (var _len = arguments.length, refs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
- refs[_key - 1] = arguments[_key];
- }
- target[Refs] = refs;
- return new Proxy(target, {
- get(target, key) {
- if (Reflect.has(target, key)) {
- return Reflect.get(target, key);
- }
- // Skip internal properties
- if (typeof key === 'symbol' || key.startsWith('__')) return;
- for (const ref of refs) {
- if (ref.value && Reflect.has(ref.value, key)) {
- const val = Reflect.get(ref.value, key);
- return typeof val === 'function' ? val.bind(ref.value) : val;
- }
- }
- },
- has(target, key) {
- if (Reflect.has(target, key)) {
- return true;
- }
- // Skip internal properties
- if (typeof key === 'symbol' || key.startsWith('__')) return false;
- for (const ref of refs) {
- if (ref.value && Reflect.has(ref.value, key)) {
- return true;
- }
- }
- return false;
- },
- set(target, key, value) {
- if (Reflect.has(target, key)) {
- return Reflect.set(target, key, value);
- }
- // Skip internal properties
- if (typeof key === 'symbol' || key.startsWith('__')) return false;
- for (const ref of refs) {
- if (ref.value && Reflect.has(ref.value, key)) {
- return Reflect.set(ref.value, key, value);
- }
- }
- return false;
- },
- getOwnPropertyDescriptor(target, key) {
- const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
- if (descriptor) return descriptor;
- // Skip internal properties
- if (typeof key === 'symbol' || key.startsWith('__')) return;
- // Check each ref's own properties
- for (const ref of refs) {
- if (!ref.value) continue;
- const descriptor = getDescriptor(ref.value, key) ?? ('_' in ref.value ? getDescriptor(ref.value._?.setupState, key) : undefined);
- if (descriptor) return descriptor;
- }
- // Recursive search up each ref's prototype
- for (const ref of refs) {
- const childRefs = ref.value && ref.value[Refs];
- if (!childRefs) continue;
- const queue = childRefs.slice();
- while (queue.length) {
- const ref = queue.shift();
- const descriptor = getDescriptor(ref.value, key);
- if (descriptor) return descriptor;
- const childRefs = ref.value && ref.value[Refs];
- if (childRefs) queue.push(...childRefs);
- }
- }
- return undefined;
- }
- });
- }
- // Types
- const makeVMenuProps = propsFactory({
- // TODO
- // disableKeys: Boolean,
- id: String,
- ...omit(makeVOverlayProps({
- closeDelay: 250,
- closeOnContentClick: true,
- locationStrategy: 'connected',
- openDelay: 300,
- scrim: false,
- scrollStrategy: 'reposition',
- transition: {
- component: VDialogTransition
- }
- }), ['absolute'])
- }, 'VMenu');
- const VMenu = genericComponent()({
- name: 'VMenu',
- props: makeVMenuProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const isActive = useProxiedModel(props, 'modelValue');
- const {
- scopeId
- } = useScopeId();
- const uid = getUid();
- const id = vue.computed(() => props.id || `v-menu-${uid}`);
- const overlay = vue.ref();
- const parent = vue.inject(VMenuSymbol, null);
- const openChildren = vue.shallowRef(0);
- vue.provide(VMenuSymbol, {
- register() {
- ++openChildren.value;
- },
- unregister() {
- --openChildren.value;
- },
- closeParents() {
- setTimeout(() => {
- if (!openChildren.value) {
- isActive.value = false;
- parent?.closeParents();
- }
- }, 40);
- }
- });
- function onFocusIn(e) {
- const before = e.relatedTarget;
- const after = e.target;
- if (before !== after && overlay.value?.contentEl &&
- // We're the topmost menu
- overlay.value?.globalTop &&
- // It isn't the document or the menu body
- ![document, overlay.value.contentEl].includes(after) &&
- // It isn't inside the menu body
- !overlay.value.contentEl.contains(after)) {
- const focusable = focusableChildren(overlay.value.contentEl);
- focusable[0]?.focus();
- }
- }
- vue.watch(isActive, val => {
- if (val) {
- parent?.register();
- document.addEventListener('focusin', onFocusIn, {
- once: true
- });
- } else {
- parent?.unregister();
- document.removeEventListener('focusin', onFocusIn);
- }
- });
- function onClickOutside() {
- parent?.closeParents();
- }
- function onKeydown(e) {
- if (props.disabled) return;
- if (e.key === 'Tab') {
- const nextElement = getNextElement(focusableChildren(overlay.value?.contentEl, false), e.shiftKey ? 'prev' : 'next', el => el.tabIndex >= 0);
- if (!nextElement) {
- isActive.value = false;
- overlay.value?.activatorEl?.focus();
- }
- }
- }
- function onActivatorKeydown(e) {
- if (props.disabled) return;
- const el = overlay.value?.contentEl;
- if (el && isActive.value) {
- if (e.key === 'ArrowDown') {
- e.preventDefault();
- focusChild(el, 'next');
- } else if (e.key === 'ArrowUp') {
- e.preventDefault();
- focusChild(el, 'prev');
- }
- } else if (['ArrowDown', 'ArrowUp'].includes(e.key)) {
- isActive.value = true;
- e.preventDefault();
- setTimeout(() => setTimeout(() => onActivatorKeydown(e)));
- }
- }
- const activatorProps = vue.computed(() => vue.mergeProps({
- 'aria-haspopup': 'menu',
- 'aria-expanded': String(isActive.value),
- 'aria-owns': id.value,
- onKeydown: onActivatorKeydown
- }, props.activatorProps));
- useRender(() => {
- const [overlayProps] = VOverlay.filterProps(props);
- return vue.createVNode(VOverlay, vue.mergeProps({
- "ref": overlay,
- "class": ['v-menu', props.class],
- "style": props.style
- }, overlayProps, {
- "modelValue": isActive.value,
- "onUpdate:modelValue": $event => isActive.value = $event,
- "absolute": true,
- "activatorProps": activatorProps.value,
- "onClick:outside": onClickOutside,
- "onKeydown": onKeydown
- }, scopeId), {
- activator: slots.activator,
- default: function () {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- return vue.createVNode(VDefaultsProvider, {
- "root": "VMenu"
- }, {
- default: () => [slots.default?.(...args)]
- });
- }
- });
- });
- return forwardRefs({
- id,
- ΨopenChildren: openChildren
- }, overlay);
- }
- });
- // Types
- const makeVCounterProps = propsFactory({
- active: Boolean,
- max: [Number, String],
- value: {
- type: [Number, String],
- default: 0
- },
- ...makeComponentProps(),
- ...makeTransitionProps({
- transition: {
- component: VSlideYTransition
- }
- })
- }, 'VCounter');
- const VCounter = genericComponent()({
- name: 'VCounter',
- functional: true,
- props: makeVCounterProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const counter = vue.computed(() => {
- return props.max ? `${props.value} / ${props.max}` : String(props.value);
- });
- useRender(() => vue.createVNode(MaybeTransition, {
- "transition": props.transition
- }, {
- default: () => [vue.withDirectives(vue.createVNode("div", {
- "class": ['v-counter', props.class],
- "style": props.style
- }, [slots.default ? slots.default({
- counter: counter.value,
- max: props.max,
- value: props.value
- }) : counter.value]), [[vue.vShow, props.active]])]
- }));
- return {};
- }
- });
- const makeVFieldLabelProps = propsFactory({
- floating: Boolean,
- ...makeComponentProps()
- }, 'VFieldLabel');
- const VFieldLabel = genericComponent()({
- name: 'VFieldLabel',
- props: makeVFieldLabelProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode(VLabel, {
- "class": ['v-field-label', {
- 'v-field-label--floating': props.floating
- }, props.class],
- "style": props.style,
- "aria-hidden": props.floating || undefined
- }, slots));
- return {};
- }
- });
- // Types
- const allowedVariants$1 = ['underlined', 'outlined', 'filled', 'solo', 'solo-inverted', 'solo-filled', 'plain'];
- const makeVFieldProps = propsFactory({
- appendInnerIcon: IconValue,
- bgColor: String,
- clearable: Boolean,
- clearIcon: {
- type: IconValue,
- default: '$clear'
- },
- active: Boolean,
- centerAffix: {
- type: Boolean,
- default: undefined
- },
- color: String,
- baseColor: String,
- dirty: Boolean,
- disabled: {
- type: Boolean,
- default: null
- },
- error: Boolean,
- flat: Boolean,
- label: String,
- persistentClear: Boolean,
- prependInnerIcon: IconValue,
- reverse: Boolean,
- singleLine: Boolean,
- variant: {
- type: String,
- default: 'filled',
- validator: v => allowedVariants$1.includes(v)
- },
- 'onClick:clear': EventProp(),
- 'onClick:appendInner': EventProp(),
- 'onClick:prependInner': EventProp(),
- ...makeComponentProps(),
- ...makeLoaderProps(),
- ...makeRoundedProps(),
- ...makeThemeProps()
- }, 'VField');
- const VField = genericComponent()({
- name: 'VField',
- inheritAttrs: false,
- props: {
- id: String,
- ...makeFocusProps(),
- ...makeVFieldProps()
- },
- emits: {
- 'update:focused': focused => true,
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- emit,
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- loaderClasses
- } = useLoader(props);
- const {
- focusClasses,
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const {
- InputIcon
- } = useInputIcon(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- rtlClasses
- } = useRtl();
- const isActive = vue.computed(() => props.dirty || props.active);
- const hasLabel = vue.computed(() => !props.singleLine && !!(props.label || slots.label));
- const uid = getUid();
- const id = vue.computed(() => props.id || `input-${uid}`);
- const messagesId = vue.computed(() => `${id.value}-messages`);
- const labelRef = vue.ref();
- const floatingLabelRef = vue.ref();
- const controlRef = vue.ref();
- const isPlainOrUnderlined = vue.computed(() => ['plain', 'underlined'].includes(props.variant));
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'bgColor'));
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.computed(() => {
- return props.error || props.disabled ? undefined : isActive.value && isFocused.value ? props.color : props.baseColor;
- }));
- vue.watch(isActive, val => {
- if (hasLabel.value) {
- const el = labelRef.value.$el;
- const targetEl = floatingLabelRef.value.$el;
- requestAnimationFrame(() => {
- const rect = nullifyTransforms(el);
- const targetRect = targetEl.getBoundingClientRect();
- const x = targetRect.x - rect.x;
- const y = targetRect.y - rect.y - (rect.height / 2 - targetRect.height / 2);
- const targetWidth = targetRect.width / 0.75;
- const width = Math.abs(targetWidth - rect.width) > 1 ? {
- maxWidth: convertToUnit(targetWidth)
- } : undefined;
- const style = getComputedStyle(el);
- const targetStyle = getComputedStyle(targetEl);
- const duration = parseFloat(style.transitionDuration) * 1000 || 150;
- const scale = parseFloat(targetStyle.getPropertyValue('--v-field-label-scale'));
- const color = targetStyle.getPropertyValue('color');
- el.style.visibility = 'visible';
- targetEl.style.visibility = 'hidden';
- animate(el, {
- transform: `translate(${x}px, ${y}px) scale(${scale})`,
- color,
- ...width
- }, {
- duration,
- easing: standardEasing,
- direction: val ? 'normal' : 'reverse'
- }).finished.then(() => {
- el.style.removeProperty('visibility');
- targetEl.style.removeProperty('visibility');
- });
- });
- }
- }, {
- flush: 'post'
- });
- const slotProps = vue.computed(() => ({
- isActive,
- isFocused,
- controlRef,
- blur,
- focus
- }));
- function onClick(e) {
- if (e.target !== document.activeElement) {
- e.preventDefault();
- }
- }
- useRender(() => {
- const isOutlined = props.variant === 'outlined';
- const hasPrepend = slots['prepend-inner'] || props.prependInnerIcon;
- const hasClear = !!(props.clearable || slots.clear);
- const hasAppend = !!(slots['append-inner'] || props.appendInnerIcon || hasClear);
- const label = slots.label ? slots.label({
- ...slotProps.value,
- label: props.label,
- props: {
- for: id.value
- }
- }) : props.label;
- return vue.createVNode("div", vue.mergeProps({
- "class": ['v-field', {
- 'v-field--active': isActive.value,
- 'v-field--appended': hasAppend,
- 'v-field--center-affix': props.centerAffix ?? !isPlainOrUnderlined.value,
- 'v-field--disabled': props.disabled,
- 'v-field--dirty': props.dirty,
- 'v-field--error': props.error,
- 'v-field--flat': props.flat,
- 'v-field--has-background': !!props.bgColor,
- 'v-field--persistent-clear': props.persistentClear,
- 'v-field--prepended': hasPrepend,
- 'v-field--reverse': props.reverse,
- 'v-field--single-line': props.singleLine,
- 'v-field--no-label': !label,
- [`v-field--variant-${props.variant}`]: true
- }, themeClasses.value, backgroundColorClasses.value, focusClasses.value, loaderClasses.value, roundedClasses.value, rtlClasses.value, props.class],
- "style": [backgroundColorStyles.value, textColorStyles.value, props.style],
- "onClick": onClick
- }, attrs), [vue.createVNode("div", {
- "class": "v-field__overlay"
- }, null), vue.createVNode(LoaderSlot, {
- "name": "v-field",
- "active": !!props.loading,
- "color": props.error ? 'error' : typeof props.loading === 'string' ? props.loading : props.color
- }, {
- default: slots.loader
- }), hasPrepend && vue.createVNode("div", {
- "key": "prepend",
- "class": "v-field__prepend-inner"
- }, [props.prependInnerIcon && vue.createVNode(InputIcon, {
- "key": "prepend-icon",
- "name": "prependInner"
- }, null), slots['prepend-inner']?.(slotProps.value)]), vue.createVNode("div", {
- "class": "v-field__field",
- "data-no-activator": ""
- }, [['filled', 'solo', 'solo-inverted', 'solo-filled'].includes(props.variant) && hasLabel.value && vue.createVNode(VFieldLabel, {
- "key": "floating-label",
- "ref": floatingLabelRef,
- "class": [textColorClasses.value],
- "floating": true,
- "for": id.value
- }, {
- default: () => [label]
- }), vue.createVNode(VFieldLabel, {
- "ref": labelRef,
- "for": id.value
- }, {
- default: () => [label]
- }), slots.default?.({
- ...slotProps.value,
- props: {
- id: id.value,
- class: 'v-field__input',
- 'aria-describedby': messagesId.value
- },
- focus,
- blur
- })]), hasClear && vue.createVNode(VExpandXTransition, {
- "key": "clear"
- }, {
- default: () => [vue.withDirectives(vue.createVNode("div", {
- "class": "v-field__clearable",
- "onMousedown": e => {
- e.preventDefault();
- e.stopPropagation();
- }
- }, [slots.clear ? slots.clear() : vue.createVNode(InputIcon, {
- "name": "clear"
- }, null)]), [[vue.vShow, props.dirty]])]
- }), hasAppend && vue.createVNode("div", {
- "key": "append",
- "class": "v-field__append-inner"
- }, [slots['append-inner']?.(slotProps.value), props.appendInnerIcon && vue.createVNode(InputIcon, {
- "key": "append-icon",
- "name": "appendInner"
- }, null)]), vue.createVNode("div", {
- "class": ['v-field__outline', textColorClasses.value]
- }, [isOutlined && vue.createVNode(vue.Fragment, null, [vue.createVNode("div", {
- "class": "v-field__outline__start"
- }, null), hasLabel.value && vue.createVNode("div", {
- "class": "v-field__outline__notch"
- }, [vue.createVNode(VFieldLabel, {
- "ref": floatingLabelRef,
- "floating": true,
- "for": id.value
- }, {
- default: () => [label]
- })]), vue.createVNode("div", {
- "class": "v-field__outline__end"
- }, null)]), isPlainOrUnderlined.value && hasLabel.value && vue.createVNode(VFieldLabel, {
- "ref": floatingLabelRef,
- "floating": true,
- "for": id.value
- }, {
- default: () => [label]
- })])]);
- });
- return {
- controlRef
- };
- }
- });
- // TODO: this is kinda slow, might be better to implicitly inherit props instead
- function filterFieldProps(attrs) {
- const keys = Object.keys(VField.props).filter(k => !isOn(k) && k !== 'class' && k !== 'style');
- return pick(attrs, keys);
- }
- // Types
- const activeTypes = ['color', 'file', 'time', 'date', 'datetime-local', 'week', 'month'];
- const makeVTextFieldProps = propsFactory({
- autofocus: Boolean,
- counter: [Boolean, Number, String],
- counterValue: Function,
- prefix: String,
- placeholder: String,
- persistentPlaceholder: Boolean,
- persistentCounter: Boolean,
- suffix: String,
- type: {
- type: String,
- default: 'text'
- },
- modelModifiers: Object,
- ...makeVInputProps(),
- ...makeVFieldProps()
- }, 'VTextField');
- const VTextField = genericComponent()({
- name: 'VTextField',
- directives: {
- Intersect
- },
- inheritAttrs: false,
- props: makeVTextFieldProps(),
- emits: {
- 'click:control': e => true,
- 'mousedown:control': e => true,
- 'update:focused': focused => true,
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- emit,
- slots
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const {
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const counterValue = vue.computed(() => {
- return typeof props.counterValue === 'function' ? props.counterValue(model.value) : (model.value ?? '').toString().length;
- });
- const max = vue.computed(() => {
- if (attrs.maxlength) return attrs.maxlength;
- if (!props.counter || typeof props.counter !== 'number' && typeof props.counter !== 'string') return undefined;
- return props.counter;
- });
- const isPlainOrUnderlined = vue.computed(() => ['plain', 'underlined'].includes(props.variant));
- function onIntersect(isIntersecting, entries) {
- if (!props.autofocus || !isIntersecting) return;
- entries[0].target?.focus?.();
- }
- const vInputRef = vue.ref();
- const vFieldRef = vue.ref();
- const inputRef = vue.ref();
- const isActive = vue.computed(() => activeTypes.includes(props.type) || props.persistentPlaceholder || isFocused.value || props.active);
- function onFocus() {
- if (inputRef.value !== document.activeElement) {
- inputRef.value?.focus();
- }
- if (!isFocused.value) focus();
- }
- function onControlMousedown(e) {
- emit('mousedown:control', e);
- if (e.target === inputRef.value) return;
- onFocus();
- e.preventDefault();
- }
- function onControlClick(e) {
- onFocus();
- emit('click:control', e);
- }
- function onClear(e) {
- e.stopPropagation();
- onFocus();
- vue.nextTick(() => {
- model.value = null;
- callEvent(props['onClick:clear'], e);
- });
- }
- function onInput(e) {
- const el = e.target;
- model.value = el.value;
- if (props.modelModifiers?.trim && ['text', 'search', 'password', 'tel', 'url'].includes(props.type)) {
- const caretPosition = [el.selectionStart, el.selectionEnd];
- vue.nextTick(() => {
- el.selectionStart = caretPosition[0];
- el.selectionEnd = caretPosition[1];
- });
- }
- }
- useRender(() => {
- const hasCounter = !!(slots.counter || props.counter || props.counterValue);
- const hasDetails = !!(hasCounter || slots.details);
- const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
- const [{
- modelValue: _,
- ...inputProps
- }] = VInput.filterProps(props);
- const [fieldProps] = filterFieldProps(props);
- return vue.createVNode(VInput, vue.mergeProps({
- "ref": vInputRef,
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "class": ['v-text-field', {
- 'v-text-field--prefixed': props.prefix,
- 'v-text-field--suffixed': props.suffix,
- 'v-text-field--plain-underlined': ['plain', 'underlined'].includes(props.variant)
- }, props.class],
- "style": props.style
- }, rootAttrs, inputProps, {
- "centerAffix": !isPlainOrUnderlined.value,
- "focused": isFocused.value
- }), {
- ...slots,
- default: _ref2 => {
- let {
- id,
- isDisabled,
- isDirty,
- isReadonly,
- isValid
- } = _ref2;
- return vue.createVNode(VField, vue.mergeProps({
- "ref": vFieldRef,
- "onMousedown": onControlMousedown,
- "onClick": onControlClick,
- "onClick:clear": onClear,
- "onClick:prependInner": props['onClick:prependInner'],
- "onClick:appendInner": props['onClick:appendInner'],
- "role": "textbox"
- }, fieldProps, {
- "id": id.value,
- "active": isActive.value || isDirty.value,
- "dirty": isDirty.value || props.dirty,
- "disabled": isDisabled.value,
- "focused": isFocused.value,
- "error": isValid.value === false
- }), {
- ...slots,
- default: _ref3 => {
- let {
- props: {
- class: fieldClass,
- ...slotProps
- }
- } = _ref3;
- const inputNode = vue.withDirectives(vue.createVNode("input", vue.mergeProps({
- "ref": inputRef,
- "value": model.value,
- "onInput": onInput,
- "autofocus": props.autofocus,
- "readonly": isReadonly.value,
- "disabled": isDisabled.value,
- "name": props.name,
- "placeholder": props.placeholder,
- "size": 1,
- "type": props.type,
- "onFocus": onFocus,
- "onBlur": blur
- }, slotProps, inputAttrs), null), [[vue.resolveDirective("intersect"), {
- handler: onIntersect
- }, null, {
- once: true
- }]]);
- return vue.createVNode(vue.Fragment, null, [props.prefix && vue.createVNode("span", {
- "class": "v-text-field__prefix"
- }, [vue.createVNode("span", {
- "class": "v-text-field__prefix__text"
- }, [props.prefix])]), vue.createVNode("div", {
- "class": fieldClass,
- "data-no-activator": ""
- }, [slots.default ? vue.createVNode(vue.Fragment, null, [slots.default(), inputNode]) : vue.cloneVNode(inputNode)]), props.suffix && vue.createVNode("span", {
- "class": "v-text-field__suffix"
- }, [vue.createVNode("span", {
- "class": "v-text-field__suffix__text"
- }, [props.suffix])])]);
- }
- });
- },
- details: hasDetails ? slotProps => vue.createVNode(vue.Fragment, null, [slots.details?.(slotProps), hasCounter && vue.createVNode(vue.Fragment, null, [vue.createVNode("span", null, null), vue.createVNode(VCounter, {
- "active": props.persistentCounter || isFocused.value,
- "value": counterValue.value,
- "max": max.value
- }, slots.counter)])]) : undefined
- });
- });
- return forwardRefs({}, vInputRef, vFieldRef, inputRef);
- }
- });
- // Types
- const makeVVirtualScrollItemProps = propsFactory({
- renderless: Boolean,
- ...makeComponentProps()
- }, 'VVirtualScrollItem');
- const VVirtualScrollItem = genericComponent()({
- name: 'VVirtualScrollItem',
- inheritAttrs: false,
- props: makeVVirtualScrollItemProps(),
- emits: {
- 'update:height': height => true
- },
- setup(props, _ref) {
- let {
- attrs,
- emit,
- slots
- } = _ref;
- const {
- resizeRef,
- contentRect
- } = useResizeObserver(undefined, 'border');
- vue.watch(() => contentRect.value?.height, height => {
- if (height != null) emit('update:height', height);
- });
- useRender(() => props.renderless ? vue.createVNode(vue.Fragment, null, [slots.default?.({
- itemRef: resizeRef
- })]) : vue.createVNode("div", vue.mergeProps({
- "ref": resizeRef,
- "class": ['v-virtual-scroll__item', props.class],
- "style": props.style
- }, attrs), [slots.default?.()]));
- }
- });
- // Composables
- // Types
- const UP = -1;
- const DOWN = 1;
- const makeVirtualProps = propsFactory({
- itemHeight: {
- type: [Number, String],
- default: 48
- }
- }, 'virtual');
- function useVirtual(props, items, offset) {
- const first = vue.shallowRef(0);
- const baseItemHeight = vue.shallowRef(props.itemHeight);
- const itemHeight = vue.computed({
- get: () => parseInt(baseItemHeight.value ?? 0, 10),
- set(val) {
- baseItemHeight.value = val;
- }
- });
- const containerRef = vue.ref();
- const {
- resizeRef,
- contentRect
- } = useResizeObserver();
- vue.watchEffect(() => {
- resizeRef.value = containerRef.value;
- });
- const display = useDisplay();
- const sizeMap = new Map();
- let sizes = Array.from({
- length: items.value.length
- });
- const visibleItems = vue.computed(() => {
- const height = (!contentRect.value || containerRef.value === document.documentElement ? display.height.value : contentRect.value.height) - (offset?.value ?? 0);
- return Math.ceil(height / itemHeight.value * 1.7 + 1);
- });
- function handleItemResize(index, height) {
- itemHeight.value = Math.max(itemHeight.value, height);
- sizes[index] = height;
- sizeMap.set(items.value[index], height);
- }
- function calculateOffset(index) {
- return sizes.slice(0, index).reduce((acc, val) => acc + (val || itemHeight.value), 0);
- }
- function calculateMidPointIndex(scrollTop) {
- const end = items.value.length;
- let middle = 0;
- let middleOffset = 0;
- while (middleOffset < scrollTop && middle < end) {
- middleOffset += sizes[middle++] || itemHeight.value;
- }
- return middle - 1;
- }
- let lastScrollTop = 0;
- function handleScroll() {
- if (!containerRef.value || !contentRect.value) return;
- const height = contentRect.value.height - 56;
- const scrollTop = containerRef.value.scrollTop;
- const direction = scrollTop < lastScrollTop ? UP : DOWN;
- const midPointIndex = calculateMidPointIndex(scrollTop + height / 2);
- const buffer = Math.round(visibleItems.value / 3);
- const firstIndex = midPointIndex - buffer;
- const lastIndex = first.value + buffer * 2 - 1;
- if (direction === UP && midPointIndex <= lastIndex) {
- first.value = clamp(firstIndex, 0, items.value.length);
- } else if (direction === DOWN && midPointIndex >= lastIndex) {
- first.value = clamp(firstIndex, 0, items.value.length - visibleItems.value);
- }
- lastScrollTop = scrollTop;
- }
- function scrollToIndex(index) {
- if (!containerRef.value) return;
- const offset = calculateOffset(index);
- containerRef.value.scrollTop = offset;
- }
- const last = vue.computed(() => Math.min(items.value.length, first.value + visibleItems.value));
- const computedItems = vue.computed(() => {
- return items.value.slice(first.value, last.value).map((item, index) => ({
- raw: item,
- index: index + first.value
- }));
- });
- const paddingTop = vue.computed(() => calculateOffset(first.value));
- const paddingBottom = vue.computed(() => calculateOffset(items.value.length) - calculateOffset(last.value));
- vue.watch(() => items.value.length, () => {
- sizes = createRange(items.value.length).map(() => itemHeight.value);
- sizeMap.forEach((height, item) => {
- const index = items.value.indexOf(item);
- if (index === -1) {
- sizeMap.delete(item);
- } else {
- sizes[index] = height;
- }
- });
- });
- return {
- containerRef,
- computedItems,
- itemHeight,
- paddingTop,
- paddingBottom,
- scrollToIndex,
- handleScroll,
- handleItemResize
- };
- }
- // Types
- const makeVVirtualScrollProps = propsFactory({
- items: {
- type: Array,
- default: () => []
- },
- renderless: Boolean,
- ...makeVirtualProps(),
- ...makeComponentProps(),
- ...makeDimensionProps()
- }, 'VVirtualScroll');
- const VVirtualScroll = genericComponent()({
- name: 'VVirtualScroll',
- props: makeVVirtualScrollProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const vm = getCurrentInstance('VVirtualScroll');
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- containerRef,
- handleScroll,
- handleItemResize,
- scrollToIndex,
- paddingTop,
- paddingBottom,
- computedItems
- } = useVirtual(props, vue.toRef(props, 'items'));
- useToggleScope(() => props.renderless, () => {
- vue.onMounted(() => {
- containerRef.value = getScrollParent(vm.vnode.el, true);
- containerRef.value?.addEventListener('scroll', handleScroll);
- });
- vue.onScopeDispose(() => {
- containerRef.value?.removeEventListener('scroll', handleScroll);
- });
- });
- useRender(() => {
- const children = computedItems.value.map(item => vue.createVNode(VVirtualScrollItem, {
- "key": item.index,
- "renderless": props.renderless,
- "onUpdate:height": height => handleItemResize(item.index, height)
- }, {
- default: slotProps => slots.default?.({
- item: item.raw,
- index: item.index,
- ...slotProps
- })
- }));
- return props.renderless ? vue.createVNode(vue.Fragment, null, [vue.createVNode("div", {
- "class": "v-virtual-scroll__spacer",
- "style": {
- paddingTop: convertToUnit(paddingTop.value)
- }
- }, null), children, vue.createVNode("div", {
- "class": "v-virtual-scroll__spacer",
- "style": {
- paddingBottom: convertToUnit(paddingBottom.value)
- }
- }, null)]) : vue.createVNode("div", {
- "ref": containerRef,
- "class": ['v-virtual-scroll', props.class],
- "onScroll": handleScroll,
- "style": [dimensionStyles.value, props.style]
- }, [vue.createVNode("div", {
- "class": "v-virtual-scroll__container",
- "style": {
- paddingTop: convertToUnit(paddingTop.value),
- paddingBottom: convertToUnit(paddingBottom.value)
- }
- }, [children])]);
- });
- return {
- scrollToIndex
- };
- }
- });
- // Utilities
- // Types
- function useScrolling(listRef, textFieldRef) {
- const isScrolling = vue.shallowRef(false);
- let scrollTimeout;
- function onListScroll(e) {
- cancelAnimationFrame(scrollTimeout);
- isScrolling.value = true;
- scrollTimeout = requestAnimationFrame(() => {
- scrollTimeout = requestAnimationFrame(() => {
- isScrolling.value = false;
- });
- });
- }
- async function finishScrolling() {
- await new Promise(resolve => requestAnimationFrame(resolve));
- await new Promise(resolve => requestAnimationFrame(resolve));
- await new Promise(resolve => requestAnimationFrame(resolve));
- await new Promise(resolve => {
- if (isScrolling.value) {
- const stop = vue.watch(isScrolling, () => {
- stop();
- resolve();
- });
- } else resolve();
- });
- }
- async function onListKeydown(e) {
- if (e.key === 'Tab') {
- textFieldRef.value?.focus();
- }
- if (!['PageDown', 'PageUp', 'Home', 'End'].includes(e.key)) return;
- const el = listRef.value?.$el;
- if (!el) return;
- if (e.key === 'Home' || e.key === 'End') {
- el.scrollTo({
- top: e.key === 'Home' ? 0 : el.scrollHeight,
- behavior: 'smooth'
- });
- }
- await finishScrolling();
- const children = el.querySelectorAll(':scope > :not(.v-virtual-scroll__spacer)');
- if (e.key === 'PageDown' || e.key === 'Home') {
- const top = el.getBoundingClientRect().top;
- for (const child of children) {
- if (child.getBoundingClientRect().top >= top) {
- child.focus();
- break;
- }
- }
- } else {
- const bottom = el.getBoundingClientRect().bottom;
- for (const child of [...children].reverse()) {
- if (child.getBoundingClientRect().bottom <= bottom) {
- child.focus();
- break;
- }
- }
- }
- }
- return {
- onListScroll,
- onListKeydown
- };
- }
- // Types
- const makeSelectProps = propsFactory({
- chips: Boolean,
- closableChips: Boolean,
- eager: Boolean,
- hideNoData: Boolean,
- hideSelected: Boolean,
- menu: Boolean,
- menuIcon: {
- type: IconValue,
- default: '$dropdown'
- },
- menuProps: {
- type: Object
- },
- multiple: Boolean,
- noDataText: {
- type: String,
- default: '$vuetify.noDataText'
- },
- openOnClear: Boolean,
- valueComparator: {
- type: Function,
- default: deepEqual
- },
- itemColor: String,
- ...makeItemsProps({
- itemChildren: false
- })
- }, 'Select');
- const makeVSelectProps = propsFactory({
- ...makeSelectProps(),
- ...omit(makeVTextFieldProps({
- modelValue: null
- }), ['validationValue', 'dirty', 'appendInnerIcon']),
- ...makeTransitionProps({
- transition: {
- component: VDialogTransition
- }
- })
- }, 'VSelect');
- const VSelect = genericComponent()({
- name: 'VSelect',
- props: makeVSelectProps(),
- emits: {
- 'update:focused': focused => true,
- 'update:modelValue': val => true,
- 'update:menu': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const vTextFieldRef = vue.ref();
- const vMenuRef = vue.ref();
- const _menu = useProxiedModel(props, 'menu');
- const menu = vue.computed({
- get: () => _menu.value,
- set: v => {
- if (_menu.value && !v && vMenuRef.value?.ΨopenChildren) return;
- _menu.value = v;
- }
- });
- const {
- items,
- transformIn,
- transformOut
- } = useItems(props);
- const model = useProxiedModel(props, 'modelValue', [], v => transformIn(v === null ? [null] : wrapInArray(v)), v => {
- const transformed = transformOut(v);
- return props.multiple ? transformed : transformed[0] ?? null;
- });
- const form = useForm();
- const selections = vue.computed(() => {
- return model.value.map(v => {
- return items.value.find(item => {
- const itemRawValue = getPropertyFromItem(item.raw, props.itemValue);
- const modelRawValue = getPropertyFromItem(v.raw, props.itemValue);
- if (itemRawValue === undefined || modelRawValue === undefined) return false;
- return props.returnObject ? props.valueComparator(itemRawValue, modelRawValue) : props.valueComparator(item.value, v.value);
- }) || v;
- });
- });
- const selected = vue.computed(() => selections.value.map(selection => selection.props.value));
- const isFocused = vue.shallowRef(false);
- let keyboardLookupPrefix = '';
- let keyboardLookupLastTime;
- const displayItems = vue.computed(() => {
- if (props.hideSelected) {
- return items.value.filter(item => !selections.value.some(s => s === item));
- }
- return items.value;
- });
- const menuDisabled = vue.computed(() => props.hideNoData && !items.value.length || props.readonly || form?.isReadonly.value);
- const listRef = vue.ref();
- const {
- onListScroll,
- onListKeydown
- } = useScrolling(listRef, vTextFieldRef);
- function onClear(e) {
- if (props.openOnClear) {
- menu.value = true;
- }
- }
- function onMousedownControl() {
- if (menuDisabled.value) return;
- menu.value = !menu.value;
- }
- function onKeydown(e) {
- if (!e.key || props.readonly || form?.isReadonly.value) return;
- if (['Enter', ' ', 'ArrowDown', 'ArrowUp', 'Home', 'End'].includes(e.key)) {
- e.preventDefault();
- }
- if (['Enter', 'ArrowDown', ' '].includes(e.key)) {
- menu.value = true;
- }
- if (['Escape', 'Tab'].includes(e.key)) {
- menu.value = false;
- }
- if (e.key === 'Home') {
- listRef.value?.focus('first');
- } else if (e.key === 'End') {
- listRef.value?.focus('last');
- }
- // html select hotkeys
- const KEYBOARD_LOOKUP_THRESHOLD = 1000; // milliseconds
- function checkPrintable(e) {
- const isPrintableChar = e.key.length === 1;
- const noModifier = !e.ctrlKey && !e.metaKey && !e.altKey;
- return isPrintableChar && noModifier;
- }
- if (props.multiple || !checkPrintable(e)) return;
- const now = performance.now();
- if (now - keyboardLookupLastTime > KEYBOARD_LOOKUP_THRESHOLD) {
- keyboardLookupPrefix = '';
- }
- keyboardLookupPrefix += e.key.toLowerCase();
- keyboardLookupLastTime = now;
- const item = items.value.find(item => item.title.toLowerCase().startsWith(keyboardLookupPrefix));
- if (item !== undefined) {
- model.value = [item];
- }
- }
- function select(item) {
- if (props.multiple) {
- const index = selected.value.findIndex(selection => props.valueComparator(selection, item.value));
- if (index === -1) {
- model.value = [...model.value, item];
- } else {
- const value = [...model.value];
- value.splice(index, 1);
- model.value = value;
- }
- } else {
- model.value = [item];
- menu.value = false;
- }
- }
- function onBlur(e) {
- if (!listRef.value?.$el.contains(e.relatedTarget)) {
- menu.value = false;
- }
- }
- function onAfterLeave() {
- if (isFocused.value) {
- vTextFieldRef.value?.focus();
- }
- }
- function onFocusin(e) {
- isFocused.value = true;
- }
- function onModelUpdate(v) {
- if (v == null) model.value = [];else if (matchesSelector(vTextFieldRef.value, ':autofill') || matchesSelector(vTextFieldRef.value, ':-webkit-autofill')) {
- const item = items.value.find(item => item.title === v);
- if (item) {
- select(item);
- }
- } else if (vTextFieldRef.value) {
- vTextFieldRef.value.value = '';
- }
- }
- useRender(() => {
- const hasChips = !!(props.chips || slots.chip);
- const hasList = !!(!props.hideNoData || displayItems.value.length || slots['prepend-item'] || slots['append-item'] || slots['no-data']);
- const isDirty = model.value.length > 0;
- const [textFieldProps] = VTextField.filterProps(props);
- const placeholder = isDirty || !isFocused.value && props.label && !props.persistentPlaceholder ? undefined : props.placeholder;
- return vue.createVNode(VTextField, vue.mergeProps({
- "ref": vTextFieldRef
- }, textFieldProps, {
- "modelValue": model.value.map(v => v.props.value).join(', '),
- "onUpdate:modelValue": onModelUpdate,
- "focused": isFocused.value,
- "onUpdate:focused": $event => isFocused.value = $event,
- "validationValue": model.externalValue,
- "dirty": isDirty,
- "class": ['v-select', {
- 'v-select--active-menu': menu.value,
- 'v-select--chips': !!props.chips,
- [`v-select--${props.multiple ? 'multiple' : 'single'}`]: true,
- 'v-select--selected': model.value.length,
- 'v-select--selection-slot': !!slots.selection
- }, props.class],
- "style": props.style,
- "inputmode": "none",
- "placeholder": placeholder,
- "onClick:clear": onClear,
- "onMousedown:control": onMousedownControl,
- "onBlur": onBlur,
- "onKeydown": onKeydown
- }), {
- ...slots,
- default: () => vue.createVNode(vue.Fragment, null, [vue.createVNode(VMenu, vue.mergeProps({
- "ref": vMenuRef,
- "modelValue": menu.value,
- "onUpdate:modelValue": $event => menu.value = $event,
- "activator": "parent",
- "contentClass": "v-select__content",
- "disabled": menuDisabled.value,
- "eager": props.eager,
- "maxHeight": 310,
- "openOnClick": false,
- "closeOnContentClick": false,
- "transition": props.transition,
- "onAfterLeave": onAfterLeave
- }, props.menuProps), {
- default: () => [hasList && vue.createVNode(VList, {
- "ref": listRef,
- "selected": selected.value,
- "selectStrategy": props.multiple ? 'independent' : 'single-independent',
- "onMousedown": e => e.preventDefault(),
- "onKeydown": onListKeydown,
- "onFocusin": onFocusin,
- "onScrollPassive": onListScroll,
- "tabindex": "-1",
- "color": props.itemColor ?? props.color
- }, {
- default: () => [slots['prepend-item']?.(), !displayItems.value.length && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
- "title": t(props.noDataText)
- }, null)), vue.createVNode(VVirtualScroll, {
- "renderless": true,
- "items": displayItems.value
- }, {
- default: _ref2 => {
- let {
- item,
- index,
- itemRef
- } = _ref2;
- const itemProps = vue.mergeProps(item.props, {
- ref: itemRef,
- key: index,
- onClick: () => select(item)
- });
- return slots.item?.({
- item,
- index,
- props: itemProps
- }) ?? vue.createVNode(VListItem, itemProps, {
- prepend: _ref3 => {
- let {
- isSelected
- } = _ref3;
- return vue.createVNode(vue.Fragment, null, [props.multiple && !props.hideSelected ? vue.createVNode(VCheckboxBtn, {
- "key": item.value,
- "modelValue": isSelected,
- "ripple": false,
- "tabindex": "-1"
- }, null) : undefined, item.props.prependIcon && vue.createVNode(VIcon, {
- "icon": item.props.prependIcon
- }, null)]);
- }
- });
- }
- }), slots['append-item']?.()]
- })]
- }), selections.value.map((item, index) => {
- function onChipClose(e) {
- e.stopPropagation();
- e.preventDefault();
- select(item);
- }
- const slotProps = {
- 'onClick:close': onChipClose,
- onMousedown(e) {
- e.preventDefault();
- e.stopPropagation();
- },
- modelValue: true,
- 'onUpdate:modelValue': undefined
- };
- return vue.createVNode("div", {
- "key": item.value,
- "class": "v-select__selection"
- }, [hasChips ? !slots.chip ? vue.createVNode(VChip, vue.mergeProps({
- "key": "chip",
- "closable": props.closableChips,
- "size": "small",
- "text": item.title
- }, slotProps), null) : vue.createVNode(VDefaultsProvider, {
- "key": "chip-defaults",
- "defaults": {
- VChip: {
- closable: props.closableChips,
- size: 'small',
- text: item.title
- }
- }
- }, {
- default: () => [slots.chip?.({
- item,
- index,
- props: slotProps
- })]
- }) : slots.selection?.({
- item,
- index
- }) ?? vue.createVNode("span", {
- "class": "v-select__selection-text"
- }, [item.title, props.multiple && index < selections.value.length - 1 && vue.createVNode("span", {
- "class": "v-select__selection-comma"
- }, [vue.createTextVNode(",")])])]);
- })]),
- 'append-inner': function () {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- return vue.createVNode(vue.Fragment, null, [slots['append-inner']?.(...args), props.menuIcon ? vue.createVNode(VIcon, {
- "class": "v-select__menu-icon",
- "icon": props.menuIcon
- }, null) : undefined]);
- }
- });
- });
- return forwardRefs({
- isFocused,
- menu,
- select
- }, vTextFieldRef);
- }
- });
- /* eslint-disable max-statements */
- /* eslint-disable no-labels */
- // Types
- // Composables
- const defaultFilter = (value, query, item) => {
- if (value == null || query == null) return -1;
- return value.toString().toLocaleLowerCase().indexOf(query.toString().toLocaleLowerCase());
- };
- const makeFilterProps = propsFactory({
- customFilter: Function,
- customKeyFilter: Object,
- filterKeys: [Array, String],
- filterMode: {
- type: String,
- default: 'intersection'
- },
- noFilter: Boolean
- }, 'filter');
- function filterItems(items, query, options) {
- const array = [];
- // always ensure we fall back to a functioning filter
- const filter = options?.default ?? defaultFilter;
- const keys = options?.filterKeys ? wrapInArray(options.filterKeys) : false;
- const customFiltersLength = Object.keys(options?.customKeyFilter ?? {}).length;
- if (!items?.length) return array;
- loop: for (let i = 0; i < items.length; i++) {
- const item = items[i];
- const customMatches = {};
- const defaultMatches = {};
- let match = -1;
- if (query && !options?.noFilter) {
- if (typeof item === 'object') {
- const filterKeys = keys || Object.keys(item);
- for (const key of filterKeys) {
- const value = getPropertyFromItem(item, key, item);
- const keyFilter = options?.customKeyFilter?.[key];
- match = keyFilter ? keyFilter(value, query, item) : filter(value, query, item);
- if (match !== -1 && match !== false) {
- if (keyFilter) customMatches[key] = match;else defaultMatches[key] = match;
- } else if (options?.filterMode === 'every') {
- continue loop;
- }
- }
- } else {
- match = filter(item, query, item);
- if (match !== -1 && match !== false) {
- defaultMatches.title = match;
- }
- }
- const defaultMatchesLength = Object.keys(defaultMatches).length;
- const customMatchesLength = Object.keys(customMatches).length;
- if (!defaultMatchesLength && !customMatchesLength) continue;
- if (options?.filterMode === 'union' && customMatchesLength !== customFiltersLength && !defaultMatchesLength) continue;
- if (options?.filterMode === 'intersection' && (customMatchesLength !== customFiltersLength || !defaultMatchesLength)) continue;
- }
- array.push({
- index: i,
- matches: {
- ...defaultMatches,
- ...customMatches
- }
- });
- }
- return array;
- }
- function useFilter(props, items, query, options) {
- const filteredItems = vue.ref([]);
- const filteredMatches = vue.ref(new Map());
- const transformedItems = vue.computed(() => options?.transform ? vue.unref(items).map(options?.transform) : vue.unref(items));
- vue.watchEffect(() => {
- const _query = typeof query === 'function' ? query() : vue.unref(query);
- const strQuery = typeof _query !== 'string' && typeof _query !== 'number' ? '' : String(_query);
- const results = filterItems(transformedItems.value, strQuery, {
- customKeyFilter: props.customKeyFilter,
- default: props.customFilter,
- filterKeys: props.filterKeys,
- filterMode: props.filterMode,
- noFilter: props.noFilter
- });
- const originalItems = vue.unref(items);
- const _filteredItems = [];
- const _filteredMatches = new Map();
- results.forEach(_ref => {
- let {
- index,
- matches
- } = _ref;
- const item = originalItems[index];
- _filteredItems.push(item);
- _filteredMatches.set(item.value, matches);
- });
- filteredItems.value = _filteredItems;
- filteredMatches.value = _filteredMatches;
- });
- function getMatches(item) {
- return filteredMatches.value.get(item.value);
- }
- return {
- filteredItems,
- filteredMatches,
- getMatches
- };
- }
- // Types
- function highlightResult$1(text, matches, length) {
- if (matches == null) return text;
- if (Array.isArray(matches)) throw new Error('Multiple matches is not implemented');
- return typeof matches === 'number' && ~matches ? vue.createVNode(vue.Fragment, null, [vue.createVNode("span", {
- "class": "v-autocomplete__unmask"
- }, [text.substr(0, matches)]), vue.createVNode("span", {
- "class": "v-autocomplete__mask"
- }, [text.substr(matches, length)]), vue.createVNode("span", {
- "class": "v-autocomplete__unmask"
- }, [text.substr(matches + length)])]) : text;
- }
- const makeVAutocompleteProps = propsFactory({
- autoSelectFirst: {
- type: [Boolean, String]
- },
- search: String,
- ...makeFilterProps({
- filterKeys: ['title']
- }),
- ...makeSelectProps(),
- ...omit(makeVTextFieldProps({
- modelValue: null
- }), ['validationValue', 'dirty', 'appendInnerIcon']),
- ...makeTransitionProps({
- transition: false
- })
- }, 'VAutocomplete');
- const VAutocomplete = genericComponent()({
- name: 'VAutocomplete',
- props: makeVAutocompleteProps(),
- emits: {
- 'update:focused': focused => true,
- 'update:search': val => true,
- 'update:modelValue': val => true,
- 'update:menu': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const vTextFieldRef = vue.ref();
- const isFocused = vue.shallowRef(false);
- const isPristine = vue.shallowRef(true);
- const listHasFocus = vue.shallowRef(false);
- const vMenuRef = vue.ref();
- const _menu = useProxiedModel(props, 'menu');
- const menu = vue.computed({
- get: () => _menu.value,
- set: v => {
- if (_menu.value && !v && vMenuRef.value?.ΨopenChildren) return;
- _menu.value = v;
- }
- });
- const selectionIndex = vue.shallowRef(-1);
- const color = vue.computed(() => vTextFieldRef.value?.color);
- const {
- items,
- transformIn,
- transformOut
- } = useItems(props);
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(color);
- const search = useProxiedModel(props, 'search', '');
- const model = useProxiedModel(props, 'modelValue', [], v => transformIn(v === null ? [null] : wrapInArray(v)), v => {
- const transformed = transformOut(v);
- return props.multiple ? transformed : transformed[0] ?? null;
- });
- const form = useForm();
- const {
- filteredItems,
- getMatches
- } = useFilter(props, items, () => isPristine.value ? '' : search.value);
- const selections = vue.computed(() => {
- return model.value.map(v => {
- return items.value.find(item => {
- const itemRawValue = getPropertyFromItem(item.raw, props.itemValue);
- const modelRawValue = getPropertyFromItem(v.raw, props.itemValue);
- if (itemRawValue === undefined || modelRawValue === undefined) return false;
- return props.returnObject ? props.valueComparator(itemRawValue, modelRawValue) : props.valueComparator(item.value, v.value);
- }) || v;
- });
- });
- const displayItems = vue.computed(() => {
- if (props.hideSelected) {
- return filteredItems.value.filter(filteredItem => !selections.value.some(s => s.value === filteredItem.value));
- }
- return filteredItems.value;
- });
- const selected = vue.computed(() => selections.value.map(selection => selection.props.value));
- const selection = vue.computed(() => selections.value[selectionIndex.value]);
- const highlightFirst = vue.computed(() => {
- const selectFirst = props.autoSelectFirst === true || props.autoSelectFirst === 'exact' && search.value === displayItems.value[0]?.title;
- return selectFirst && displayItems.value.length > 0 && !isPristine.value && !listHasFocus.value;
- });
- const menuDisabled = vue.computed(() => props.hideNoData && !items.value.length || props.readonly || form?.isReadonly.value);
- const listRef = vue.ref();
- const {
- onListScroll,
- onListKeydown
- } = useScrolling(listRef, vTextFieldRef);
- function onClear(e) {
- if (props.openOnClear) {
- menu.value = true;
- }
- search.value = '';
- }
- function onMousedownControl() {
- if (menuDisabled.value) return;
- menu.value = true;
- }
- function onMousedownMenuIcon(e) {
- if (menuDisabled.value) return;
- if (isFocused.value) {
- e.preventDefault();
- e.stopPropagation();
- }
- menu.value = !menu.value;
- }
- function onKeydown(e) {
- if (props.readonly || form?.isReadonly.value) return;
- const selectionStart = vTextFieldRef.value.selectionStart;
- const length = selected.value.length;
- if (selectionIndex.value > -1 || ['Enter', 'ArrowDown', 'ArrowUp'].includes(e.key)) {
- e.preventDefault();
- }
- if (['Enter', 'ArrowDown'].includes(e.key)) {
- menu.value = true;
- }
- if (['Escape'].includes(e.key)) {
- menu.value = false;
- }
- if (highlightFirst.value && ['Enter', 'Tab'].includes(e.key)) {
- select(filteredItems.value[0]);
- }
- if (e.key === 'ArrowDown' && highlightFirst.value) {
- listRef.value?.focus('next');
- }
- if (!props.multiple) return;
- if (['Backspace', 'Delete'].includes(e.key)) {
- if (selectionIndex.value < 0) {
- if (e.key === 'Backspace' && !search.value) {
- selectionIndex.value = length - 1;
- }
- return;
- }
- const originalSelectionIndex = selectionIndex.value;
- if (selection.value) select(selection.value);
- selectionIndex.value = originalSelectionIndex >= length - 1 ? length - 2 : originalSelectionIndex;
- }
- if (e.key === 'ArrowLeft') {
- if (selectionIndex.value < 0 && selectionStart > 0) return;
- const prev = selectionIndex.value > -1 ? selectionIndex.value - 1 : length - 1;
- if (selections.value[prev]) {
- selectionIndex.value = prev;
- } else {
- selectionIndex.value = -1;
- vTextFieldRef.value.setSelectionRange(search.value?.length, search.value?.length);
- }
- }
- if (e.key === 'ArrowRight') {
- if (selectionIndex.value < 0) return;
- const next = selectionIndex.value + 1;
- if (selections.value[next]) {
- selectionIndex.value = next;
- } else {
- selectionIndex.value = -1;
- vTextFieldRef.value.setSelectionRange(0, 0);
- }
- }
- }
- function onInput(e) {
- search.value = e.target.value;
- }
- function onChange(e) {
- if (matchesSelector(vTextFieldRef.value, ':autofill') || matchesSelector(vTextFieldRef.value, ':-webkit-autofill')) {
- const item = items.value.find(item => item.title === e.target.value);
- if (item) {
- select(item);
- }
- }
- }
- function onAfterLeave() {
- if (isFocused.value) {
- isPristine.value = true;
- vTextFieldRef.value?.focus();
- }
- }
- function onFocusin(e) {
- isFocused.value = true;
- setTimeout(() => {
- listHasFocus.value = true;
- });
- }
- function onFocusout(e) {
- listHasFocus.value = false;
- }
- function onUpdateModelValue(v) {
- if (v == null || v === '' && !props.multiple) model.value = [];
- }
- const isSelecting = vue.shallowRef(false);
- function select(item) {
- if (props.multiple) {
- const index = selected.value.findIndex(selection => props.valueComparator(selection, item.value));
- if (index === -1) {
- model.value = [...model.value, item];
- } else {
- const value = [...model.value];
- value.splice(index, 1);
- model.value = value;
- }
- } else {
- model.value = [item];
- isSelecting.value = true;
- search.value = item.title;
- menu.value = false;
- isPristine.value = true;
- vue.nextTick(() => isSelecting.value = false);
- }
- }
- vue.watch(isFocused, (val, oldVal) => {
- if (val === oldVal) return;
- if (val) {
- isSelecting.value = true;
- search.value = props.multiple ? '' : String(selections.value.at(-1)?.props.title ?? '');
- isPristine.value = true;
- vue.nextTick(() => isSelecting.value = false);
- } else {
- if (!props.multiple && !search.value) model.value = [];else if (highlightFirst.value && !listHasFocus.value && !selections.value.some(_ref2 => {
- let {
- value
- } = _ref2;
- return value === displayItems.value[0].value;
- })) {
- select(displayItems.value[0]);
- }
- menu.value = false;
- search.value = '';
- selectionIndex.value = -1;
- }
- });
- vue.watch(search, val => {
- if (!isFocused.value || isSelecting.value) return;
- if (val) menu.value = true;
- isPristine.value = !val;
- });
- useRender(() => {
- const hasChips = !!(props.chips || slots.chip);
- const hasList = !!(!props.hideNoData || displayItems.value.length || slots['prepend-item'] || slots['append-item'] || slots['no-data']);
- const isDirty = model.value.length > 0;
- const [textFieldProps] = VTextField.filterProps(props);
- return vue.createVNode(VTextField, vue.mergeProps({
- "ref": vTextFieldRef
- }, textFieldProps, {
- "modelValue": search.value,
- "onUpdate:modelValue": onUpdateModelValue,
- "focused": isFocused.value,
- "onUpdate:focused": $event => isFocused.value = $event,
- "validationValue": model.externalValue,
- "dirty": isDirty,
- "onInput": onInput,
- "onChange": onChange,
- "class": ['v-autocomplete', `v-autocomplete--${props.multiple ? 'multiple' : 'single'}`, {
- 'v-autocomplete--active-menu': menu.value,
- 'v-autocomplete--chips': !!props.chips,
- 'v-autocomplete--selection-slot': !!slots.selection,
- 'v-autocomplete--selecting-index': selectionIndex.value > -1
- }, props.class],
- "style": props.style,
- "readonly": props.readonly,
- "placeholder": isDirty ? undefined : props.placeholder,
- "onClick:clear": onClear,
- "onMousedown:control": onMousedownControl,
- "onKeydown": onKeydown
- }), {
- ...slots,
- default: () => vue.createVNode(vue.Fragment, null, [vue.createVNode(VMenu, vue.mergeProps({
- "ref": vMenuRef,
- "modelValue": menu.value,
- "onUpdate:modelValue": $event => menu.value = $event,
- "activator": "parent",
- "contentClass": "v-autocomplete__content",
- "disabled": menuDisabled.value,
- "eager": props.eager,
- "maxHeight": 310,
- "openOnClick": false,
- "closeOnContentClick": false,
- "transition": props.transition,
- "onAfterLeave": onAfterLeave
- }, props.menuProps), {
- default: () => [hasList && vue.createVNode(VList, {
- "ref": listRef,
- "selected": selected.value,
- "selectStrategy": props.multiple ? 'independent' : 'single-independent',
- "onMousedown": e => e.preventDefault(),
- "onKeydown": onListKeydown,
- "onFocusin": onFocusin,
- "onFocusout": onFocusout,
- "onScrollPassive": onListScroll,
- "tabindex": "-1",
- "color": props.itemColor ?? props.color
- }, {
- default: () => [slots['prepend-item']?.(), !displayItems.value.length && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
- "title": t(props.noDataText)
- }, null)), vue.createVNode(VVirtualScroll, {
- "renderless": true,
- "items": displayItems.value
- }, {
- default: _ref3 => {
- let {
- item,
- index,
- itemRef
- } = _ref3;
- const itemProps = vue.mergeProps(item.props, {
- ref: itemRef,
- key: index,
- active: highlightFirst.value && index === 0 ? true : undefined,
- onClick: () => select(item)
- });
- return slots.item?.({
- item,
- index,
- props: itemProps
- }) ?? vue.createVNode(VListItem, itemProps, {
- prepend: _ref4 => {
- let {
- isSelected
- } = _ref4;
- return vue.createVNode(vue.Fragment, null, [props.multiple && !props.hideSelected ? vue.createVNode(VCheckboxBtn, {
- "key": item.value,
- "modelValue": isSelected,
- "ripple": false,
- "tabindex": "-1"
- }, null) : undefined, item.props.prependIcon && vue.createVNode(VIcon, {
- "icon": item.props.prependIcon
- }, null)]);
- },
- title: () => {
- return isPristine.value ? item.title : highlightResult$1(item.title, getMatches(item)?.title, search.value?.length ?? 0);
- }
- });
- }
- }), slots['append-item']?.()]
- })]
- }), selections.value.map((item, index) => {
- function onChipClose(e) {
- e.stopPropagation();
- e.preventDefault();
- select(item);
- }
- const slotProps = {
- 'onClick:close': onChipClose,
- onMousedown(e) {
- e.preventDefault();
- e.stopPropagation();
- },
- modelValue: true,
- 'onUpdate:modelValue': undefined
- };
- return vue.createVNode("div", {
- "key": item.value,
- "class": ['v-autocomplete__selection', index === selectionIndex.value && ['v-autocomplete__selection--selected', textColorClasses.value]],
- "style": index === selectionIndex.value ? textColorStyles.value : {}
- }, [hasChips ? !slots.chip ? vue.createVNode(VChip, vue.mergeProps({
- "key": "chip",
- "closable": props.closableChips,
- "size": "small",
- "text": item.title
- }, slotProps), null) : vue.createVNode(VDefaultsProvider, {
- "key": "chip-defaults",
- "defaults": {
- VChip: {
- closable: props.closableChips,
- size: 'small',
- text: item.title
- }
- }
- }, {
- default: () => [slots.chip?.({
- item,
- index,
- props: slotProps
- })]
- }) : slots.selection?.({
- item,
- index
- }) ?? vue.createVNode("span", {
- "class": "v-autocomplete__selection-text"
- }, [item.title, props.multiple && index < selections.value.length - 1 && vue.createVNode("span", {
- "class": "v-autocomplete__selection-comma"
- }, [vue.createTextVNode(",")])])]);
- })]),
- 'append-inner': function () {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- return vue.createVNode(vue.Fragment, null, [slots['append-inner']?.(...args), props.menuIcon ? vue.createVNode(VIcon, {
- "class": "v-autocomplete__menu-icon",
- "icon": props.menuIcon,
- "onMousedown": onMousedownMenuIcon,
- "onClick": noop
- }, null) : undefined]);
- }
- });
- });
- return forwardRefs({
- isFocused,
- isPristine,
- menu,
- search,
- filteredItems,
- select
- }, vTextFieldRef);
- }
- });
- const makeVBadgeProps = propsFactory({
- bordered: Boolean,
- color: String,
- content: [Number, String],
- dot: Boolean,
- floating: Boolean,
- icon: IconValue,
- inline: Boolean,
- label: {
- type: String,
- default: '$vuetify.badge'
- },
- max: [Number, String],
- modelValue: {
- type: Boolean,
- default: true
- },
- offsetX: [Number, String],
- offsetY: [Number, String],
- textColor: String,
- ...makeComponentProps(),
- ...makeLocationProps({
- location: 'top end'
- }),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeThemeProps(),
- ...makeTransitionProps({
- transition: 'scale-rotate-transition'
- })
- }, 'VBadge');
- const VBadge = genericComponent()({
- name: 'VBadge',
- inheritAttrs: false,
- props: makeVBadgeProps(),
- setup(props, ctx) {
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- const {
- roundedClasses
- } = useRounded(props);
- const {
- t
- } = useLocale();
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.toRef(props, 'textColor'));
- const {
- themeClasses
- } = useTheme();
- const {
- locationStyles
- } = useLocation(props, true, side => {
- const base = props.floating ? props.dot ? 2 : 4 : props.dot ? 8 : 12;
- return base + (['top', 'bottom'].includes(side) ? +(props.offsetY ?? 0) : ['left', 'right'].includes(side) ? +(props.offsetX ?? 0) : 0);
- });
- useRender(() => {
- const value = Number(props.content);
- const content = !props.max || isNaN(value) ? props.content : value <= +props.max ? value : `${props.max}+`;
- const [badgeAttrs, attrs] = pick(ctx.attrs, ['aria-atomic', 'aria-label', 'aria-live', 'role', 'title']);
- return vue.createVNode(props.tag, vue.mergeProps({
- "class": ['v-badge', {
- 'v-badge--bordered': props.bordered,
- 'v-badge--dot': props.dot,
- 'v-badge--floating': props.floating,
- 'v-badge--inline': props.inline
- }, props.class]
- }, attrs, {
- "style": props.style
- }), {
- default: () => [vue.createVNode("div", {
- "class": "v-badge__wrapper"
- }, [ctx.slots.default?.(), vue.createVNode(MaybeTransition, {
- "transition": props.transition
- }, {
- default: () => [vue.withDirectives(vue.createVNode("span", vue.mergeProps({
- "class": ['v-badge__badge', themeClasses.value, backgroundColorClasses.value, roundedClasses.value, textColorClasses.value],
- "style": [backgroundColorStyles.value, textColorStyles.value, props.inline ? {} : locationStyles.value],
- "aria-atomic": "true",
- "aria-label": t(props.label, value),
- "aria-live": "polite",
- "role": "status"
- }, badgeAttrs), [props.dot ? undefined : ctx.slots.badge ? ctx.slots.badge?.() : props.icon ? vue.createVNode(VIcon, {
- "icon": props.icon
- }, null) : content]), [[vue.vShow, props.modelValue]])]
- })])]
- });
- });
- return {};
- }
- });
- const makeVBannerActionsProps = propsFactory({
- color: String,
- density: String,
- ...makeComponentProps()
- }, 'VBannerActions');
- const VBannerActions = genericComponent()({
- name: 'VBannerActions',
- props: makeVBannerActionsProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- provideDefaults({
- VBtn: {
- color: props.color,
- density: props.density,
- variant: 'text'
- }
- });
- useRender(() => vue.createVNode("div", {
- "class": ['v-banner-actions', props.class],
- "style": props.style
- }, [slots.default?.()]));
- return {};
- }
- });
- // Utilities
- const VBannerText = createSimpleFunctional('v-banner-text');
- // Types
- const makeVBannerProps = propsFactory({
- avatar: String,
- color: String,
- icon: IconValue,
- lines: String,
- stacked: Boolean,
- sticky: Boolean,
- text: String,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeDimensionProps(),
- ...makeElevationProps(),
- ...makeLocationProps(),
- ...makePositionProps(),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VBanner');
- const VBanner = genericComponent()({
- name: 'VBanner',
- props: makeVBannerProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- borderClasses
- } = useBorder(props);
- const {
- densityClasses
- } = useDensity(props);
- const {
- mobile
- } = useDisplay();
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- locationStyles
- } = useLocation(props);
- const {
- positionClasses
- } = usePosition(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- themeClasses
- } = provideTheme(props);
- const color = vue.toRef(props, 'color');
- const density = vue.toRef(props, 'density');
- provideDefaults({
- VBannerActions: {
- color,
- density
- }
- });
- useRender(() => {
- const hasText = !!(props.text || slots.text);
- const hasPrependMedia = !!(props.avatar || props.icon);
- const hasPrepend = !!(hasPrependMedia || slots.prepend);
- return vue.createVNode(props.tag, {
- "class": ['v-banner', {
- 'v-banner--stacked': props.stacked || mobile.value,
- 'v-banner--sticky': props.sticky,
- [`v-banner--${props.lines}-line`]: !!props.lines
- }, borderClasses.value, densityClasses.value, elevationClasses.value, positionClasses.value, roundedClasses.value, themeClasses.value, props.class],
- "style": [dimensionStyles.value, locationStyles.value, props.style],
- "role": "banner"
- }, {
- default: () => [hasPrepend && vue.createVNode("div", {
- "key": "prepend",
- "class": "v-banner__prepend"
- }, [!slots.prepend ? vue.createVNode(VAvatar, {
- "key": "prepend-avatar",
- "color": color.value,
- "density": density.value,
- "icon": props.icon,
- "image": props.avatar
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "prepend-defaults",
- "disabled": !hasPrependMedia,
- "defaults": {
- VAvatar: {
- color: color.value,
- density: density.value,
- icon: props.icon,
- image: props.avatar
- }
- }
- }, slots.prepend)]), vue.createVNode("div", {
- "class": "v-banner__content"
- }, [hasText && vue.createVNode(VBannerText, {
- "key": "text"
- }, {
- default: () => [slots.text?.() ?? props.text]
- }), slots.default?.()]), slots.actions && vue.createVNode(VBannerActions, {
- "key": "actions"
- }, slots.actions)]
- });
- });
- }
- });
- const makeVBottomNavigationProps = propsFactory({
- bgColor: String,
- color: String,
- grow: Boolean,
- mode: {
- type: String,
- validator: v => !v || ['horizontal', 'shift'].includes(v)
- },
- height: {
- type: [Number, String],
- default: 56
- },
- active: {
- type: Boolean,
- default: true
- },
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeElevationProps(),
- ...makeRoundedProps(),
- ...makeLayoutItemProps({
- name: 'bottom-navigation'
- }),
- ...makeTagProps({
- tag: 'header'
- }),
- ...makeGroupProps({
- modelValue: true,
- selectedClass: 'v-btn--selected'
- }),
- ...makeThemeProps()
- }, 'VBottomNavigation');
- const VBottomNavigation = genericComponent()({
- name: 'VBottomNavigation',
- props: makeVBottomNavigationProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = useTheme();
- const {
- borderClasses
- } = useBorder(props);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'bgColor'));
- const {
- densityClasses
- } = useDensity(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- ssrBootStyles
- } = useSsrBoot();
- const height = vue.computed(() => Number(props.height) - (props.density === 'comfortable' ? 8 : 0) - (props.density === 'compact' ? 16 : 0));
- const isActive = vue.toRef(props, 'active');
- const {
- layoutItemStyles
- } = useLayoutItem({
- id: props.name,
- order: vue.computed(() => parseInt(props.order, 10)),
- position: vue.computed(() => 'bottom'),
- layoutSize: vue.computed(() => isActive.value ? height.value : 0),
- elementSize: height,
- active: isActive,
- absolute: vue.toRef(props, 'absolute')
- });
- useGroup(props, VBtnToggleSymbol);
- provideDefaults({
- VBtn: {
- color: vue.toRef(props, 'color'),
- density: vue.toRef(props, 'density'),
- stacked: vue.computed(() => props.mode !== 'horizontal'),
- variant: 'text'
- }
- }, {
- scoped: true
- });
- useRender(() => {
- return vue.createVNode(props.tag, {
- "class": ['v-bottom-navigation', {
- 'v-bottom-navigation--active': isActive.value,
- 'v-bottom-navigation--grow': props.grow,
- 'v-bottom-navigation--shift': props.mode === 'shift'
- }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, densityClasses.value, elevationClasses.value, roundedClasses.value, props.class],
- "style": [backgroundColorStyles.value, layoutItemStyles.value, {
- height: convertToUnit(height.value),
- transform: `translateY(${convertToUnit(!isActive.value ? 100 : 0, '%')})`
- }, ssrBootStyles.value, props.style]
- }, {
- default: () => [slots.default && vue.createVNode("div", {
- "class": "v-bottom-navigation__content"
- }, [slots.default()])]
- });
- });
- return {};
- }
- });
- const makeVBreadcrumbsDividerProps = propsFactory({
- divider: [Number, String],
- ...makeComponentProps()
- }, 'VBreadcrumbsDivider');
- const VBreadcrumbsDivider = genericComponent()({
- name: 'VBreadcrumbsDivider',
- props: makeVBreadcrumbsDividerProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode("li", {
- "class": ['v-breadcrumbs-divider', props.class],
- "style": props.style
- }, [slots?.default?.() ?? props.divider]));
- return {};
- }
- });
- const makeVBreadcrumbsItemProps = propsFactory({
- active: Boolean,
- activeClass: String,
- activeColor: String,
- color: String,
- disabled: Boolean,
- title: String,
- ...makeComponentProps(),
- ...makeRouterProps(),
- ...makeTagProps({
- tag: 'li'
- })
- }, 'VBreadcrumbsItem');
- const VBreadcrumbsItem = genericComponent()({
- name: 'VBreadcrumbsItem',
- props: makeVBreadcrumbsItemProps(),
- setup(props, _ref) {
- let {
- slots,
- attrs
- } = _ref;
- const link = useLink(props, attrs);
- const isActive = vue.computed(() => props.active || link.isActive?.value);
- const color = vue.computed(() => isActive.value ? props.activeColor : props.color);
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(color);
- useRender(() => {
- return vue.createVNode(props.tag, {
- "class": ['v-breadcrumbs-item', {
- 'v-breadcrumbs-item--active': isActive.value,
- 'v-breadcrumbs-item--disabled': props.disabled,
- [`${props.activeClass}`]: isActive.value && props.activeClass
- }, textColorClasses.value, props.class],
- "style": [textColorStyles.value, props.style],
- "aria-current": isActive.value ? 'page' : undefined
- }, {
- default: () => [!link.isLink.value ? slots.default?.() ?? props.title : vue.createVNode("a", {
- "class": "v-breadcrumbs-item--link",
- "href": link.href.value,
- "aria-current": isActive.value ? 'page' : undefined,
- "onClick": link.navigate
- }, [slots.default?.() ?? props.title])]
- });
- });
- return {};
- }
- });
- // Types
- const makeVBreadcrumbsProps = propsFactory({
- activeClass: String,
- activeColor: String,
- bgColor: String,
- color: String,
- disabled: Boolean,
- divider: {
- type: String,
- default: '/'
- },
- icon: IconValue,
- items: {
- type: Array,
- default: () => []
- },
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeRoundedProps(),
- ...makeTagProps({
- tag: 'ul'
- })
- }, 'VBreadcrumbs');
- const VBreadcrumbs = genericComponent()({
- name: 'VBreadcrumbs',
- props: makeVBreadcrumbsProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'bgColor'));
- const {
- densityClasses
- } = useDensity(props);
- const {
- roundedClasses
- } = useRounded(props);
- provideDefaults({
- VBreadcrumbsDivider: {
- divider: vue.toRef(props, 'divider')
- },
- VBreadcrumbsItem: {
- activeClass: vue.toRef(props, 'activeClass'),
- activeColor: vue.toRef(props, 'activeColor'),
- color: vue.toRef(props, 'color'),
- disabled: vue.toRef(props, 'disabled')
- }
- });
- const items = vue.computed(() => props.items.map(item => {
- return typeof item === 'string' ? {
- item: {
- title: item
- },
- raw: item
- } : {
- item,
- raw: item
- };
- }));
- useRender(() => {
- const hasPrepend = !!(slots.prepend || props.icon);
- return vue.createVNode(props.tag, {
- "class": ['v-breadcrumbs', backgroundColorClasses.value, densityClasses.value, roundedClasses.value, props.class],
- "style": [backgroundColorStyles.value, props.style]
- }, {
- default: () => [hasPrepend && vue.createVNode("li", {
- "key": "prepend",
- "class": "v-breadcrumbs__prepend"
- }, [!slots.prepend ? vue.createVNode(VIcon, {
- "key": "prepend-icon",
- "start": true,
- "icon": props.icon
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "prepend-defaults",
- "disabled": !props.icon,
- "defaults": {
- VIcon: {
- icon: props.icon,
- start: true
- }
- }
- }, slots.prepend)]), items.value.map((_ref2, index, array) => {
- let {
- item,
- raw
- } = _ref2;
- return vue.createVNode(vue.Fragment, null, [vue.createVNode(VBreadcrumbsItem, vue.mergeProps({
- "key": item.title,
- "disabled": index >= array.length - 1
- }, item), {
- default: slots.title ? () => slots.title?.({
- item: raw,
- index
- }) : undefined
- }), index < array.length - 1 && vue.createVNode(VBreadcrumbsDivider, null, {
- default: slots.divider ? () => slots.divider?.({
- item: raw,
- index
- }) : undefined
- })]);
- }), slots.default?.()]
- });
- });
- return {};
- }
- });
- const VCardActions = genericComponent()({
- name: 'VCardActions',
- props: makeComponentProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- provideDefaults({
- VBtn: {
- variant: 'text'
- }
- });
- useRender(() => vue.createVNode("div", {
- "class": ['v-card-actions', props.class],
- "style": props.style
- }, [slots.default?.()]));
- return {};
- }
- });
- // Utilities
- const VCardSubtitle = createSimpleFunctional('v-card-subtitle');
- // Utilities
- const VCardTitle = createSimpleFunctional('v-card-title');
- const makeCardItemProps = propsFactory({
- appendAvatar: String,
- appendIcon: IconValue,
- prependAvatar: String,
- prependIcon: IconValue,
- subtitle: String,
- title: String,
- ...makeComponentProps(),
- ...makeDensityProps()
- }, 'VCardItem');
- const VCardItem = genericComponent()({
- name: 'VCardItem',
- props: makeCardItemProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => {
- const hasPrependMedia = !!(props.prependAvatar || props.prependIcon);
- const hasPrepend = !!(hasPrependMedia || slots.prepend);
- const hasAppendMedia = !!(props.appendAvatar || props.appendIcon);
- const hasAppend = !!(hasAppendMedia || slots.append);
- const hasTitle = !!(props.title || slots.title);
- const hasSubtitle = !!(props.subtitle || slots.subtitle);
- return vue.createVNode("div", {
- "class": ['v-card-item', props.class],
- "style": props.style
- }, [hasPrepend && vue.createVNode("div", {
- "key": "prepend",
- "class": "v-card-item__prepend"
- }, [!slots.prepend ? hasPrependMedia && vue.createVNode(VAvatar, {
- "key": "prepend-avatar",
- "density": props.density,
- "icon": props.prependIcon,
- "image": props.prependAvatar
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "prepend-defaults",
- "disabled": !hasPrependMedia,
- "defaults": {
- VAvatar: {
- density: props.density,
- icon: props.prependIcon,
- image: props.prependAvatar
- }
- }
- }, slots.prepend)]), vue.createVNode("div", {
- "class": "v-card-item__content"
- }, [hasTitle && vue.createVNode(VCardTitle, {
- "key": "title"
- }, {
- default: () => [slots.title?.() ?? props.title]
- }), hasSubtitle && vue.createVNode(VCardSubtitle, {
- "key": "subtitle"
- }, {
- default: () => [slots.subtitle?.() ?? props.subtitle]
- }), slots.default?.()]), hasAppend && vue.createVNode("div", {
- "key": "append",
- "class": "v-card-item__append"
- }, [!slots.append ? hasAppendMedia && vue.createVNode(VAvatar, {
- "key": "append-avatar",
- "density": props.density,
- "icon": props.appendIcon,
- "image": props.appendAvatar
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "append-defaults",
- "disabled": !hasAppendMedia,
- "defaults": {
- VAvatar: {
- density: props.density,
- icon: props.appendIcon,
- image: props.appendAvatar
- }
- }
- }, slots.append)])]);
- });
- return {};
- }
- });
- // Utilities
- const VCardText = createSimpleFunctional('v-card-text');
- // Types
- const makeVCardProps = propsFactory({
- appendAvatar: String,
- appendIcon: IconValue,
- disabled: Boolean,
- flat: Boolean,
- hover: Boolean,
- image: String,
- link: {
- type: Boolean,
- default: undefined
- },
- prependAvatar: String,
- prependIcon: IconValue,
- ripple: {
- type: [Boolean, Object],
- default: true
- },
- subtitle: String,
- text: String,
- title: String,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeDimensionProps(),
- ...makeElevationProps(),
- ...makeLoaderProps(),
- ...makeLocationProps(),
- ...makePositionProps(),
- ...makeRoundedProps(),
- ...makeRouterProps(),
- ...makeTagProps(),
- ...makeThemeProps(),
- ...makeVariantProps({
- variant: 'elevated'
- })
- }, 'VCard');
- const VCard = genericComponent()({
- name: 'VCard',
- directives: {
- Ripple
- },
- props: makeVCardProps(),
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- borderClasses
- } = useBorder(props);
- const {
- colorClasses,
- colorStyles,
- variantClasses
- } = useVariant(props);
- const {
- densityClasses
- } = useDensity(props);
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- loaderClasses
- } = useLoader(props);
- const {
- locationStyles
- } = useLocation(props);
- const {
- positionClasses
- } = usePosition(props);
- const {
- roundedClasses
- } = useRounded(props);
- const link = useLink(props, attrs);
- const isLink = vue.computed(() => props.link !== false && link.isLink.value);
- const isClickable = vue.computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value));
- useRender(() => {
- const Tag = isLink.value ? 'a' : props.tag;
- const hasTitle = !!(slots.title || props.title);
- const hasSubtitle = !!(slots.subtitle || props.subtitle);
- const hasHeader = hasTitle || hasSubtitle;
- const hasAppend = !!(slots.append || props.appendAvatar || props.appendIcon);
- const hasPrepend = !!(slots.prepend || props.prependAvatar || props.prependIcon);
- const hasImage = !!(slots.image || props.image);
- const hasCardItem = hasHeader || hasPrepend || hasAppend;
- const hasText = !!(slots.text || props.text);
- return vue.withDirectives(vue.createVNode(Tag, {
- "class": ['v-card', {
- 'v-card--disabled': props.disabled,
- 'v-card--flat': props.flat,
- 'v-card--hover': props.hover && !(props.disabled || props.flat),
- 'v-card--link': isClickable.value
- }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, loaderClasses.value, positionClasses.value, roundedClasses.value, variantClasses.value, props.class],
- "style": [colorStyles.value, dimensionStyles.value, locationStyles.value, props.style],
- "href": link.href.value,
- "onClick": isClickable.value && link.navigate,
- "tabindex": props.disabled ? -1 : undefined
- }, {
- default: () => [hasImage && vue.createVNode("div", {
- "key": "image",
- "class": "v-card__image"
- }, [!slots.image ? vue.createVNode(VImg, {
- "key": "image-img",
- "cover": true,
- "src": props.image
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "image-defaults",
- "disabled": !props.image,
- "defaults": {
- VImg: {
- cover: true,
- src: props.image
- }
- }
- }, slots.image)]), vue.createVNode(LoaderSlot, {
- "name": "v-card",
- "active": !!props.loading,
- "color": typeof props.loading === 'boolean' ? undefined : props.loading
- }, {
- default: slots.loader
- }), hasCardItem && vue.createVNode(VCardItem, {
- "key": "item",
- "prependAvatar": props.prependAvatar,
- "prependIcon": props.prependIcon,
- "title": props.title,
- "subtitle": props.subtitle,
- "appendAvatar": props.appendAvatar,
- "appendIcon": props.appendIcon
- }, {
- default: slots.item,
- prepend: slots.prepend,
- title: slots.title,
- subtitle: slots.subtitle,
- append: slots.append
- }), hasText && vue.createVNode(VCardText, {
- "key": "text"
- }, {
- default: () => [slots.text?.() ?? props.text]
- }), slots.default?.(), slots.actions && vue.createVNode(VCardActions, null, {
- default: slots.actions
- }), genOverlays(isClickable.value, 'v-card')]
- }), [[vue.resolveDirective("ripple"), isClickable.value && props.ripple]]);
- });
- return {};
- }
- });
- // Utilities
- // Types
- const handleGesture = wrapper => {
- const {
- touchstartX,
- touchendX,
- touchstartY,
- touchendY
- } = wrapper;
- const dirRatio = 0.5;
- const minDistance = 16;
- wrapper.offsetX = touchendX - touchstartX;
- wrapper.offsetY = touchendY - touchstartY;
- if (Math.abs(wrapper.offsetY) < dirRatio * Math.abs(wrapper.offsetX)) {
- wrapper.left && touchendX < touchstartX - minDistance && wrapper.left(wrapper);
- wrapper.right && touchendX > touchstartX + minDistance && wrapper.right(wrapper);
- }
- if (Math.abs(wrapper.offsetX) < dirRatio * Math.abs(wrapper.offsetY)) {
- wrapper.up && touchendY < touchstartY - minDistance && wrapper.up(wrapper);
- wrapper.down && touchendY > touchstartY + minDistance && wrapper.down(wrapper);
- }
- };
- function touchstart(event, wrapper) {
- const touch = event.changedTouches[0];
- wrapper.touchstartX = touch.clientX;
- wrapper.touchstartY = touch.clientY;
- wrapper.start?.({
- originalEvent: event,
- ...wrapper
- });
- }
- function touchend(event, wrapper) {
- const touch = event.changedTouches[0];
- wrapper.touchendX = touch.clientX;
- wrapper.touchendY = touch.clientY;
- wrapper.end?.({
- originalEvent: event,
- ...wrapper
- });
- handleGesture(wrapper);
- }
- function touchmove(event, wrapper) {
- const touch = event.changedTouches[0];
- wrapper.touchmoveX = touch.clientX;
- wrapper.touchmoveY = touch.clientY;
- wrapper.move?.({
- originalEvent: event,
- ...wrapper
- });
- }
- function createHandlers() {
- let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- const wrapper = {
- touchstartX: 0,
- touchstartY: 0,
- touchendX: 0,
- touchendY: 0,
- touchmoveX: 0,
- touchmoveY: 0,
- offsetX: 0,
- offsetY: 0,
- left: value.left,
- right: value.right,
- up: value.up,
- down: value.down,
- start: value.start,
- move: value.move,
- end: value.end
- };
- return {
- touchstart: e => touchstart(e, wrapper),
- touchend: e => touchend(e, wrapper),
- touchmove: e => touchmove(e, wrapper)
- };
- }
- function mounted$3(el, binding) {
- const value = binding.value;
- const target = value?.parent ? el.parentElement : el;
- const options = value?.options ?? {
- passive: true
- };
- const uid = binding.instance?.$.uid; // TODO: use custom uid generator
- if (!target || !uid) return;
- const handlers = createHandlers(binding.value);
- target._touchHandlers = target._touchHandlers ?? Object.create(null);
- target._touchHandlers[uid] = handlers;
- keys(handlers).forEach(eventName => {
- target.addEventListener(eventName, handlers[eventName], options);
- });
- }
- function unmounted$3(el, binding) {
- const target = binding.value?.parent ? el.parentElement : el;
- const uid = binding.instance?.$.uid;
- if (!target?._touchHandlers || !uid) return;
- const handlers = target._touchHandlers[uid];
- keys(handlers).forEach(eventName => {
- target.removeEventListener(eventName, handlers[eventName]);
- });
- delete target._touchHandlers[uid];
- }
- const Touch = {
- mounted: mounted$3,
- unmounted: unmounted$3
- };
- // Types
- const VWindowSymbol = Symbol.for('vuetify:v-window');
- const VWindowGroupSymbol = Symbol.for('vuetify:v-window-group');
- const makeVWindowProps = propsFactory({
- continuous: Boolean,
- nextIcon: {
- type: [Boolean, String, Function, Object],
- default: '$next'
- },
- prevIcon: {
- type: [Boolean, String, Function, Object],
- default: '$prev'
- },
- reverse: Boolean,
- showArrows: {
- type: [Boolean, String],
- validator: v => typeof v === 'boolean' || v === 'hover'
- },
- touch: {
- type: [Object, Boolean],
- default: undefined
- },
- direction: {
- type: String,
- default: 'horizontal'
- },
- modelValue: null,
- disabled: Boolean,
- selectedClass: {
- type: String,
- default: 'v-window-item--active'
- },
- // TODO: mandatory should probably not be exposed but do this for now
- mandatory: {
- type: [Boolean, String],
- default: 'force'
- },
- ...makeComponentProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VWindow');
- const VWindow = genericComponent()({
- name: 'VWindow',
- directives: {
- Touch
- },
- props: makeVWindowProps(),
- emits: {
- 'update:modelValue': v => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- isRtl
- } = useRtl();
- const {
- t
- } = useLocale();
- const group = useGroup(props, VWindowGroupSymbol);
- const rootRef = vue.ref();
- const isRtlReverse = vue.computed(() => isRtl.value ? !props.reverse : props.reverse);
- const isReversed = vue.shallowRef(false);
- const transition = vue.computed(() => {
- const axis = props.direction === 'vertical' ? 'y' : 'x';
- const reverse = isRtlReverse.value ? !isReversed.value : isReversed.value;
- const direction = reverse ? '-reverse' : '';
- return `v-window-${axis}${direction}-transition`;
- });
- const transitionCount = vue.shallowRef(0);
- const transitionHeight = vue.ref(undefined);
- const activeIndex = vue.computed(() => {
- return group.items.value.findIndex(item => group.selected.value.includes(item.id));
- });
- vue.watch(activeIndex, (newVal, oldVal) => {
- const itemsLength = group.items.value.length;
- const lastIndex = itemsLength - 1;
- if (itemsLength <= 2) {
- isReversed.value = newVal < oldVal;
- } else if (newVal === lastIndex && oldVal === 0) {
- isReversed.value = true;
- } else if (newVal === 0 && oldVal === lastIndex) {
- isReversed.value = false;
- } else {
- isReversed.value = newVal < oldVal;
- }
- });
- vue.provide(VWindowSymbol, {
- transition,
- isReversed,
- transitionCount,
- transitionHeight,
- rootRef
- });
- const canMoveBack = vue.computed(() => props.continuous || activeIndex.value !== 0);
- const canMoveForward = vue.computed(() => props.continuous || activeIndex.value !== group.items.value.length - 1);
- function prev() {
- canMoveBack.value && group.prev();
- }
- function next() {
- canMoveForward.value && group.next();
- }
- const arrows = vue.computed(() => {
- const arrows = [];
- const prevProps = {
- icon: isRtl.value ? props.nextIcon : props.prevIcon,
- class: `v-window__${isRtlReverse.value ? 'right' : 'left'}`,
- onClick: group.prev,
- ariaLabel: t('$vuetify.carousel.prev')
- };
- arrows.push(canMoveBack.value ? slots.prev ? slots.prev({
- props: prevProps
- }) : vue.createVNode(VBtn, prevProps, null) : vue.createVNode("div", null, null));
- const nextProps = {
- icon: isRtl.value ? props.prevIcon : props.nextIcon,
- class: `v-window__${isRtlReverse.value ? 'left' : 'right'}`,
- onClick: group.next,
- ariaLabel: t('$vuetify.carousel.next')
- };
- arrows.push(canMoveForward.value ? slots.next ? slots.next({
- props: nextProps
- }) : vue.createVNode(VBtn, nextProps, null) : vue.createVNode("div", null, null));
- return arrows;
- });
- const touchOptions = vue.computed(() => {
- if (props.touch === false) return props.touch;
- const options = {
- left: () => {
- isRtlReverse.value ? prev() : next();
- },
- right: () => {
- isRtlReverse.value ? next() : prev();
- },
- start: _ref2 => {
- let {
- originalEvent
- } = _ref2;
- originalEvent.stopPropagation();
- }
- };
- return {
- ...options,
- ...(props.touch === true ? {} : props.touch)
- };
- });
- useRender(() => vue.withDirectives(vue.createVNode(props.tag, {
- "ref": rootRef,
- "class": ['v-window', {
- 'v-window--show-arrows-on-hover': props.showArrows === 'hover'
- }, themeClasses.value, props.class],
- "style": props.style
- }, {
- default: () => [vue.createVNode("div", {
- "class": "v-window__container",
- "style": {
- height: transitionHeight.value
- }
- }, [slots.default?.({
- group
- }), props.showArrows !== false && vue.createVNode("div", {
- "class": "v-window__controls"
- }, [arrows.value])]), slots.additional?.({
- group
- })]
- }), [[vue.resolveDirective("touch"), touchOptions.value]]));
- return {
- group
- };
- }
- });
- // Types
- const makeVCarouselProps = propsFactory({
- color: String,
- cycle: Boolean,
- delimiterIcon: {
- type: IconValue,
- default: '$delimiter'
- },
- height: {
- type: [Number, String],
- default: 500
- },
- hideDelimiters: Boolean,
- hideDelimiterBackground: Boolean,
- interval: {
- type: [Number, String],
- default: 6000,
- validator: value => Number(value) > 0
- },
- progress: [Boolean, String],
- verticalDelimiters: [Boolean, String],
- ...makeVWindowProps({
- continuous: true,
- mandatory: 'force',
- showArrows: true
- })
- }, 'VCarousel');
- const VCarousel = genericComponent()({
- name: 'VCarousel',
- props: makeVCarouselProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const {
- t
- } = useLocale();
- const windowRef = vue.ref();
- let slideTimeout = -1;
- vue.watch(model, restartTimeout);
- vue.watch(() => props.interval, restartTimeout);
- vue.watch(() => props.cycle, val => {
- if (val) restartTimeout();else window.clearTimeout(slideTimeout);
- });
- vue.onMounted(startTimeout);
- function startTimeout() {
- if (!props.cycle || !windowRef.value) return;
- slideTimeout = window.setTimeout(windowRef.value.group.next, +props.interval > 0 ? +props.interval : 6000);
- }
- function restartTimeout() {
- window.clearTimeout(slideTimeout);
- window.requestAnimationFrame(startTimeout);
- }
- useRender(() => {
- const [windowProps] = VWindow.filterProps(props);
- return vue.createVNode(VWindow, vue.mergeProps({
- "ref": windowRef
- }, windowProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "class": ['v-carousel', {
- 'v-carousel--hide-delimiter-background': props.hideDelimiterBackground,
- 'v-carousel--vertical-delimiters': props.verticalDelimiters
- }, props.class],
- "style": [{
- height: convertToUnit(props.height)
- }, props.style]
- }), {
- default: slots.default,
- additional: _ref2 => {
- let {
- group
- } = _ref2;
- return vue.createVNode(vue.Fragment, null, [!props.hideDelimiters && vue.createVNode("div", {
- "class": "v-carousel__controls",
- "style": {
- left: props.verticalDelimiters === 'left' && props.verticalDelimiters ? 0 : 'auto',
- right: props.verticalDelimiters === 'right' ? 0 : 'auto'
- }
- }, [group.items.value.length > 0 && vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- color: props.color,
- icon: props.delimiterIcon,
- size: 'x-small',
- variant: 'text'
- }
- },
- "scoped": true
- }, {
- default: () => [group.items.value.map((item, index) => {
- const props = {
- id: `carousel-item-${item.id}`,
- 'aria-label': t('$vuetify.carousel.ariaLabel.delimiter', index + 1, group.items.value.length),
- class: [group.isSelected(item.id) && 'v-btn--active'],
- onClick: () => group.select(item.id, true)
- };
- return slots.item ? slots.item({
- props,
- item
- }) : vue.createVNode(VBtn, vue.mergeProps(item, props), null);
- })]
- })]), props.progress && vue.createVNode(VProgressLinear, {
- "class": "v-carousel__progress",
- "color": typeof props.progress === 'string' ? props.progress : undefined,
- "modelValue": (group.getItemIndex(model.value) + 1) / group.items.value.length * 100
- }, null)]);
- },
- prev: slots.prev,
- next: slots.next
- });
- });
- return {};
- }
- });
- const makeVWindowItemProps = propsFactory({
- reverseTransition: {
- type: [Boolean, String],
- default: undefined
- },
- transition: {
- type: [Boolean, String],
- default: undefined
- },
- ...makeComponentProps(),
- ...makeGroupItemProps(),
- ...makeLazyProps()
- }, 'VWindowItem');
- const VWindowItem = genericComponent()({
- name: 'VWindowItem',
- directives: {
- Touch
- },
- props: makeVWindowItemProps(),
- emits: {
- 'group:selected': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const window = vue.inject(VWindowSymbol);
- const groupItem = useGroupItem(props, VWindowGroupSymbol);
- const {
- isBooted
- } = useSsrBoot();
- if (!window || !groupItem) throw new Error('[Vuetify] VWindowItem must be used inside VWindow');
- const isTransitioning = vue.shallowRef(false);
- const hasTransition = vue.computed(() => isBooted.value && (window.isReversed.value ? props.reverseTransition !== false : props.transition !== false));
- function onAfterTransition() {
- if (!isTransitioning.value || !window) {
- return;
- }
- // Finalize transition state.
- isTransitioning.value = false;
- if (window.transitionCount.value > 0) {
- window.transitionCount.value -= 1;
- // Remove container height if we are out of transition.
- if (window.transitionCount.value === 0) {
- window.transitionHeight.value = undefined;
- }
- }
- }
- function onBeforeTransition() {
- if (isTransitioning.value || !window) {
- return;
- }
- // Initialize transition state here.
- isTransitioning.value = true;
- if (window.transitionCount.value === 0) {
- // Set initial height for height transition.
- window.transitionHeight.value = convertToUnit(window.rootRef.value?.clientHeight);
- }
- window.transitionCount.value += 1;
- }
- function onTransitionCancelled() {
- onAfterTransition(); // This should have the same path as normal transition end.
- }
- function onEnterTransition(el) {
- if (!isTransitioning.value) {
- return;
- }
- vue.nextTick(() => {
- // Do not set height if no transition or cancelled.
- if (!hasTransition.value || !isTransitioning.value || !window) {
- return;
- }
- // Set transition target height.
- window.transitionHeight.value = convertToUnit(el.clientHeight);
- });
- }
- const transition = vue.computed(() => {
- const name = window.isReversed.value ? props.reverseTransition : props.transition;
- return !hasTransition.value ? false : {
- name: typeof name !== 'string' ? window.transition.value : name,
- onBeforeEnter: onBeforeTransition,
- onAfterEnter: onAfterTransition,
- onEnterCancelled: onTransitionCancelled,
- onBeforeLeave: onBeforeTransition,
- onAfterLeave: onAfterTransition,
- onLeaveCancelled: onTransitionCancelled,
- onEnter: onEnterTransition
- };
- });
- const {
- hasContent
- } = useLazy(props, groupItem.isSelected);
- useRender(() => vue.createVNode(MaybeTransition, {
- "transition": transition.value,
- "disabled": !isBooted.value
- }, {
- default: () => [vue.withDirectives(vue.createVNode("div", {
- "class": ['v-window-item', groupItem.selectedClass.value, props.class],
- "style": props.style
- }, [hasContent.value && slots.default?.()]), [[vue.vShow, groupItem.isSelected.value]])]
- }));
- return {
- groupItem
- };
- }
- });
- // Types
- const makeVCarouselItemProps = propsFactory({
- ...makeVImgProps(),
- ...makeVWindowItemProps()
- }, 'VCarouselItem');
- const VCarouselItem = genericComponent()({
- name: 'VCarouselItem',
- inheritAttrs: false,
- props: makeVCarouselItemProps(),
- setup(props, _ref) {
- let {
- slots,
- attrs
- } = _ref;
- useRender(() => {
- const [imgProps] = VImg.filterProps(props);
- const [windowItemProps] = VWindowItem.filterProps(props);
- return vue.createVNode(VWindowItem, vue.mergeProps({
- "class": "v-carousel-item"
- }, windowItemProps), {
- default: () => [vue.createVNode(VImg, vue.mergeProps(attrs, imgProps), slots)]
- });
- });
- }
- });
- // Styles
- const VCode = createSimpleFunctional('v-code');
- // Types
- const makeVColorPickerCanvasProps = propsFactory({
- color: {
- type: Object
- },
- disabled: Boolean,
- dotSize: {
- type: [Number, String],
- default: 10
- },
- height: {
- type: [Number, String],
- default: 150
- },
- width: {
- type: [Number, String],
- default: 300
- },
- ...makeComponentProps()
- }, 'VColorPickerCanvas');
- const VColorPickerCanvas = defineComponent({
- name: 'VColorPickerCanvas',
- props: makeVColorPickerCanvasProps(),
- emits: {
- 'update:color': color => true,
- 'update:position': hue => true
- },
- setup(props, _ref) {
- let {
- emit
- } = _ref;
- const isInteracting = vue.shallowRef(false);
- const isOutsideUpdate = vue.shallowRef(false);
- const dotPosition = vue.ref({
- x: 0,
- y: 0
- });
- const dotStyles = vue.computed(() => {
- const {
- x,
- y
- } = dotPosition.value;
- const radius = parseInt(props.dotSize, 10) / 2;
- return {
- width: convertToUnit(props.dotSize),
- height: convertToUnit(props.dotSize),
- transform: `translate(${convertToUnit(x - radius)}, ${convertToUnit(y - radius)})`
- };
- });
- const canvasRef = vue.ref();
- const canvasWidth = vue.shallowRef(parseFloat(props.width));
- const canvasHeight = vue.shallowRef(parseFloat(props.height));
- const {
- resizeRef
- } = useResizeObserver(entries => {
- if (!resizeRef.value?.offsetParent) return;
- const {
- width,
- height
- } = entries[0].contentRect;
- canvasWidth.value = width;
- canvasHeight.value = height;
- });
- function updateDotPosition(x, y, rect) {
- const {
- left,
- top,
- width,
- height
- } = rect;
- dotPosition.value = {
- x: clamp(x - left, 0, width),
- y: clamp(y - top, 0, height)
- };
- }
- function handleClick(e) {
- if (props.disabled || !canvasRef.value) return;
- updateDotPosition(e.clientX, e.clientY, canvasRef.value.getBoundingClientRect());
- }
- function handleMouseDown(e) {
- // To prevent selection while moving cursor
- e.preventDefault();
- if (props.disabled) return;
- isInteracting.value = true;
- window.addEventListener('mousemove', handleMouseMove);
- window.addEventListener('mouseup', handleMouseUp);
- window.addEventListener('touchmove', handleMouseMove);
- window.addEventListener('touchend', handleMouseUp);
- }
- function handleMouseMove(e) {
- if (props.disabled || !canvasRef.value) return;
- isInteracting.value = true;
- const coords = getEventCoordinates(e);
- updateDotPosition(coords.clientX, coords.clientY, canvasRef.value.getBoundingClientRect());
- }
- function handleMouseUp() {
- window.removeEventListener('mousemove', handleMouseMove);
- window.removeEventListener('mouseup', handleMouseUp);
- window.removeEventListener('touchmove', handleMouseMove);
- window.removeEventListener('touchend', handleMouseUp);
- }
- vue.watch(dotPosition, () => {
- if (isOutsideUpdate.value) {
- isOutsideUpdate.value = false;
- return;
- }
- if (!canvasRef.value) return;
- const {
- x,
- y
- } = dotPosition.value;
- emit('update:color', {
- h: props.color?.h ?? 0,
- s: clamp(x, 0, canvasWidth.value) / canvasWidth.value,
- v: 1 - clamp(y, 0, canvasHeight.value) / canvasHeight.value,
- a: props.color?.a ?? 1
- });
- });
- function updateCanvas() {
- if (!canvasRef.value) return;
- const canvas = canvasRef.value;
- const ctx = canvas.getContext('2d');
- if (!ctx) return;
- const saturationGradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
- saturationGradient.addColorStop(0, 'hsla(0, 0%, 100%, 1)'); // white
- saturationGradient.addColorStop(1, `hsla(${props.color?.h ?? 0}, 100%, 50%, 1)`);
- ctx.fillStyle = saturationGradient;
- ctx.fillRect(0, 0, canvas.width, canvas.height);
- const valueGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
- valueGradient.addColorStop(0, 'hsla(0, 0%, 100%, 0)'); // transparent
- valueGradient.addColorStop(1, 'hsla(0, 0%, 0%, 1)'); // black
- ctx.fillStyle = valueGradient;
- ctx.fillRect(0, 0, canvas.width, canvas.height);
- }
- vue.watch(() => props.color?.h, updateCanvas, {
- immediate: true
- });
- vue.watch(() => [canvasWidth.value, canvasHeight.value], (newVal, oldVal) => {
- updateCanvas();
- dotPosition.value = {
- x: dotPosition.value.x * newVal[0] / oldVal[0],
- y: dotPosition.value.y * newVal[1] / oldVal[1]
- };
- }, {
- flush: 'post'
- });
- vue.watch(() => props.color, () => {
- if (isInteracting.value) {
- isInteracting.value = false;
- return;
- }
- isOutsideUpdate.value = true;
- dotPosition.value = props.color ? {
- x: props.color.s * canvasWidth.value,
- y: (1 - props.color.v) * canvasHeight.value
- } : {
- x: 0,
- y: 0
- };
- }, {
- deep: true,
- immediate: true
- });
- vue.onMounted(() => updateCanvas());
- useRender(() => vue.createVNode("div", {
- "ref": resizeRef,
- "class": ['v-color-picker-canvas', props.class],
- "style": props.style,
- "onClick": handleClick,
- "onMousedown": handleMouseDown,
- "onTouchstart": handleMouseDown
- }, [vue.createVNode("canvas", {
- "ref": canvasRef,
- "width": canvasWidth.value,
- "height": canvasHeight.value
- }, null), props.color && vue.createVNode("div", {
- "class": ['v-color-picker-canvas__dot', {
- 'v-color-picker-canvas__dot--disabled': props.disabled
- }],
- "style": dotStyles.value
- }, null)]));
- return {};
- }
- });
- // Utilities
- // Types
- function stripAlpha(color, stripAlpha) {
- if (stripAlpha) {
- const {
- a,
- ...rest
- } = color;
- return rest;
- }
- return color;
- }
- function extractColor(color, input) {
- if (input == null || typeof input === 'string') {
- const hex = HSVtoHex(color);
- if (color.a === 1) return hex.slice(0, 7);else return hex;
- }
- if (typeof input === 'object') {
- let converted;
- if (has(input, ['r', 'g', 'b'])) converted = HSVtoRGB(color);else if (has(input, ['h', 's', 'l'])) converted = HSVtoHSL(color);else if (has(input, ['h', 's', 'v'])) converted = color;
- return stripAlpha(converted, !has(input, ['a']) && color.a === 1);
- }
- return color;
- }
- const nullColor = {
- h: 0,
- s: 0,
- v: 1,
- a: 1
- };
- const rgba = {
- inputProps: {
- type: 'number',
- min: 0
- },
- inputs: [{
- label: 'R',
- max: 255,
- step: 1,
- getValue: c => Math.round(c.r),
- getColor: (c, v) => ({
- ...c,
- r: Number(v)
- })
- }, {
- label: 'G',
- max: 255,
- step: 1,
- getValue: c => Math.round(c.g),
- getColor: (c, v) => ({
- ...c,
- g: Number(v)
- })
- }, {
- label: 'B',
- max: 255,
- step: 1,
- getValue: c => Math.round(c.b),
- getColor: (c, v) => ({
- ...c,
- b: Number(v)
- })
- }, {
- label: 'A',
- max: 1,
- step: 0.01,
- getValue: _ref => {
- let {
- a
- } = _ref;
- return a != null ? Math.round(a * 100) / 100 : 1;
- },
- getColor: (c, v) => ({
- ...c,
- a: Number(v)
- })
- }],
- to: HSVtoRGB,
- from: RGBtoHSV
- };
- const rgb = {
- ...rgba,
- inputs: rgba.inputs?.slice(0, 3)
- };
- const hsla = {
- inputProps: {
- type: 'number',
- min: 0
- },
- inputs: [{
- label: 'H',
- max: 360,
- step: 1,
- getValue: c => Math.round(c.h),
- getColor: (c, v) => ({
- ...c,
- h: Number(v)
- })
- }, {
- label: 'S',
- max: 1,
- step: 0.01,
- getValue: c => Math.round(c.s * 100) / 100,
- getColor: (c, v) => ({
- ...c,
- s: Number(v)
- })
- }, {
- label: 'L',
- max: 1,
- step: 0.01,
- getValue: c => Math.round(c.l * 100) / 100,
- getColor: (c, v) => ({
- ...c,
- l: Number(v)
- })
- }, {
- label: 'A',
- max: 1,
- step: 0.01,
- getValue: _ref2 => {
- let {
- a
- } = _ref2;
- return a != null ? Math.round(a * 100) / 100 : 1;
- },
- getColor: (c, v) => ({
- ...c,
- a: Number(v)
- })
- }],
- to: HSVtoHSL,
- from: HSLtoHSV
- };
- const hsl = {
- ...hsla,
- inputs: hsla.inputs.slice(0, 3)
- };
- const hexa = {
- inputProps: {
- type: 'text'
- },
- inputs: [{
- label: 'HEXA',
- getValue: c => c,
- getColor: (c, v) => v
- }],
- to: HSVtoHex,
- from: HexToHSV
- };
- const hex = {
- ...hexa,
- inputs: [{
- label: 'HEX',
- getValue: c => c.slice(0, 7),
- getColor: (c, v) => v
- }]
- };
- const modes = {
- rgb,
- rgba,
- hsl,
- hsla,
- hex,
- hexa
- };
- // Types
- const VColorPickerInput = _ref => {
- let {
- label,
- ...rest
- } = _ref;
- return vue.createVNode("div", {
- "class": "v-color-picker-edit__input"
- }, [vue.createVNode("input", rest, null), vue.createVNode("span", null, [label])]);
- };
- const makeVColorPickerEditProps = propsFactory({
- color: Object,
- disabled: Boolean,
- mode: {
- type: String,
- default: 'rgba',
- validator: v => Object.keys(modes).includes(v)
- },
- modes: {
- type: Array,
- default: () => Object.keys(modes),
- validator: v => Array.isArray(v) && v.every(m => Object.keys(modes).includes(m))
- },
- ...makeComponentProps()
- }, 'VColorPickerEdit');
- const VColorPickerEdit = defineComponent({
- name: 'VColorPickerEdit',
- props: makeVColorPickerEditProps(),
- emits: {
- 'update:color': color => true,
- 'update:mode': mode => true
- },
- setup(props, _ref2) {
- let {
- emit
- } = _ref2;
- const enabledModes = vue.computed(() => {
- return props.modes.map(key => ({
- ...modes[key],
- name: key
- }));
- });
- const inputs = vue.computed(() => {
- const mode = enabledModes.value.find(m => m.name === props.mode);
- if (!mode) return [];
- const color = props.color ? mode.to(props.color) : null;
- return mode.inputs?.map(_ref3 => {
- let {
- getValue,
- getColor,
- ...inputProps
- } = _ref3;
- return {
- ...mode.inputProps,
- ...inputProps,
- disabled: props.disabled,
- value: color && getValue(color),
- onChange: e => {
- const target = e.target;
- if (!target) return;
- emit('update:color', mode.from(getColor(color ?? nullColor, target.value)));
- }
- };
- });
- });
- useRender(() => vue.createVNode("div", {
- "class": ['v-color-picker-edit', props.class],
- "style": props.style
- }, [inputs.value?.map(props => vue.createVNode(VColorPickerInput, props, null)), enabledModes.value.length > 1 && vue.createVNode(VBtn, {
- "icon": "$unfold",
- "size": "x-small",
- "variant": "plain",
- "onClick": () => {
- const mi = enabledModes.value.findIndex(m => m.name === props.mode);
- emit('update:mode', enabledModes.value[(mi + 1) % enabledModes.value.length].name);
- }
- }, null)]));
- return {};
- }
- });
- /* eslint-disable max-statements */
- // Composables
- // Types
- const VSliderSymbol = Symbol.for('vuetify:v-slider');
- function getOffset(e, el, direction) {
- const vertical = direction === 'vertical';
- const rect = el.getBoundingClientRect();
- const touch = 'touches' in e ? e.touches[0] : e;
- return vertical ? touch.clientY - (rect.top + rect.height / 2) : touch.clientX - (rect.left + rect.width / 2);
- }
- function getPosition(e, position) {
- if ('touches' in e && e.touches.length) return e.touches[0][position];else if ('changedTouches' in e && e.changedTouches.length) return e.changedTouches[0][position];else return e[position];
- }
- const makeSliderProps = propsFactory({
- disabled: {
- type: Boolean,
- default: null
- },
- error: Boolean,
- readonly: {
- type: Boolean,
- default: null
- },
- max: {
- type: [Number, String],
- default: 100
- },
- min: {
- type: [Number, String],
- default: 0
- },
- step: {
- type: [Number, String],
- default: 0
- },
- thumbColor: String,
- thumbLabel: {
- type: [Boolean, String],
- default: undefined,
- validator: v => typeof v === 'boolean' || v === 'always'
- },
- thumbSize: {
- type: [Number, String],
- default: 20
- },
- showTicks: {
- type: [Boolean, String],
- default: false,
- validator: v => typeof v === 'boolean' || v === 'always'
- },
- ticks: {
- type: [Array, Object]
- },
- tickSize: {
- type: [Number, String],
- default: 2
- },
- color: String,
- trackColor: String,
- trackFillColor: String,
- trackSize: {
- type: [Number, String],
- default: 4
- },
- direction: {
- type: String,
- default: 'horizontal',
- validator: v => ['vertical', 'horizontal'].includes(v)
- },
- reverse: Boolean,
- ...makeRoundedProps(),
- ...makeElevationProps({
- elevation: 2
- })
- }, 'Slider');
- const useSteps = props => {
- const min = vue.computed(() => parseFloat(props.min));
- const max = vue.computed(() => parseFloat(props.max));
- const step = vue.computed(() => +props.step > 0 ? parseFloat(props.step) : 0);
- const decimals = vue.computed(() => Math.max(getDecimals(step.value), getDecimals(min.value)));
- function roundValue(value) {
- value = parseFloat(value);
- if (step.value <= 0) return value;
- const clamped = clamp(value, min.value, max.value);
- const offset = min.value % step.value;
- const newValue = Math.round((clamped - offset) / step.value) * step.value + offset;
- return parseFloat(Math.min(newValue, max.value).toFixed(decimals.value));
- }
- return {
- min,
- max,
- step,
- decimals,
- roundValue
- };
- };
- const useSlider = _ref => {
- let {
- props,
- steps,
- onSliderStart,
- onSliderMove,
- onSliderEnd,
- getActiveThumb
- } = _ref;
- const {
- isRtl
- } = useRtl();
- const isReversed = vue.toRef(props, 'reverse');
- const horizontalDirection = vue.computed(() => {
- let hd = isRtl.value ? 'rtl' : 'ltr';
- if (props.reverse) {
- hd = hd === 'rtl' ? 'ltr' : 'rtl';
- }
- return hd;
- });
- const {
- min,
- max,
- step,
- decimals,
- roundValue
- } = steps;
- const thumbSize = vue.computed(() => parseInt(props.thumbSize, 10));
- const tickSize = vue.computed(() => parseInt(props.tickSize, 10));
- const trackSize = vue.computed(() => parseInt(props.trackSize, 10));
- const numTicks = vue.computed(() => (max.value - min.value) / step.value);
- const disabled = vue.toRef(props, 'disabled');
- const vertical = vue.computed(() => props.direction === 'vertical');
- const thumbColor = vue.computed(() => props.error || props.disabled ? undefined : props.thumbColor ?? props.color);
- const trackColor = vue.computed(() => props.error || props.disabled ? undefined : props.trackColor ?? props.color);
- const trackFillColor = vue.computed(() => props.error || props.disabled ? undefined : props.trackFillColor ?? props.color);
- const mousePressed = vue.shallowRef(false);
- const startOffset = vue.shallowRef(0);
- const trackContainerRef = vue.ref();
- const activeThumbRef = vue.ref();
- function parseMouseMove(e) {
- const vertical = props.direction === 'vertical';
- const start = vertical ? 'top' : 'left';
- const length = vertical ? 'height' : 'width';
- const position = vertical ? 'clientY' : 'clientX';
- const {
- [start]: trackStart,
- [length]: trackLength
- } = trackContainerRef.value?.$el.getBoundingClientRect();
- const clickOffset = getPosition(e, position);
- // It is possible for left to be NaN, force to number
- let clickPos = Math.min(Math.max((clickOffset - trackStart - startOffset.value) / trackLength, 0), 1) || 0;
- if (vertical || horizontalDirection.value === 'rtl') clickPos = 1 - clickPos;
- return roundValue(min.value + clickPos * (max.value - min.value));
- }
- const handleStop = e => {
- onSliderEnd({
- value: parseMouseMove(e)
- });
- mousePressed.value = false;
- startOffset.value = 0;
- };
- const handleStart = e => {
- activeThumbRef.value = getActiveThumb(e);
- if (!activeThumbRef.value) return;
- activeThumbRef.value.focus();
- mousePressed.value = true;
- if (activeThumbRef.value.contains(e.target)) {
- startOffset.value = getOffset(e, activeThumbRef.value, props.direction);
- } else {
- startOffset.value = 0;
- onSliderMove({
- value: parseMouseMove(e)
- });
- }
- onSliderStart({
- value: parseMouseMove(e)
- });
- };
- const moveListenerOptions = {
- passive: true,
- capture: true
- };
- function onMouseMove(e) {
- onSliderMove({
- value: parseMouseMove(e)
- });
- }
- function onSliderMouseUp(e) {
- e.stopPropagation();
- e.preventDefault();
- handleStop(e);
- window.removeEventListener('mousemove', onMouseMove, moveListenerOptions);
- window.removeEventListener('mouseup', onSliderMouseUp);
- }
- function onSliderTouchend(e) {
- handleStop(e);
- window.removeEventListener('touchmove', onMouseMove, moveListenerOptions);
- e.target?.removeEventListener('touchend', onSliderTouchend);
- }
- function onSliderTouchstart(e) {
- handleStart(e);
- window.addEventListener('touchmove', onMouseMove, moveListenerOptions);
- e.target?.addEventListener('touchend', onSliderTouchend, {
- passive: false
- });
- }
- function onSliderMousedown(e) {
- e.preventDefault();
- handleStart(e);
- window.addEventListener('mousemove', onMouseMove, moveListenerOptions);
- window.addEventListener('mouseup', onSliderMouseUp, {
- passive: false
- });
- }
- const position = val => {
- const percentage = (val - min.value) / (max.value - min.value) * 100;
- return clamp(isNaN(percentage) ? 0 : percentage, 0, 100);
- };
- const showTicks = vue.toRef(props, 'showTicks');
- const parsedTicks = vue.computed(() => {
- if (!showTicks.value) return [];
- if (!props.ticks) {
- return numTicks.value !== Infinity ? createRange(numTicks.value + 1).map(t => {
- const value = min.value + t * step.value;
- return {
- value,
- position: position(value)
- };
- }) : [];
- }
- if (Array.isArray(props.ticks)) return props.ticks.map(t => ({
- value: t,
- position: position(t),
- label: t.toString()
- }));
- return Object.keys(props.ticks).map(key => ({
- value: parseFloat(key),
- position: position(parseFloat(key)),
- label: props.ticks[key]
- }));
- });
- const hasLabels = vue.computed(() => parsedTicks.value.some(_ref2 => {
- let {
- label
- } = _ref2;
- return !!label;
- }));
- const data = {
- activeThumbRef,
- color: vue.toRef(props, 'color'),
- decimals,
- disabled,
- direction: vue.toRef(props, 'direction'),
- elevation: vue.toRef(props, 'elevation'),
- hasLabels,
- horizontalDirection,
- isReversed,
- min,
- max,
- mousePressed,
- numTicks,
- onSliderMousedown,
- onSliderTouchstart,
- parsedTicks,
- parseMouseMove,
- position,
- readonly: vue.toRef(props, 'readonly'),
- rounded: vue.toRef(props, 'rounded'),
- roundValue,
- showTicks,
- startOffset,
- step,
- thumbSize,
- thumbColor,
- thumbLabel: vue.toRef(props, 'thumbLabel'),
- ticks: vue.toRef(props, 'ticks'),
- tickSize,
- trackColor,
- trackContainerRef,
- trackFillColor,
- trackSize,
- vertical
- };
- vue.provide(VSliderSymbol, data);
- return data;
- };
- // Types
- const makeVSliderThumbProps = propsFactory({
- focused: Boolean,
- max: {
- type: Number,
- required: true
- },
- min: {
- type: Number,
- required: true
- },
- modelValue: {
- type: Number,
- required: true
- },
- position: {
- type: Number,
- required: true
- },
- ripple: {
- type: [Boolean, Object],
- default: true
- },
- ...makeComponentProps()
- }, 'VSliderThumb');
- const VSliderThumb = genericComponent()({
- name: 'VSliderThumb',
- directives: {
- Ripple
- },
- props: makeVSliderThumbProps(),
- emits: {
- 'update:modelValue': v => true
- },
- setup(props, _ref) {
- let {
- slots,
- emit
- } = _ref;
- const slider = vue.inject(VSliderSymbol);
- const {
- rtlClasses
- } = useRtl();
- if (!slider) throw new Error('[Vuetify] v-slider-thumb must be used inside v-slider or v-range-slider');
- const {
- thumbColor,
- step,
- vertical,
- disabled,
- thumbSize,
- thumbLabel,
- direction,
- readonly,
- elevation,
- isReversed,
- horizontalDirection,
- mousePressed,
- decimals
- } = slider;
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(thumbColor);
- const {
- pageup,
- pagedown,
- end,
- home,
- left,
- right,
- down,
- up
- } = keyValues;
- const relevantKeys = [pageup, pagedown, end, home, left, right, down, up];
- const multipliers = vue.computed(() => {
- if (step.value) return [1, 2, 3];else return [1, 5, 10];
- });
- function parseKeydown(e, value) {
- if (!relevantKeys.includes(e.key)) return;
- e.preventDefault();
- const _step = step.value || 0.1;
- const steps = (props.max - props.min) / _step;
- if ([left, right, down, up].includes(e.key)) {
- const increase = horizontalDirection.value === 'rtl' ? [left, up] : [right, up];
- const direction = increase.includes(e.key) ? 1 : -1;
- const multiplier = e.shiftKey ? 2 : e.ctrlKey ? 1 : 0;
- value = value + direction * _step * multipliers.value[multiplier];
- } else if (e.key === home) {
- value = props.min;
- } else if (e.key === end) {
- value = props.max;
- } else {
- const direction = e.key === pagedown ? 1 : -1;
- value = value - direction * _step * (steps > 100 ? steps / 10 : 10);
- }
- return Math.max(props.min, Math.min(props.max, value));
- }
- function onKeydown(e) {
- const newValue = parseKeydown(e, props.modelValue);
- newValue != null && emit('update:modelValue', newValue);
- }
- useRender(() => {
- const positionPercentage = convertToUnit(vertical.value || isReversed.value ? 100 - props.position : props.position, '%');
- const {
- elevationClasses
- } = useElevation(vue.computed(() => !disabled.value ? elevation.value : undefined));
- return vue.createVNode("div", {
- "class": ['v-slider-thumb', {
- 'v-slider-thumb--focused': props.focused,
- 'v-slider-thumb--pressed': props.focused && mousePressed.value
- }, props.class, rtlClasses.value],
- "style": [{
- '--v-slider-thumb-position': positionPercentage,
- '--v-slider-thumb-size': convertToUnit(thumbSize.value)
- }, props.style],
- "role": "slider",
- "tabindex": disabled.value ? -1 : 0,
- "aria-valuemin": props.min,
- "aria-valuemax": props.max,
- "aria-valuenow": props.modelValue,
- "aria-readonly": !!readonly.value,
- "aria-orientation": direction.value,
- "onKeydown": !readonly.value ? onKeydown : undefined
- }, [vue.createVNode("div", {
- "class": ['v-slider-thumb__surface', textColorClasses.value, elevationClasses.value],
- "style": {
- ...textColorStyles.value
- }
- }, null), vue.withDirectives(vue.createVNode("div", {
- "class": ['v-slider-thumb__ripple', textColorClasses.value],
- "style": textColorStyles.value
- }, null), [[vue.resolveDirective("ripple"), props.ripple, null, {
- circle: true,
- center: true
- }]]), vue.createVNode(VScaleTransition, {
- "origin": "bottom center"
- }, {
- default: () => [vue.withDirectives(vue.createVNode("div", {
- "class": "v-slider-thumb__label-container"
- }, [vue.createVNode("div", {
- "class": ['v-slider-thumb__label']
- }, [vue.createVNode("div", null, [slots['thumb-label']?.({
- modelValue: props.modelValue
- }) ?? props.modelValue.toFixed(step.value ? decimals.value : 1)])])]), [[vue.vShow, thumbLabel.value && props.focused || thumbLabel.value === 'always']])]
- })]);
- });
- return {};
- }
- });
- // Types
- const makeVSliderTrackProps = propsFactory({
- start: {
- type: Number,
- required: true
- },
- stop: {
- type: Number,
- required: true
- },
- ...makeComponentProps()
- }, 'VSliderTrack');
- const VSliderTrack = genericComponent()({
- name: 'VSliderTrack',
- props: makeVSliderTrackProps(),
- emits: {},
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const slider = vue.inject(VSliderSymbol);
- if (!slider) throw new Error('[Vuetify] v-slider-track must be inside v-slider or v-range-slider');
- const {
- color,
- horizontalDirection,
- parsedTicks,
- rounded,
- showTicks,
- tickSize,
- trackColor,
- trackFillColor,
- trackSize,
- vertical,
- min,
- max
- } = slider;
- const {
- roundedClasses
- } = useRounded(rounded);
- const {
- backgroundColorClasses: trackFillColorClasses,
- backgroundColorStyles: trackFillColorStyles
- } = useBackgroundColor(trackFillColor);
- const {
- backgroundColorClasses: trackColorClasses,
- backgroundColorStyles: trackColorStyles
- } = useBackgroundColor(trackColor);
- const startDir = vue.computed(() => `inset-${vertical.value ? 'block-end' : 'inline-start'}`);
- const endDir = vue.computed(() => vertical.value ? 'height' : 'width');
- const backgroundStyles = vue.computed(() => {
- return {
- [startDir.value]: '0%',
- [endDir.value]: '100%'
- };
- });
- const trackFillWidth = vue.computed(() => props.stop - props.start);
- const trackFillStyles = vue.computed(() => {
- return {
- [startDir.value]: convertToUnit(props.start, '%'),
- [endDir.value]: convertToUnit(trackFillWidth.value, '%')
- };
- });
- const computedTicks = vue.computed(() => {
- if (!showTicks.value) return [];
- const ticks = vertical.value ? parsedTicks.value.slice().reverse() : parsedTicks.value;
- return ticks.map((tick, index) => {
- const directionProperty = vertical.value ? 'bottom' : 'margin-inline-start';
- const directionValue = tick.value !== min.value && tick.value !== max.value ? convertToUnit(tick.position, '%') : undefined;
- return vue.createVNode("div", {
- "key": tick.value,
- "class": ['v-slider-track__tick', {
- 'v-slider-track__tick--filled': tick.position >= props.start && tick.position <= props.stop,
- 'v-slider-track__tick--first': tick.value === min.value,
- 'v-slider-track__tick--last': tick.value === max.value
- }],
- "style": {
- [directionProperty]: directionValue
- }
- }, [(tick.label || slots['tick-label']) && vue.createVNode("div", {
- "class": "v-slider-track__tick-label"
- }, [slots['tick-label']?.({
- tick,
- index
- }) ?? tick.label])]);
- });
- });
- useRender(() => {
- return vue.createVNode("div", {
- "class": ['v-slider-track', roundedClasses.value, props.class],
- "style": [{
- '--v-slider-track-size': convertToUnit(trackSize.value),
- '--v-slider-tick-size': convertToUnit(tickSize.value),
- direction: !vertical.value ? horizontalDirection.value : undefined
- }, props.style]
- }, [vue.createVNode("div", {
- "class": ['v-slider-track__background', trackColorClasses.value, {
- 'v-slider-track__background--opacity': !!color.value || !trackFillColor.value
- }],
- "style": {
- ...backgroundStyles.value,
- ...trackColorStyles.value
- }
- }, null), vue.createVNode("div", {
- "class": ['v-slider-track__fill', trackFillColorClasses.value],
- "style": {
- ...trackFillStyles.value,
- ...trackFillColorStyles.value
- }
- }, null), showTicks.value && vue.createVNode("div", {
- "class": ['v-slider-track__ticks', {
- 'v-slider-track__ticks--always-show': showTicks.value === 'always'
- }]
- }, [computedTicks.value])]);
- });
- return {};
- }
- });
- // Types
- const makeVSliderProps = propsFactory({
- ...makeFocusProps(),
- ...makeSliderProps(),
- ...makeVInputProps(),
- modelValue: {
- type: [Number, String],
- default: 0
- }
- }, 'VSlider');
- const VSlider = genericComponent()({
- name: 'VSlider',
- props: makeVSliderProps(),
- emits: {
- 'update:focused': value => true,
- 'update:modelValue': v => true,
- start: value => true,
- end: value => true
- },
- setup(props, _ref) {
- let {
- slots,
- emit
- } = _ref;
- const thumbContainerRef = vue.ref();
- const {
- rtlClasses
- } = useRtl();
- const steps = useSteps(props);
- const model = useProxiedModel(props, 'modelValue', undefined, value => {
- return steps.roundValue(value == null ? steps.min.value : value);
- });
- const {
- min,
- max,
- mousePressed,
- roundValue,
- onSliderMousedown,
- onSliderTouchstart,
- trackContainerRef,
- position,
- hasLabels,
- readonly
- } = useSlider({
- props,
- steps,
- onSliderStart: () => {
- emit('start', model.value);
- },
- onSliderEnd: _ref2 => {
- let {
- value
- } = _ref2;
- const roundedValue = roundValue(value);
- model.value = roundedValue;
- emit('end', roundedValue);
- },
- onSliderMove: _ref3 => {
- let {
- value
- } = _ref3;
- return model.value = roundValue(value);
- },
- getActiveThumb: () => thumbContainerRef.value?.$el
- });
- const {
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const trackStop = vue.computed(() => position(model.value));
- useRender(() => {
- const [inputProps, _] = VInput.filterProps(props);
- const hasPrepend = !!(props.label || slots.label || slots.prepend);
- return vue.createVNode(VInput, vue.mergeProps({
- "class": ['v-slider', {
- 'v-slider--has-labels': !!slots['tick-label'] || hasLabels.value,
- 'v-slider--focused': isFocused.value,
- 'v-slider--pressed': mousePressed.value,
- 'v-slider--disabled': props.disabled
- }, rtlClasses.value, props.class],
- "style": props.style
- }, inputProps, {
- "focused": isFocused.value
- }), {
- ...slots,
- prepend: hasPrepend ? slotProps => vue.createVNode(vue.Fragment, null, [slots.label?.(slotProps) ?? props.label ? vue.createVNode(VLabel, {
- "id": slotProps.id.value,
- "class": "v-slider__label",
- "text": props.label
- }, null) : undefined, slots.prepend?.(slotProps)]) : undefined,
- default: _ref4 => {
- let {
- id,
- messagesId
- } = _ref4;
- return vue.createVNode("div", {
- "class": "v-slider__container",
- "onMousedown": !readonly.value ? onSliderMousedown : undefined,
- "onTouchstartPassive": !readonly.value ? onSliderTouchstart : undefined
- }, [vue.createVNode("input", {
- "id": id.value,
- "name": props.name || id.value,
- "disabled": !!props.disabled,
- "readonly": !!props.readonly,
- "tabindex": "-1",
- "value": model.value
- }, null), vue.createVNode(VSliderTrack, {
- "ref": trackContainerRef,
- "start": 0,
- "stop": trackStop.value
- }, {
- 'tick-label': slots['tick-label']
- }), vue.createVNode(VSliderThumb, {
- "ref": thumbContainerRef,
- "aria-describedby": messagesId.value,
- "focused": isFocused.value,
- "min": min.value,
- "max": max.value,
- "modelValue": model.value,
- "onUpdate:modelValue": v => model.value = v,
- "position": trackStop.value,
- "elevation": props.elevation,
- "onFocus": focus,
- "onBlur": blur
- }, {
- 'thumb-label': slots['thumb-label']
- })]);
- }
- });
- });
- return {};
- }
- });
- // Types
- const makeVColorPickerPreviewProps = propsFactory({
- color: {
- type: Object
- },
- disabled: Boolean,
- hideAlpha: Boolean,
- ...makeComponentProps()
- }, 'VColorPickerPreview');
- const VColorPickerPreview = defineComponent({
- name: 'VColorPickerPreview',
- props: makeVColorPickerPreviewProps(),
- emits: {
- 'update:color': color => true
- },
- setup(props, _ref) {
- let {
- emit
- } = _ref;
- useRender(() => vue.createVNode("div", {
- "class": ['v-color-picker-preview', {
- 'v-color-picker-preview--hide-alpha': props.hideAlpha
- }, props.class],
- "style": props.style
- }, [vue.createVNode("div", {
- "class": "v-color-picker-preview__dot"
- }, [vue.createVNode("div", {
- "style": {
- background: HSVtoCSS(props.color ?? nullColor)
- }
- }, null)]), vue.createVNode("div", {
- "class": "v-color-picker-preview__sliders"
- }, [vue.createVNode(VSlider, {
- "class": "v-color-picker-preview__track v-color-picker-preview__hue",
- "modelValue": props.color?.h,
- "onUpdate:modelValue": h => emit('update:color', {
- ...(props.color ?? nullColor),
- h
- }),
- "step": 0,
- "min": 0,
- "max": 360,
- "disabled": props.disabled,
- "thumbSize": 14,
- "trackSize": 8,
- "trackFillColor": "white",
- "hideDetails": true
- }, null), !props.hideAlpha && vue.createVNode(VSlider, {
- "class": "v-color-picker-preview__track v-color-picker-preview__alpha",
- "modelValue": props.color?.a ?? 1,
- "onUpdate:modelValue": a => emit('update:color', {
- ...(props.color ?? nullColor),
- a
- }),
- "step": 1 / 256,
- "min": 0,
- "max": 1,
- "disabled": props.disabled,
- "thumbSize": 14,
- "trackSize": 8,
- "trackFillColor": "white",
- "hideDetails": true
- }, null)])]));
- return {};
- }
- });
- const red = Object.freeze({
- base: '#f44336',
- lighten5: '#ffebee',
- lighten4: '#ffcdd2',
- lighten3: '#ef9a9a',
- lighten2: '#e57373',
- lighten1: '#ef5350',
- darken1: '#e53935',
- darken2: '#d32f2f',
- darken3: '#c62828',
- darken4: '#b71c1c',
- accent1: '#ff8a80',
- accent2: '#ff5252',
- accent3: '#ff1744',
- accent4: '#d50000'
- });
- const pink = Object.freeze({
- base: '#e91e63',
- lighten5: '#fce4ec',
- lighten4: '#f8bbd0',
- lighten3: '#f48fb1',
- lighten2: '#f06292',
- lighten1: '#ec407a',
- darken1: '#d81b60',
- darken2: '#c2185b',
- darken3: '#ad1457',
- darken4: '#880e4f',
- accent1: '#ff80ab',
- accent2: '#ff4081',
- accent3: '#f50057',
- accent4: '#c51162'
- });
- const purple = Object.freeze({
- base: '#9c27b0',
- lighten5: '#f3e5f5',
- lighten4: '#e1bee7',
- lighten3: '#ce93d8',
- lighten2: '#ba68c8',
- lighten1: '#ab47bc',
- darken1: '#8e24aa',
- darken2: '#7b1fa2',
- darken3: '#6a1b9a',
- darken4: '#4a148c',
- accent1: '#ea80fc',
- accent2: '#e040fb',
- accent3: '#d500f9',
- accent4: '#aa00ff'
- });
- const deepPurple = Object.freeze({
- base: '#673ab7',
- lighten5: '#ede7f6',
- lighten4: '#d1c4e9',
- lighten3: '#b39ddb',
- lighten2: '#9575cd',
- lighten1: '#7e57c2',
- darken1: '#5e35b1',
- darken2: '#512da8',
- darken3: '#4527a0',
- darken4: '#311b92',
- accent1: '#b388ff',
- accent2: '#7c4dff',
- accent3: '#651fff',
- accent4: '#6200ea'
- });
- const indigo = Object.freeze({
- base: '#3f51b5',
- lighten5: '#e8eaf6',
- lighten4: '#c5cae9',
- lighten3: '#9fa8da',
- lighten2: '#7986cb',
- lighten1: '#5c6bc0',
- darken1: '#3949ab',
- darken2: '#303f9f',
- darken3: '#283593',
- darken4: '#1a237e',
- accent1: '#8c9eff',
- accent2: '#536dfe',
- accent3: '#3d5afe',
- accent4: '#304ffe'
- });
- const blue = Object.freeze({
- base: '#2196f3',
- lighten5: '#e3f2fd',
- lighten4: '#bbdefb',
- lighten3: '#90caf9',
- lighten2: '#64b5f6',
- lighten1: '#42a5f5',
- darken1: '#1e88e5',
- darken2: '#1976d2',
- darken3: '#1565c0',
- darken4: '#0d47a1',
- accent1: '#82b1ff',
- accent2: '#448aff',
- accent3: '#2979ff',
- accent4: '#2962ff'
- });
- const lightBlue = Object.freeze({
- base: '#03a9f4',
- lighten5: '#e1f5fe',
- lighten4: '#b3e5fc',
- lighten3: '#81d4fa',
- lighten2: '#4fc3f7',
- lighten1: '#29b6f6',
- darken1: '#039be5',
- darken2: '#0288d1',
- darken3: '#0277bd',
- darken4: '#01579b',
- accent1: '#80d8ff',
- accent2: '#40c4ff',
- accent3: '#00b0ff',
- accent4: '#0091ea'
- });
- const cyan = Object.freeze({
- base: '#00bcd4',
- lighten5: '#e0f7fa',
- lighten4: '#b2ebf2',
- lighten3: '#80deea',
- lighten2: '#4dd0e1',
- lighten1: '#26c6da',
- darken1: '#00acc1',
- darken2: '#0097a7',
- darken3: '#00838f',
- darken4: '#006064',
- accent1: '#84ffff',
- accent2: '#18ffff',
- accent3: '#00e5ff',
- accent4: '#00b8d4'
- });
- const teal = Object.freeze({
- base: '#009688',
- lighten5: '#e0f2f1',
- lighten4: '#b2dfdb',
- lighten3: '#80cbc4',
- lighten2: '#4db6ac',
- lighten1: '#26a69a',
- darken1: '#00897b',
- darken2: '#00796b',
- darken3: '#00695c',
- darken4: '#004d40',
- accent1: '#a7ffeb',
- accent2: '#64ffda',
- accent3: '#1de9b6',
- accent4: '#00bfa5'
- });
- const green = Object.freeze({
- base: '#4caf50',
- lighten5: '#e8f5e9',
- lighten4: '#c8e6c9',
- lighten3: '#a5d6a7',
- lighten2: '#81c784',
- lighten1: '#66bb6a',
- darken1: '#43a047',
- darken2: '#388e3c',
- darken3: '#2e7d32',
- darken4: '#1b5e20',
- accent1: '#b9f6ca',
- accent2: '#69f0ae',
- accent3: '#00e676',
- accent4: '#00c853'
- });
- const lightGreen = Object.freeze({
- base: '#8bc34a',
- lighten5: '#f1f8e9',
- lighten4: '#dcedc8',
- lighten3: '#c5e1a5',
- lighten2: '#aed581',
- lighten1: '#9ccc65',
- darken1: '#7cb342',
- darken2: '#689f38',
- darken3: '#558b2f',
- darken4: '#33691e',
- accent1: '#ccff90',
- accent2: '#b2ff59',
- accent3: '#76ff03',
- accent4: '#64dd17'
- });
- const lime = Object.freeze({
- base: '#cddc39',
- lighten5: '#f9fbe7',
- lighten4: '#f0f4c3',
- lighten3: '#e6ee9c',
- lighten2: '#dce775',
- lighten1: '#d4e157',
- darken1: '#c0ca33',
- darken2: '#afb42b',
- darken3: '#9e9d24',
- darken4: '#827717',
- accent1: '#f4ff81',
- accent2: '#eeff41',
- accent3: '#c6ff00',
- accent4: '#aeea00'
- });
- const yellow = Object.freeze({
- base: '#ffeb3b',
- lighten5: '#fffde7',
- lighten4: '#fff9c4',
- lighten3: '#fff59d',
- lighten2: '#fff176',
- lighten1: '#ffee58',
- darken1: '#fdd835',
- darken2: '#fbc02d',
- darken3: '#f9a825',
- darken4: '#f57f17',
- accent1: '#ffff8d',
- accent2: '#ffff00',
- accent3: '#ffea00',
- accent4: '#ffd600'
- });
- const amber = Object.freeze({
- base: '#ffc107',
- lighten5: '#fff8e1',
- lighten4: '#ffecb3',
- lighten3: '#ffe082',
- lighten2: '#ffd54f',
- lighten1: '#ffca28',
- darken1: '#ffb300',
- darken2: '#ffa000',
- darken3: '#ff8f00',
- darken4: '#ff6f00',
- accent1: '#ffe57f',
- accent2: '#ffd740',
- accent3: '#ffc400',
- accent4: '#ffab00'
- });
- const orange = Object.freeze({
- base: '#ff9800',
- lighten5: '#fff3e0',
- lighten4: '#ffe0b2',
- lighten3: '#ffcc80',
- lighten2: '#ffb74d',
- lighten1: '#ffa726',
- darken1: '#fb8c00',
- darken2: '#f57c00',
- darken3: '#ef6c00',
- darken4: '#e65100',
- accent1: '#ffd180',
- accent2: '#ffab40',
- accent3: '#ff9100',
- accent4: '#ff6d00'
- });
- const deepOrange = Object.freeze({
- base: '#ff5722',
- lighten5: '#fbe9e7',
- lighten4: '#ffccbc',
- lighten3: '#ffab91',
- lighten2: '#ff8a65',
- lighten1: '#ff7043',
- darken1: '#f4511e',
- darken2: '#e64a19',
- darken3: '#d84315',
- darken4: '#bf360c',
- accent1: '#ff9e80',
- accent2: '#ff6e40',
- accent3: '#ff3d00',
- accent4: '#dd2c00'
- });
- const brown = Object.freeze({
- base: '#795548',
- lighten5: '#efebe9',
- lighten4: '#d7ccc8',
- lighten3: '#bcaaa4',
- lighten2: '#a1887f',
- lighten1: '#8d6e63',
- darken1: '#6d4c41',
- darken2: '#5d4037',
- darken3: '#4e342e',
- darken4: '#3e2723'
- });
- const blueGrey = Object.freeze({
- base: '#607d8b',
- lighten5: '#eceff1',
- lighten4: '#cfd8dc',
- lighten3: '#b0bec5',
- lighten2: '#90a4ae',
- lighten1: '#78909c',
- darken1: '#546e7a',
- darken2: '#455a64',
- darken3: '#37474f',
- darken4: '#263238'
- });
- const grey = Object.freeze({
- base: '#9e9e9e',
- lighten5: '#fafafa',
- lighten4: '#f5f5f5',
- lighten3: '#eeeeee',
- lighten2: '#e0e0e0',
- lighten1: '#bdbdbd',
- darken1: '#757575',
- darken2: '#616161',
- darken3: '#424242',
- darken4: '#212121'
- });
- const shades = Object.freeze({
- black: '#000000',
- white: '#ffffff',
- transparent: '#ffffff00'
- });
- var colors = Object.freeze({
- red,
- pink,
- purple,
- deepPurple,
- indigo,
- blue,
- lightBlue,
- cyan,
- teal,
- green,
- lightGreen,
- lime,
- yellow,
- amber,
- orange,
- deepOrange,
- brown,
- blueGrey,
- grey,
- shades
- });
- // Types
- const makeVColorPickerSwatchesProps = propsFactory({
- swatches: {
- type: Array,
- default: () => parseDefaultColors(colors)
- },
- disabled: Boolean,
- color: Object,
- maxHeight: [Number, String],
- ...makeComponentProps()
- }, 'VColorPickerSwatches');
- function parseDefaultColors(colors) {
- return Object.keys(colors).map(key => {
- const color = colors[key];
- return color.base ? [color.base, color.darken4, color.darken3, color.darken2, color.darken1, color.lighten1, color.lighten2, color.lighten3, color.lighten4, color.lighten5] : [color.black, color.white, color.transparent];
- });
- }
- const VColorPickerSwatches = defineComponent({
- name: 'VColorPickerSwatches',
- props: makeVColorPickerSwatchesProps(),
- emits: {
- 'update:color': color => true
- },
- setup(props, _ref) {
- let {
- emit
- } = _ref;
- useRender(() => vue.createVNode("div", {
- "class": ['v-color-picker-swatches', props.class],
- "style": [{
- maxHeight: convertToUnit(props.maxHeight)
- }, props.style]
- }, [vue.createVNode("div", null, [props.swatches.map(swatch => vue.createVNode("div", {
- "class": "v-color-picker-swatches__swatch"
- }, [swatch.map(color => {
- const rgba = parseColor(color);
- const hsva = RGBtoHSV(rgba);
- const background = RGBtoCSS(rgba);
- return vue.createVNode("div", {
- "class": "v-color-picker-swatches__color",
- "onClick": () => hsva && emit('update:color', hsva)
- }, [vue.createVNode("div", {
- "style": {
- background
- }
- }, [props.color && deepEqual(props.color, hsva) ? vue.createVNode(VIcon, {
- "size": "x-small",
- "icon": "$success",
- "color": getContrast(color, '#FFFFFF') > 2 ? 'white' : 'black'
- }, null) : undefined])]);
- })]))])]));
- return {};
- }
- });
- const makeVSheetProps = propsFactory({
- color: String,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDimensionProps(),
- ...makeElevationProps(),
- ...makeLocationProps(),
- ...makePositionProps(),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VSheet');
- const VSheet = genericComponent()({
- name: 'VSheet',
- props: makeVSheetProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- const {
- borderClasses
- } = useBorder(props);
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- locationStyles
- } = useLocation(props);
- const {
- positionClasses
- } = usePosition(props);
- const {
- roundedClasses
- } = useRounded(props);
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-sheet', themeClasses.value, backgroundColorClasses.value, borderClasses.value, elevationClasses.value, positionClasses.value, roundedClasses.value, props.class],
- "style": [backgroundColorStyles.value, dimensionStyles.value, locationStyles.value, props.style]
- }, slots));
- return {};
- }
- });
- // Types
- const makeVColorPickerProps = propsFactory({
- canvasHeight: {
- type: [String, Number],
- default: 150
- },
- disabled: Boolean,
- dotSize: {
- type: [Number, String],
- default: 10
- },
- hideCanvas: Boolean,
- hideSliders: Boolean,
- hideInputs: Boolean,
- mode: {
- type: String,
- default: 'rgba',
- validator: v => Object.keys(modes).includes(v)
- },
- modes: {
- type: Array,
- default: () => Object.keys(modes),
- validator: v => Array.isArray(v) && v.every(m => Object.keys(modes).includes(m))
- },
- showSwatches: Boolean,
- swatches: Array,
- swatchesMaxHeight: {
- type: [Number, String],
- default: 150
- },
- modelValue: {
- type: [Object, String]
- },
- ...omit(makeVSheetProps({
- width: 300
- }), ['height', 'location', 'minHeight', 'maxHeight', 'minWidth', 'maxWidth'])
- }, 'VColorPicker');
- const VColorPicker = defineComponent({
- name: 'VColorPicker',
- props: makeVColorPickerProps(),
- emits: {
- 'update:modelValue': color => true,
- 'update:mode': mode => true
- },
- setup(props) {
- const mode = useProxiedModel(props, 'mode');
- const lastPickedColor = vue.ref(null);
- const currentColor = useProxiedModel(props, 'modelValue', undefined, v => {
- if (v == null || v === '') return null;
- let c;
- try {
- c = RGBtoHSV(parseColor(v));
- } catch (err) {
- consoleWarn(err);
- return null;
- }
- if (lastPickedColor.value) {
- c = {
- ...c,
- h: lastPickedColor.value.h
- };
- lastPickedColor.value = null;
- }
- return c;
- }, v => {
- if (!v) return null;
- return extractColor(v, props.modelValue);
- });
- const {
- rtlClasses
- } = useRtl();
- const updateColor = hsva => {
- currentColor.value = hsva;
- lastPickedColor.value = hsva;
- };
- vue.onMounted(() => {
- if (!props.modes.includes(mode.value)) mode.value = props.modes[0];
- });
- provideDefaults({
- VSlider: {
- color: undefined,
- trackColor: undefined,
- trackFillColor: undefined
- }
- });
- useRender(() => {
- const [sheetProps] = VSheet.filterProps(props);
- return vue.createVNode(VSheet, vue.mergeProps({
- "rounded": props.rounded,
- "elevation": props.elevation,
- "theme": props.theme,
- "class": ['v-color-picker', rtlClasses.value, props.class],
- "style": [{
- '--v-color-picker-color-hsv': HSVtoCSS({
- ...(currentColor.value ?? nullColor),
- a: 1
- })
- }, props.style]
- }, sheetProps, {
- "maxWidth": props.width
- }), {
- default: () => [!props.hideCanvas && vue.createVNode(VColorPickerCanvas, {
- "key": "canvas",
- "color": currentColor.value,
- "onUpdate:color": updateColor,
- "disabled": props.disabled,
- "dotSize": props.dotSize,
- "width": props.width,
- "height": props.canvasHeight
- }, null), (!props.hideSliders || !props.hideInputs) && vue.createVNode("div", {
- "key": "controls",
- "class": "v-color-picker__controls"
- }, [!props.hideSliders && vue.createVNode(VColorPickerPreview, {
- "key": "preview",
- "color": currentColor.value,
- "onUpdate:color": updateColor,
- "hideAlpha": !mode.value.endsWith('a'),
- "disabled": props.disabled
- }, null), !props.hideInputs && vue.createVNode(VColorPickerEdit, {
- "key": "edit",
- "modes": props.modes,
- "mode": mode.value,
- "onUpdate:mode": m => mode.value = m,
- "color": currentColor.value,
- "onUpdate:color": updateColor,
- "disabled": props.disabled
- }, null)]), props.showSwatches && vue.createVNode(VColorPickerSwatches, {
- "key": "swatches",
- "color": currentColor.value,
- "onUpdate:color": updateColor,
- "maxHeight": props.swatchesMaxHeight,
- "swatches": props.swatches,
- "disabled": props.disabled
- }, null)]
- });
- });
- return {};
- }
- });
- // Types
- function highlightResult(text, matches, length) {
- if (matches == null) return text;
- if (Array.isArray(matches)) throw new Error('Multiple matches is not implemented');
- return typeof matches === 'number' && ~matches ? vue.createVNode(vue.Fragment, null, [vue.createVNode("span", {
- "class": "v-combobox__unmask"
- }, [text.substr(0, matches)]), vue.createVNode("span", {
- "class": "v-combobox__mask"
- }, [text.substr(matches, length)]), vue.createVNode("span", {
- "class": "v-combobox__unmask"
- }, [text.substr(matches + length)])]) : text;
- }
- const makeVComboboxProps = propsFactory({
- autoSelectFirst: {
- type: [Boolean, String]
- },
- delimiters: Array,
- ...makeFilterProps({
- filterKeys: ['title']
- }),
- ...makeSelectProps({
- hideNoData: true,
- returnObject: true
- }),
- ...omit(makeVTextFieldProps({
- modelValue: null
- }), ['validationValue', 'dirty', 'appendInnerIcon']),
- ...makeTransitionProps({
- transition: false
- })
- }, 'VCombobox');
- const VCombobox = genericComponent()({
- name: 'VCombobox',
- props: makeVComboboxProps(),
- emits: {
- 'update:focused': focused => true,
- 'update:modelValue': val => true,
- 'update:search': val => true,
- 'update:menu': val => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const vTextFieldRef = vue.ref();
- const isFocused = vue.shallowRef(false);
- const isPristine = vue.shallowRef(true);
- const listHasFocus = vue.shallowRef(false);
- const vMenuRef = vue.ref();
- const _menu = useProxiedModel(props, 'menu');
- const menu = vue.computed({
- get: () => _menu.value,
- set: v => {
- if (_menu.value && !v && vMenuRef.value?.ΨopenChildren) return;
- _menu.value = v;
- }
- });
- const selectionIndex = vue.shallowRef(-1);
- let cleared = false;
- const color = vue.computed(() => vTextFieldRef.value?.color);
- const {
- items,
- transformIn,
- transformOut
- } = useItems(props);
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(color);
- const model = useProxiedModel(props, 'modelValue', [], v => transformIn(wrapInArray(v)), v => {
- const transformed = transformOut(v);
- return props.multiple ? transformed : transformed[0] ?? null;
- });
- const form = useForm();
- const _search = vue.shallowRef(!props.multiple ? model.value[0]?.title ?? '' : '');
- const search = vue.computed({
- get: () => {
- return _search.value;
- },
- set: val => {
- _search.value = val;
- if (!props.multiple) {
- model.value = [transformItem$1(props, val)];
- }
- if (val && props.multiple && props.delimiters?.length) {
- const values = val.split(new RegExp(`(?:${props.delimiters.join('|')})+`));
- if (values.length > 1) {
- values.forEach(v => {
- v = v.trim();
- if (v) select(transformItem$1(props, v));
- });
- _search.value = '';
- }
- }
- if (!val) selectionIndex.value = -1;
- isPristine.value = !val;
- }
- });
- vue.watch(_search, value => {
- if (cleared) {
- // wait for clear to finish, VTextField sets _search to null
- // then search computed triggers and updates _search to ''
- vue.nextTick(() => cleared = false);
- } else if (isFocused.value && !menu.value) {
- menu.value = true;
- }
- emit('update:search', value);
- });
- vue.watch(model, value => {
- if (!props.multiple) {
- _search.value = value[0]?.title ?? '';
- }
- });
- const {
- filteredItems,
- getMatches
- } = useFilter(props, items, () => isPristine.value ? '' : search.value);
- const selections = vue.computed(() => {
- return model.value.map(v => {
- return items.value.find(item => {
- const itemRawValue = getPropertyFromItem(item.raw, props.itemValue);
- const modelRawValue = getPropertyFromItem(v.raw, props.itemValue);
- if (itemRawValue === undefined || modelRawValue === undefined) return false;
- return props.returnObject ? props.valueComparator(itemRawValue, modelRawValue) : props.valueComparator(item.value, v.value);
- }) || v;
- });
- });
- const displayItems = vue.computed(() => {
- if (props.hideSelected) {
- return filteredItems.value.filter(filteredItem => !selections.value.some(s => s.value === filteredItem.value));
- }
- return filteredItems.value;
- });
- const selected = vue.computed(() => selections.value.map(selection => selection.props.value));
- const selection = vue.computed(() => selections.value[selectionIndex.value]);
- const highlightFirst = vue.computed(() => {
- const selectFirst = props.autoSelectFirst === true || props.autoSelectFirst === 'exact' && search.value === displayItems.value[0]?.title;
- return selectFirst && displayItems.value.length > 0 && !isPristine.value && !listHasFocus.value;
- });
- const menuDisabled = vue.computed(() => props.hideNoData && !items.value.length || props.readonly || form?.isReadonly.value);
- const listRef = vue.ref();
- const {
- onListScroll,
- onListKeydown
- } = useScrolling(listRef, vTextFieldRef);
- function onClear(e) {
- cleared = true;
- if (props.openOnClear) {
- menu.value = true;
- }
- }
- function onMousedownControl() {
- if (menuDisabled.value) return;
- menu.value = true;
- }
- function onMousedownMenuIcon(e) {
- if (menuDisabled.value) return;
- if (isFocused.value) {
- e.preventDefault();
- e.stopPropagation();
- }
- menu.value = !menu.value;
- }
- function onKeydown(e) {
- if (props.readonly || form?.isReadonly.value) return;
- const selectionStart = vTextFieldRef.value.selectionStart;
- const length = selected.value.length;
- if (selectionIndex.value > -1 || ['Enter', 'ArrowDown', 'ArrowUp'].includes(e.key)) {
- e.preventDefault();
- }
- if (['Enter', 'ArrowDown'].includes(e.key)) {
- menu.value = true;
- }
- if (['Escape'].includes(e.key)) {
- menu.value = false;
- }
- if (['Enter', 'Escape', 'Tab'].includes(e.key)) {
- if (highlightFirst.value && ['Enter', 'Tab'].includes(e.key)) {
- select(filteredItems.value[0]);
- }
- isPristine.value = true;
- }
- if (e.key === 'ArrowDown' && highlightFirst.value) {
- listRef.value?.focus('next');
- }
- if (!props.multiple) return;
- if (['Backspace', 'Delete'].includes(e.key)) {
- if (selectionIndex.value < 0) {
- if (e.key === 'Backspace' && !search.value) {
- selectionIndex.value = length - 1;
- }
- return;
- }
- const originalSelectionIndex = selectionIndex.value;
- if (selection.value) select(selection.value);
- selectionIndex.value = originalSelectionIndex >= length - 1 ? length - 2 : originalSelectionIndex;
- }
- if (e.key === 'ArrowLeft') {
- if (selectionIndex.value < 0 && selectionStart > 0) return;
- const prev = selectionIndex.value > -1 ? selectionIndex.value - 1 : length - 1;
- if (selections.value[prev]) {
- selectionIndex.value = prev;
- } else {
- selectionIndex.value = -1;
- vTextFieldRef.value.setSelectionRange(search.value.length, search.value.length);
- }
- }
- if (e.key === 'ArrowRight') {
- if (selectionIndex.value < 0) return;
- const next = selectionIndex.value + 1;
- if (selections.value[next]) {
- selectionIndex.value = next;
- } else {
- selectionIndex.value = -1;
- vTextFieldRef.value.setSelectionRange(0, 0);
- }
- }
- if (e.key === 'Enter' && search.value) {
- select(transformItem$1(props, search.value));
- search.value = '';
- }
- }
- function onAfterLeave() {
- if (isFocused.value) {
- isPristine.value = true;
- vTextFieldRef.value?.focus();
- }
- }
- function select(item) {
- if (props.multiple) {
- const index = selected.value.findIndex(selection => props.valueComparator(selection, item.value));
- if (index === -1) {
- model.value = [...model.value, item];
- } else {
- const value = [...model.value];
- value.splice(index, 1);
- model.value = value;
- }
- search.value = '';
- } else {
- model.value = [item];
- _search.value = item.title;
- // watch for search watcher to trigger
- vue.nextTick(() => {
- menu.value = false;
- isPristine.value = true;
- });
- }
- }
- function onFocusin(e) {
- isFocused.value = true;
- setTimeout(() => {
- listHasFocus.value = true;
- });
- }
- function onFocusout(e) {
- listHasFocus.value = false;
- }
- function onUpdateModelValue(v) {
- if (v == null || v === '' && !props.multiple) model.value = [];
- }
- vue.watch(filteredItems, val => {
- if (!val.length && props.hideNoData) menu.value = false;
- });
- vue.watch(isFocused, (val, oldVal) => {
- if (val || val === oldVal) return;
- selectionIndex.value = -1;
- menu.value = false;
- if (highlightFirst.value && !listHasFocus.value && !selections.value.some(_ref2 => {
- let {
- value
- } = _ref2;
- return value === displayItems.value[0].value;
- })) {
- select(displayItems.value[0]);
- } else if (props.multiple && search.value) {
- model.value = [...model.value, transformItem$1(props, search.value)];
- search.value = '';
- }
- });
- useRender(() => {
- const hasChips = !!(props.chips || slots.chip);
- const hasList = !!(!props.hideNoData || displayItems.value.length || slots['prepend-item'] || slots['append-item'] || slots['no-data']);
- const isDirty = model.value.length > 0;
- const [textFieldProps] = VTextField.filterProps(props);
- return vue.createVNode(VTextField, vue.mergeProps({
- "ref": vTextFieldRef
- }, textFieldProps, {
- "modelValue": search.value,
- "onUpdate:modelValue": [$event => search.value = $event, onUpdateModelValue],
- "focused": isFocused.value,
- "onUpdate:focused": $event => isFocused.value = $event,
- "validationValue": model.externalValue,
- "dirty": isDirty,
- "class": ['v-combobox', {
- 'v-combobox--active-menu': menu.value,
- 'v-combobox--chips': !!props.chips,
- 'v-combobox--selection-slot': !!slots.selection,
- 'v-combobox--selecting-index': selectionIndex.value > -1,
- [`v-combobox--${props.multiple ? 'multiple' : 'single'}`]: true
- }, props.class],
- "style": props.style,
- "readonly": props.readonly,
- "placeholder": isDirty ? undefined : props.placeholder,
- "onClick:clear": onClear,
- "onMousedown:control": onMousedownControl,
- "onKeydown": onKeydown
- }), {
- ...slots,
- default: () => vue.createVNode(vue.Fragment, null, [vue.createVNode(VMenu, vue.mergeProps({
- "ref": vMenuRef,
- "modelValue": menu.value,
- "onUpdate:modelValue": $event => menu.value = $event,
- "activator": "parent",
- "contentClass": "v-combobox__content",
- "disabled": menuDisabled.value,
- "eager": props.eager,
- "maxHeight": 310,
- "openOnClick": false,
- "closeOnContentClick": false,
- "transition": props.transition,
- "onAfterLeave": onAfterLeave
- }, props.menuProps), {
- default: () => [hasList && vue.createVNode(VList, {
- "ref": listRef,
- "selected": selected.value,
- "selectStrategy": props.multiple ? 'independent' : 'single-independent',
- "onMousedown": e => e.preventDefault(),
- "onKeydown": onListKeydown,
- "onFocusin": onFocusin,
- "onFocusout": onFocusout,
- "onScrollPassive": onListScroll,
- "tabindex": "-1",
- "color": props.itemColor ?? props.color
- }, {
- default: () => [slots['prepend-item']?.(), !displayItems.value.length && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
- "title": t(props.noDataText)
- }, null)), vue.createVNode(VVirtualScroll, {
- "renderless": true,
- "items": displayItems.value
- }, {
- default: _ref3 => {
- let {
- item,
- index,
- itemRef
- } = _ref3;
- const itemProps = vue.mergeProps(item.props, {
- ref: itemRef,
- key: index,
- active: highlightFirst.value && index === 0 ? true : undefined,
- onClick: () => select(item)
- });
- return slots.item?.({
- item,
- index,
- props: itemProps
- }) ?? vue.createVNode(VListItem, itemProps, {
- prepend: _ref4 => {
- let {
- isSelected
- } = _ref4;
- return vue.createVNode(vue.Fragment, null, [props.multiple && !props.hideSelected ? vue.createVNode(VCheckboxBtn, {
- "key": item.value,
- "modelValue": isSelected,
- "ripple": false,
- "tabindex": "-1"
- }, null) : undefined, item.props.prependIcon && vue.createVNode(VIcon, {
- "icon": item.props.prependIcon
- }, null)]);
- },
- title: () => {
- return isPristine.value ? item.title : highlightResult(item.title, getMatches(item)?.title, search.value?.length ?? 0);
- }
- });
- }
- }), slots['append-item']?.()]
- })]
- }), selections.value.map((item, index) => {
- function onChipClose(e) {
- e.stopPropagation();
- e.preventDefault();
- select(item);
- }
- const slotProps = {
- 'onClick:close': onChipClose,
- onMousedown(e) {
- e.preventDefault();
- e.stopPropagation();
- },
- modelValue: true,
- 'onUpdate:modelValue': undefined
- };
- return vue.createVNode("div", {
- "key": item.value,
- "class": ['v-combobox__selection', index === selectionIndex.value && ['v-combobox__selection--selected', textColorClasses.value]],
- "style": index === selectionIndex.value ? textColorStyles.value : {}
- }, [hasChips ? !slots.chip ? vue.createVNode(VChip, vue.mergeProps({
- "key": "chip",
- "closable": props.closableChips,
- "size": "small",
- "text": item.title
- }, slotProps), null) : vue.createVNode(VDefaultsProvider, {
- "key": "chip-defaults",
- "defaults": {
- VChip: {
- closable: props.closableChips,
- size: 'small',
- text: item.title
- }
- }
- }, {
- default: () => [slots.chip?.({
- item,
- index,
- props: slotProps
- })]
- }) : slots.selection?.({
- item,
- index
- }) ?? vue.createVNode("span", {
- "class": "v-combobox__selection-text"
- }, [item.title, props.multiple && index < selections.value.length - 1 && vue.createVNode("span", {
- "class": "v-combobox__selection-comma"
- }, [vue.createTextVNode(",")])])]);
- })]),
- 'append-inner': function () {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- return vue.createVNode(vue.Fragment, null, [slots['append-inner']?.(...args), (!props.hideNoData || props.items.length) && props.menuIcon ? vue.createVNode(VIcon, {
- "class": "v-combobox__menu-icon",
- "icon": props.menuIcon,
- "onMousedown": onMousedownMenuIcon,
- "onClick": noop
- }, null) : undefined]);
- }
- });
- });
- return forwardRefs({
- isFocused,
- isPristine,
- menu,
- search,
- selectionIndex,
- filteredItems,
- select
- }, vTextFieldRef);
- }
- });
- // Types
- const makeVDialogProps = propsFactory({
- fullscreen: Boolean,
- retainFocus: {
- type: Boolean,
- default: true
- },
- scrollable: Boolean,
- ...makeVOverlayProps({
- origin: 'center center',
- scrollStrategy: 'block',
- transition: {
- component: VDialogTransition
- },
- zIndex: 2400
- })
- }, 'VDialog');
- const VDialog = genericComponent()({
- name: 'VDialog',
- props: makeVDialogProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const isActive = useProxiedModel(props, 'modelValue');
- const {
- scopeId
- } = useScopeId();
- const overlay = vue.ref();
- function onFocusin(e) {
- const before = e.relatedTarget;
- const after = e.target;
- if (before !== after && overlay.value?.contentEl &&
- // We're the topmost dialog
- overlay.value?.globalTop &&
- // It isn't the document or the dialog body
- ![document, overlay.value.contentEl].includes(after) &&
- // It isn't inside the dialog body
- !overlay.value.contentEl.contains(after)) {
- const focusable = focusableChildren(overlay.value.contentEl);
- if (!focusable.length) return;
- const firstElement = focusable[0];
- const lastElement = focusable[focusable.length - 1];
- if (before === firstElement) {
- lastElement.focus();
- } else {
- firstElement.focus();
- }
- }
- }
- if (IN_BROWSER) {
- vue.watch(() => isActive.value && props.retainFocus, val => {
- val ? document.addEventListener('focusin', onFocusin) : document.removeEventListener('focusin', onFocusin);
- }, {
- immediate: true
- });
- }
- vue.watch(isActive, async val => {
- await vue.nextTick();
- if (val) {
- overlay.value.contentEl?.focus({
- preventScroll: true
- });
- } else {
- overlay.value.activatorEl?.focus({
- preventScroll: true
- });
- }
- });
- const activatorProps = vue.computed(() => vue.mergeProps({
- 'aria-haspopup': 'dialog',
- 'aria-expanded': String(isActive.value)
- }, props.activatorProps));
- useRender(() => {
- const [overlayProps] = VOverlay.filterProps(props);
- return vue.createVNode(VOverlay, vue.mergeProps({
- "ref": overlay,
- "class": ['v-dialog', {
- 'v-dialog--fullscreen': props.fullscreen,
- 'v-dialog--scrollable': props.scrollable
- }, props.class],
- "style": props.style
- }, overlayProps, {
- "modelValue": isActive.value,
- "onUpdate:modelValue": $event => isActive.value = $event,
- "aria-modal": "true",
- "activatorProps": activatorProps.value,
- "role": "dialog"
- }, scopeId), {
- activator: slots.activator,
- default: function () {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- return vue.createVNode(VDefaultsProvider, {
- "root": "VDialog"
- }, {
- default: () => [slots.default?.(...args)]
- });
- }
- });
- });
- return forwardRefs({}, overlay);
- }
- });
- // Types
- const VExpansionPanelSymbol = Symbol.for('vuetify:v-expansion-panel');
- const allowedVariants = ['default', 'accordion', 'inset', 'popout'];
- const makeVExpansionPanelsProps = propsFactory({
- color: String,
- variant: {
- type: String,
- default: 'default',
- validator: v => allowedVariants.includes(v)
- },
- readonly: Boolean,
- ...makeComponentProps(),
- ...makeGroupProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VExpansionPanels');
- const VExpansionPanels = genericComponent()({
- name: 'VExpansionPanels',
- props: makeVExpansionPanelsProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useGroup(props, VExpansionPanelSymbol);
- const {
- themeClasses
- } = provideTheme(props);
- const variantClass = vue.computed(() => props.variant && `v-expansion-panels--variant-${props.variant}`);
- provideDefaults({
- VExpansionPanel: {
- color: vue.toRef(props, 'color')
- },
- VExpansionPanelTitle: {
- readonly: vue.toRef(props, 'readonly')
- }
- });
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-expansion-panels', themeClasses.value, variantClass.value, props.class],
- "style": props.style
- }, slots));
- return {};
- }
- });
- const makeVExpansionPanelTextProps = propsFactory({
- ...makeComponentProps(),
- ...makeLazyProps()
- }, 'VExpansionPanelText');
- const VExpansionPanelText = genericComponent()({
- name: 'VExpansionPanelText',
- props: makeVExpansionPanelTextProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const expansionPanel = vue.inject(VExpansionPanelSymbol);
- if (!expansionPanel) throw new Error('[Vuetify] v-expansion-panel-text needs to be placed inside v-expansion-panel');
- const {
- hasContent,
- onAfterLeave
- } = useLazy(props, expansionPanel.isSelected);
- useRender(() => vue.createVNode(VExpandTransition, {
- "onAfterLeave": onAfterLeave
- }, {
- default: () => [vue.withDirectives(vue.createVNode("div", {
- "class": ['v-expansion-panel-text', props.class],
- "style": props.style
- }, [slots.default && hasContent.value && vue.createVNode("div", {
- "class": "v-expansion-panel-text__wrapper"
- }, [slots.default?.()])]), [[vue.vShow, expansionPanel.isSelected.value]])]
- }));
- return {};
- }
- });
- // Types
- const makeVExpansionPanelTitleProps = propsFactory({
- color: String,
- expandIcon: {
- type: IconValue,
- default: '$expand'
- },
- collapseIcon: {
- type: IconValue,
- default: '$collapse'
- },
- hideActions: Boolean,
- ripple: {
- type: [Boolean, Object],
- default: false
- },
- readonly: Boolean,
- ...makeComponentProps()
- }, 'VExpansionPanelTitle');
- const VExpansionPanelTitle = genericComponent()({
- name: 'VExpansionPanelTitle',
- directives: {
- Ripple
- },
- props: makeVExpansionPanelTitleProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const expansionPanel = vue.inject(VExpansionPanelSymbol);
- if (!expansionPanel) throw new Error('[Vuetify] v-expansion-panel-title needs to be placed inside v-expansion-panel');
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(props, 'color');
- const slotProps = vue.computed(() => ({
- collapseIcon: props.collapseIcon,
- disabled: expansionPanel.disabled.value,
- expanded: expansionPanel.isSelected.value,
- expandIcon: props.expandIcon,
- readonly: props.readonly
- }));
- useRender(() => vue.withDirectives(vue.createVNode("button", {
- "class": ['v-expansion-panel-title', {
- 'v-expansion-panel-title--active': expansionPanel.isSelected.value
- }, backgroundColorClasses.value, props.class],
- "style": [backgroundColorStyles.value, props.style],
- "type": "button",
- "tabindex": expansionPanel.disabled.value ? -1 : undefined,
- "disabled": expansionPanel.disabled.value,
- "aria-expanded": expansionPanel.isSelected.value,
- "onClick": !props.readonly ? expansionPanel.toggle : undefined
- }, [vue.createVNode("span", {
- "class": "v-expansion-panel-title__overlay"
- }, null), slots.default?.(slotProps.value), !props.hideActions && vue.createVNode("span", {
- "class": "v-expansion-panel-title__icon"
- }, [slots.actions ? slots.actions(slotProps.value) : vue.createVNode(VIcon, {
- "icon": expansionPanel.isSelected.value ? props.collapseIcon : props.expandIcon
- }, null)])]), [[vue.resolveDirective("ripple"), props.ripple]]));
- return {};
- }
- });
- const makeVExpansionPanelProps = propsFactory({
- title: String,
- text: String,
- bgColor: String,
- ...makeComponentProps(),
- ...makeElevationProps(),
- ...makeGroupItemProps(),
- ...makeLazyProps(),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeVExpansionPanelTitleProps()
- }, 'VExpansionPanel');
- const VExpansionPanel = genericComponent()({
- name: 'VExpansionPanel',
- props: makeVExpansionPanelProps(),
- emits: {
- 'group:selected': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const groupItem = useGroupItem(props, VExpansionPanelSymbol);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(props, 'bgColor');
- const {
- elevationClasses
- } = useElevation(props);
- const {
- roundedClasses
- } = useRounded(props);
- const isDisabled = vue.computed(() => groupItem?.disabled.value || props.disabled);
- const selectedIndices = vue.computed(() => groupItem.group.items.value.reduce((arr, item, index) => {
- if (groupItem.group.selected.value.includes(item.id)) arr.push(index);
- return arr;
- }, []));
- const isBeforeSelected = vue.computed(() => {
- const index = groupItem.group.items.value.findIndex(item => item.id === groupItem.id);
- return !groupItem.isSelected.value && selectedIndices.value.some(selectedIndex => selectedIndex - index === 1);
- });
- const isAfterSelected = vue.computed(() => {
- const index = groupItem.group.items.value.findIndex(item => item.id === groupItem.id);
- return !groupItem.isSelected.value && selectedIndices.value.some(selectedIndex => selectedIndex - index === -1);
- });
- vue.provide(VExpansionPanelSymbol, groupItem);
- provideDefaults({
- VExpansionPanelText: {
- eager: vue.toRef(props, 'eager')
- }
- });
- useRender(() => {
- const hasText = !!(slots.text || props.text);
- const hasTitle = !!(slots.title || props.title);
- return vue.createVNode(props.tag, {
- "class": ['v-expansion-panel', {
- 'v-expansion-panel--active': groupItem.isSelected.value,
- 'v-expansion-panel--before-active': isBeforeSelected.value,
- 'v-expansion-panel--after-active': isAfterSelected.value,
- 'v-expansion-panel--disabled': isDisabled.value
- }, roundedClasses.value, backgroundColorClasses.value, props.class],
- "style": [backgroundColorStyles.value, props.style]
- }, {
- default: () => [vue.createVNode("div", {
- "class": ['v-expansion-panel__shadow', ...elevationClasses.value]
- }, null), hasTitle && vue.createVNode(VExpansionPanelTitle, {
- "key": "title",
- "collapseIcon": props.collapseIcon,
- "color": props.color,
- "expandIcon": props.expandIcon,
- "hideActions": props.hideActions,
- "ripple": props.ripple
- }, {
- default: () => [slots.title ? slots.title() : props.title]
- }), hasText && vue.createVNode(VExpansionPanelText, {
- "key": "text"
- }, {
- default: () => [slots.text ? slots.text() : props.text]
- }), slots.default?.()]
- });
- });
- return {};
- }
- });
- // Types
- const makeVFileInputProps = propsFactory({
- chips: Boolean,
- counter: Boolean,
- counterSizeString: {
- type: String,
- default: '$vuetify.fileInput.counterSize'
- },
- counterString: {
- type: String,
- default: '$vuetify.fileInput.counter'
- },
- multiple: Boolean,
- showSize: {
- type: [Boolean, Number],
- default: false,
- validator: v => {
- return typeof v === 'boolean' || [1000, 1024].includes(v);
- }
- },
- ...makeVInputProps({
- prependIcon: '$file'
- }),
- modelValue: {
- type: Array,
- default: () => [],
- validator: val => {
- return wrapInArray(val).every(v => v != null && typeof v === 'object');
- }
- },
- ...makeVFieldProps({
- clearable: true
- })
- }, 'VFileInput');
- const VFileInput = genericComponent()({
- name: 'VFileInput',
- inheritAttrs: false,
- props: makeVFileInputProps(),
- emits: {
- 'click:control': e => true,
- 'mousedown:control': e => true,
- 'update:focused': focused => true,
- 'update:modelValue': files => true
- },
- setup(props, _ref) {
- let {
- attrs,
- emit,
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const model = useProxiedModel(props, 'modelValue');
- const {
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const base = vue.computed(() => typeof props.showSize !== 'boolean' ? props.showSize : undefined);
- const totalBytes = vue.computed(() => (model.value ?? []).reduce((bytes, _ref2) => {
- let {
- size = 0
- } = _ref2;
- return bytes + size;
- }, 0));
- const totalBytesReadable = vue.computed(() => humanReadableFileSize(totalBytes.value, base.value));
- const fileNames = vue.computed(() => (model.value ?? []).map(file => {
- const {
- name = '',
- size = 0
- } = file;
- return !props.showSize ? name : `${name} (${humanReadableFileSize(size, base.value)})`;
- }));
- const counterValue = vue.computed(() => {
- const fileCount = model.value?.length ?? 0;
- if (props.showSize) return t(props.counterSizeString, fileCount, totalBytesReadable.value);else return t(props.counterString, fileCount);
- });
- const vInputRef = vue.ref();
- const vFieldRef = vue.ref();
- const inputRef = vue.ref();
- const isActive = vue.computed(() => isFocused.value || props.active);
- const isPlainOrUnderlined = vue.computed(() => ['plain', 'underlined'].includes(props.variant));
- function onFocus() {
- if (inputRef.value !== document.activeElement) {
- inputRef.value?.focus();
- }
- if (!isFocused.value) focus();
- }
- function onClickPrepend(e) {
- onControlClick(e);
- }
- function onControlMousedown(e) {
- emit('mousedown:control', e);
- }
- function onControlClick(e) {
- inputRef.value?.click();
- emit('click:control', e);
- }
- function onClear(e) {
- e.stopPropagation();
- onFocus();
- vue.nextTick(() => {
- model.value = [];
- callEvent(props['onClick:clear'], e);
- });
- }
- vue.watch(model, newValue => {
- const hasModelReset = !Array.isArray(newValue) || !newValue.length;
- if (hasModelReset && inputRef.value) {
- inputRef.value.value = '';
- }
- });
- useRender(() => {
- const hasCounter = !!(slots.counter || props.counter);
- const hasDetails = !!(hasCounter || slots.details);
- const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
- const [{
- modelValue: _,
- ...inputProps
- }] = VInput.filterProps(props);
- const [fieldProps] = filterFieldProps(props);
- return vue.createVNode(VInput, vue.mergeProps({
- "ref": vInputRef,
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "class": ['v-file-input', {
- 'v-text-field--plain-underlined': isPlainOrUnderlined.value
- }, props.class],
- "style": props.style,
- "onClick:prepend": onClickPrepend
- }, rootAttrs, inputProps, {
- "centerAffix": !isPlainOrUnderlined.value,
- "focused": isFocused.value
- }), {
- ...slots,
- default: _ref3 => {
- let {
- id,
- isDisabled,
- isDirty,
- isReadonly,
- isValid
- } = _ref3;
- return vue.createVNode(VField, vue.mergeProps({
- "ref": vFieldRef,
- "prepend-icon": props.prependIcon,
- "onMousedown": onControlMousedown,
- "onClick": onControlClick,
- "onClick:clear": onClear,
- "onClick:prependInner": props['onClick:prependInner'],
- "onClick:appendInner": props['onClick:appendInner']
- }, fieldProps, {
- "id": id.value,
- "active": isActive.value || isDirty.value,
- "dirty": isDirty.value,
- "disabled": isDisabled.value,
- "focused": isFocused.value,
- "error": isValid.value === false
- }), {
- ...slots,
- default: _ref4 => {
- let {
- props: {
- class: fieldClass,
- ...slotProps
- }
- } = _ref4;
- return vue.createVNode(vue.Fragment, null, [vue.createVNode("input", vue.mergeProps({
- "ref": inputRef,
- "type": "file",
- "readonly": isReadonly.value,
- "disabled": isDisabled.value,
- "multiple": props.multiple,
- "name": props.name,
- "onClick": e => {
- e.stopPropagation();
- if (isReadonly.value) e.preventDefault();
- onFocus();
- },
- "onChange": e => {
- if (!e.target) return;
- const target = e.target;
- model.value = [...(target.files ?? [])];
- },
- "onFocus": onFocus,
- "onBlur": blur
- }, slotProps, inputAttrs), null), vue.createVNode("div", {
- "class": fieldClass
- }, [!!model.value?.length && (slots.selection ? slots.selection({
- fileNames: fileNames.value,
- totalBytes: totalBytes.value,
- totalBytesReadable: totalBytesReadable.value
- }) : props.chips ? fileNames.value.map(text => vue.createVNode(VChip, {
- "key": text,
- "size": "small",
- "color": props.color
- }, {
- default: () => [text]
- })) : fileNames.value.join(', '))])]);
- }
- });
- },
- details: hasDetails ? slotProps => vue.createVNode(vue.Fragment, null, [slots.details?.(slotProps), hasCounter && vue.createVNode(vue.Fragment, null, [vue.createVNode("span", null, null), vue.createVNode(VCounter, {
- "active": !!model.value?.length,
- "value": counterValue.value
- }, slots.counter)])]) : undefined
- });
- });
- return forwardRefs({}, vInputRef, vFieldRef, inputRef);
- }
- });
- const makeVFooterProps = propsFactory({
- app: Boolean,
- color: String,
- height: {
- type: [Number, String],
- default: 'auto'
- },
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeElevationProps(),
- ...makeLayoutItemProps(),
- ...makeRoundedProps(),
- ...makeTagProps({
- tag: 'footer'
- }),
- ...makeThemeProps()
- }, 'VFooter');
- const VFooter = genericComponent()({
- name: 'VFooter',
- props: makeVFooterProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- const {
- borderClasses
- } = useBorder(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- roundedClasses
- } = useRounded(props);
- const autoHeight = vue.shallowRef(32);
- const {
- resizeRef
- } = useResizeObserver(entries => {
- if (!entries.length) return;
- autoHeight.value = entries[0].target.clientHeight;
- });
- const height = vue.computed(() => props.height === 'auto' ? autoHeight.value : parseInt(props.height, 10));
- const {
- layoutItemStyles
- } = useLayoutItem({
- id: props.name,
- order: vue.computed(() => parseInt(props.order, 10)),
- position: vue.computed(() => 'bottom'),
- layoutSize: height,
- elementSize: vue.computed(() => props.height === 'auto' ? undefined : height.value),
- active: vue.computed(() => props.app),
- absolute: vue.toRef(props, 'absolute')
- });
- useRender(() => vue.createVNode(props.tag, {
- "ref": resizeRef,
- "class": ['v-footer', themeClasses.value, backgroundColorClasses.value, borderClasses.value, elevationClasses.value, roundedClasses.value, props.class],
- "style": [backgroundColorStyles.value, props.app ? layoutItemStyles.value : {
- height: convertToUnit(props.height)
- }, props.style]
- }, slots));
- return {};
- }
- });
- // Types
- const makeVFormProps = propsFactory({
- ...makeComponentProps(),
- ...makeFormProps()
- }, 'VForm');
- const VForm = genericComponent()({
- name: 'VForm',
- props: makeVFormProps(),
- emits: {
- 'update:modelValue': val => true,
- submit: e => true
- },
- setup(props, _ref) {
- let {
- slots,
- emit
- } = _ref;
- const form = createForm(props);
- const formRef = vue.ref();
- function onReset(e) {
- e.preventDefault();
- form.reset();
- }
- function onSubmit(_e) {
- const e = _e;
- const ready = form.validate();
- e.then = ready.then.bind(ready);
- e.catch = ready.catch.bind(ready);
- e.finally = ready.finally.bind(ready);
- emit('submit', e);
- if (!e.defaultPrevented) {
- ready.then(_ref2 => {
- let {
- valid
- } = _ref2;
- if (valid) {
- formRef.value?.submit();
- }
- });
- }
- e.preventDefault();
- }
- useRender(() => vue.createVNode("form", {
- "ref": formRef,
- "class": ['v-form', props.class],
- "style": props.style,
- "novalidate": true,
- "onReset": onReset,
- "onSubmit": onSubmit
- }, [slots.default?.(form)]));
- return forwardRefs(form, formRef);
- }
- });
- const makeVContainerProps = propsFactory({
- fluid: {
- type: Boolean,
- default: false
- },
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VContainer');
- const VContainer = genericComponent()({
- name: 'VContainer',
- props: makeVContainerProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- rtlClasses
- } = useRtl();
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-container', {
- 'v-container--fluid': props.fluid
- }, rtlClasses.value, props.class],
- "style": props.style
- }, slots));
- return {};
- }
- });
- // Styles
- // Types
- const breakpointProps = (() => {
- return breakpoints.reduce((props, val) => {
- props[val] = {
- type: [Boolean, String, Number],
- default: false
- };
- return props;
- }, {});
- })();
- const offsetProps = (() => {
- return breakpoints.reduce((props, val) => {
- const offsetKey = 'offset' + vue.capitalize(val);
- props[offsetKey] = {
- type: [String, Number],
- default: null
- };
- return props;
- }, {});
- })();
- const orderProps = (() => {
- return breakpoints.reduce((props, val) => {
- const orderKey = 'order' + vue.capitalize(val);
- props[orderKey] = {
- type: [String, Number],
- default: null
- };
- return props;
- }, {});
- })();
- const propMap$1 = {
- col: Object.keys(breakpointProps),
- offset: Object.keys(offsetProps),
- order: Object.keys(orderProps)
- };
- function breakpointClass$1(type, prop, val) {
- let className = type;
- if (val == null || val === false) {
- return undefined;
- }
- if (prop) {
- const breakpoint = prop.replace(type, '');
- className += `-${breakpoint}`;
- }
- if (type === 'col') {
- className = 'v-' + className;
- }
- // Handling the boolean style prop when accepting [Boolean, String, Number]
- // means Vue will not convert <v-col sm></v-col> to sm: true for us.
- // Since the default is false, an empty string indicates the prop's presence.
- if (type === 'col' && (val === '' || val === true)) {
- // .v-col-md
- return className.toLowerCase();
- }
- // .order-md-6
- className += `-${val}`;
- return className.toLowerCase();
- }
- const ALIGN_SELF_VALUES = ['auto', 'start', 'end', 'center', 'baseline', 'stretch'];
- const makeVColProps = propsFactory({
- cols: {
- type: [Boolean, String, Number],
- default: false
- },
- ...breakpointProps,
- offset: {
- type: [String, Number],
- default: null
- },
- ...offsetProps,
- order: {
- type: [String, Number],
- default: null
- },
- ...orderProps,
- alignSelf: {
- type: String,
- default: null,
- validator: str => ALIGN_SELF_VALUES.includes(str)
- },
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VCol');
- const VCol = genericComponent()({
- name: 'VCol',
- props: makeVColProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const classes = vue.computed(() => {
- const classList = [];
- // Loop through `col`, `offset`, `order` breakpoint props
- let type;
- for (type in propMap$1) {
- propMap$1[type].forEach(prop => {
- const value = props[prop];
- const className = breakpointClass$1(type, prop, value);
- if (className) classList.push(className);
- });
- }
- const hasColClasses = classList.some(className => className.startsWith('v-col-'));
- classList.push({
- // Default to .v-col if no other col-{bp}-* classes generated nor `cols` specified.
- 'v-col': !hasColClasses || !props.cols,
- [`v-col-${props.cols}`]: props.cols,
- [`offset-${props.offset}`]: props.offset,
- [`order-${props.order}`]: props.order,
- [`align-self-${props.alignSelf}`]: props.alignSelf
- });
- return classList;
- });
- return () => vue.h(props.tag, {
- class: [classes.value, props.class],
- style: props.style
- }, slots.default?.());
- }
- });
- // Styles
- // Types
- const ALIGNMENT = ['start', 'end', 'center'];
- const SPACE = ['space-between', 'space-around', 'space-evenly'];
- function makeRowProps(prefix, def) {
- return breakpoints.reduce((props, val) => {
- const prefixKey = prefix + vue.capitalize(val);
- props[prefixKey] = def();
- return props;
- }, {});
- }
- const ALIGN_VALUES = [...ALIGNMENT, 'baseline', 'stretch'];
- const alignValidator = str => ALIGN_VALUES.includes(str);
- const alignProps = makeRowProps('align', () => ({
- type: String,
- default: null,
- validator: alignValidator
- }));
- const JUSTIFY_VALUES = [...ALIGNMENT, ...SPACE];
- const justifyValidator = str => JUSTIFY_VALUES.includes(str);
- const justifyProps = makeRowProps('justify', () => ({
- type: String,
- default: null,
- validator: justifyValidator
- }));
- const ALIGN_CONTENT_VALUES = [...ALIGNMENT, ...SPACE, 'stretch'];
- const alignContentValidator = str => ALIGN_CONTENT_VALUES.includes(str);
- const alignContentProps = makeRowProps('alignContent', () => ({
- type: String,
- default: null,
- validator: alignContentValidator
- }));
- const propMap = {
- align: Object.keys(alignProps),
- justify: Object.keys(justifyProps),
- alignContent: Object.keys(alignContentProps)
- };
- const classMap = {
- align: 'align',
- justify: 'justify',
- alignContent: 'align-content'
- };
- function breakpointClass(type, prop, val) {
- let className = classMap[type];
- if (val == null) {
- return undefined;
- }
- if (prop) {
- // alignSm -> Sm
- const breakpoint = prop.replace(type, '');
- className += `-${breakpoint}`;
- }
- // .align-items-sm-center
- className += `-${val}`;
- return className.toLowerCase();
- }
- const makeVRowProps = propsFactory({
- dense: Boolean,
- noGutters: Boolean,
- align: {
- type: String,
- default: null,
- validator: alignValidator
- },
- ...alignProps,
- justify: {
- type: String,
- default: null,
- validator: justifyValidator
- },
- ...justifyProps,
- alignContent: {
- type: String,
- default: null,
- validator: alignContentValidator
- },
- ...alignContentProps,
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VRow');
- const VRow = genericComponent()({
- name: 'VRow',
- props: makeVRowProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const classes = vue.computed(() => {
- const classList = [];
- // Loop through `align`, `justify`, `alignContent` breakpoint props
- let type;
- for (type in propMap) {
- propMap[type].forEach(prop => {
- const value = props[prop];
- const className = breakpointClass(type, prop, value);
- if (className) classList.push(className);
- });
- }
- classList.push({
- 'v-row--no-gutters': props.noGutters,
- 'v-row--dense': props.dense,
- [`align-${props.align}`]: props.align,
- [`justify-${props.justify}`]: props.justify,
- [`align-content-${props.alignContent}`]: props.alignContent
- });
- return classList;
- });
- return () => vue.h(props.tag, {
- class: ['v-row', classes.value, props.class],
- style: props.style
- }, slots.default?.());
- }
- });
- // Utilities
- const VSpacer = createSimpleFunctional('flex-grow-1', 'div', 'VSpacer');
- // Composables
- const makeVHoverProps = propsFactory({
- disabled: Boolean,
- modelValue: {
- type: Boolean,
- default: undefined
- },
- ...makeDelayProps()
- }, 'VHover');
- const VHover = genericComponent()({
- name: 'VHover',
- props: makeVHoverProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const isHovering = useProxiedModel(props, 'modelValue');
- const {
- runOpenDelay,
- runCloseDelay
- } = useDelay(props, value => !props.disabled && (isHovering.value = value));
- return () => slots.default?.({
- isHovering: isHovering.value,
- props: {
- onMouseenter: runOpenDelay,
- onMouseleave: runCloseDelay
- }
- });
- }
- });
- const VItemGroupSymbol = Symbol.for('vuetify:v-item-group');
- const makeVItemGroupProps = propsFactory({
- ...makeComponentProps(),
- ...makeGroupProps({
- selectedClass: 'v-item--selected'
- }),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VItemGroup');
- const VItemGroup = genericComponent()({
- name: 'VItemGroup',
- props: makeVItemGroupProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- isSelected,
- select,
- next,
- prev,
- selected
- } = useGroup(props, VItemGroupSymbol);
- return () => vue.createVNode(props.tag, {
- "class": ['v-item-group', themeClasses.value, props.class],
- "style": props.style
- }, {
- default: () => [slots.default?.({
- isSelected,
- select,
- next,
- prev,
- selected: selected.value
- })]
- });
- }
- });
- // Composables
- const VItem = genericComponent()({
- name: 'VItem',
- props: makeGroupItemProps(),
- emits: {
- 'group:selected': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- isSelected,
- select,
- toggle,
- selectedClass,
- value,
- disabled
- } = useGroupItem(props, VItemGroupSymbol);
- return () => slots.default?.({
- isSelected: isSelected.value,
- selectedClass: selectedClass.value,
- select,
- toggle,
- value: value.value,
- disabled: disabled.value
- });
- }
- });
- // Styles
- const VKbd = createSimpleFunctional('v-kbd');
- const makeVLayoutProps = propsFactory({
- ...makeComponentProps(),
- ...makeLayoutProps()
- }, 'VLayout');
- const VLayout = genericComponent()({
- name: 'VLayout',
- props: makeVLayoutProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- layoutClasses,
- layoutStyles,
- getLayoutItem,
- items,
- layoutRef
- } = createLayout(props);
- useRender(() => vue.createVNode("div", {
- "ref": layoutRef,
- "class": [layoutClasses.value, props.class],
- "style": [layoutStyles.value, props.style]
- }, [slots.default?.()]));
- return {
- getLayoutItem,
- items
- };
- }
- });
- // Types
- const makeVLayoutItemProps = propsFactory({
- position: {
- type: String,
- required: true
- },
- size: {
- type: [Number, String],
- default: 300
- },
- modelValue: Boolean,
- ...makeComponentProps(),
- ...makeLayoutItemProps()
- }, 'VLayoutItem');
- const VLayoutItem = genericComponent()({
- name: 'VLayoutItem',
- props: makeVLayoutItemProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- layoutItemStyles
- } = useLayoutItem({
- id: props.name,
- order: vue.computed(() => parseInt(props.order, 10)),
- position: vue.toRef(props, 'position'),
- elementSize: vue.toRef(props, 'size'),
- layoutSize: vue.toRef(props, 'size'),
- active: vue.toRef(props, 'modelValue'),
- absolute: vue.toRef(props, 'absolute')
- });
- return () => vue.createVNode("div", {
- "class": ['v-layout-item', props.class],
- "style": [layoutItemStyles.value, props.style]
- }, [slots.default?.()]);
- }
- });
- // Types
- const makeVLazyProps = propsFactory({
- modelValue: Boolean,
- options: {
- type: Object,
- // For more information on types, navigate to:
- // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
- default: () => ({
- root: undefined,
- rootMargin: undefined,
- threshold: undefined
- })
- },
- ...makeComponentProps(),
- ...makeDimensionProps(),
- ...makeTagProps(),
- ...makeTransitionProps({
- transition: 'fade-transition'
- })
- }, 'VLazy');
- const VLazy = genericComponent()({
- name: 'VLazy',
- directives: {
- intersect: Intersect
- },
- props: makeVLazyProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- dimensionStyles
- } = useDimension(props);
- const isActive = useProxiedModel(props, 'modelValue');
- function onIntersect(isIntersecting) {
- if (isActive.value) return;
- isActive.value = isIntersecting;
- }
- useRender(() => vue.withDirectives(vue.createVNode(props.tag, {
- "class": ['v-lazy', props.class],
- "style": [dimensionStyles.value, props.style]
- }, {
- default: () => [isActive.value && vue.createVNode(MaybeTransition, {
- "transition": props.transition,
- "appear": true
- }, {
- default: () => [slots.default?.()]
- })]
- }), [[vue.resolveDirective("intersect"), {
- handler: onIntersect,
- options: props.options
- }, null]]));
- return {};
- }
- });
- const makeVLocaleProviderProps = propsFactory({
- locale: String,
- fallbackLocale: String,
- messages: Object,
- rtl: {
- type: Boolean,
- default: undefined
- },
- ...makeComponentProps()
- }, 'VLocaleProvider');
- const VLocaleProvider = genericComponent()({
- name: 'VLocaleProvider',
- props: makeVLocaleProviderProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- rtlClasses
- } = provideLocale(props);
- useRender(() => vue.createVNode("div", {
- "class": ['v-locale-provider', rtlClasses.value, props.class],
- "style": props.style
- }, [slots.default?.()]));
- return {};
- }
- });
- const makeVMainProps = propsFactory({
- scrollable: Boolean,
- ...makeComponentProps(),
- ...makeTagProps({
- tag: 'main'
- })
- }, 'VMain');
- const VMain = genericComponent()({
- name: 'VMain',
- props: makeVMainProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- mainStyles
- } = useLayout();
- const {
- ssrBootStyles
- } = useSsrBoot();
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-main', {
- 'v-main--scrollable': props.scrollable
- }, props.class],
- "style": [mainStyles.value, ssrBootStyles.value, props.style]
- }, {
- default: () => [props.scrollable ? vue.createVNode("div", {
- "class": "v-main__scroller"
- }, [slots.default?.()]) : slots.default?.()]
- }));
- return {};
- }
- });
- // Utilities
- // Types
- function useSticky(_ref) {
- let {
- rootEl,
- isSticky,
- layoutItemStyles
- } = _ref;
- const isStuck = vue.shallowRef(false);
- const stuckPosition = vue.shallowRef(0);
- const stickyStyles = vue.computed(() => {
- const side = typeof isStuck.value === 'boolean' ? 'top' : isStuck.value;
- return [isSticky.value ? {
- top: 'auto',
- bottom: 'auto',
- height: undefined
- } : undefined, isStuck.value ? {
- [side]: convertToUnit(stuckPosition.value)
- } : {
- top: layoutItemStyles.value.top
- }];
- });
- vue.onMounted(() => {
- vue.watch(isSticky, val => {
- if (val) {
- window.addEventListener('scroll', onScroll, {
- passive: true
- });
- } else {
- window.removeEventListener('scroll', onScroll);
- }
- }, {
- immediate: true
- });
- });
- vue.onBeforeUnmount(() => {
- window.removeEventListener('scroll', onScroll);
- });
- let lastScrollTop = 0;
- function onScroll() {
- const direction = lastScrollTop > window.scrollY ? 'up' : 'down';
- const rect = rootEl.value.getBoundingClientRect();
- const layoutTop = parseFloat(layoutItemStyles.value.top ?? 0);
- const top = window.scrollY - Math.max(0, stuckPosition.value - layoutTop);
- const bottom = rect.height + Math.max(stuckPosition.value, layoutTop) - window.scrollY - window.innerHeight;
- const bodyScroll = parseFloat(getComputedStyle(rootEl.value).getPropertyValue('--v-body-scroll-y')) || 0;
- if (rect.height < window.innerHeight - layoutTop) {
- isStuck.value = 'top';
- stuckPosition.value = layoutTop;
- } else if (direction === 'up' && isStuck.value === 'bottom' || direction === 'down' && isStuck.value === 'top') {
- stuckPosition.value = window.scrollY + rect.top - bodyScroll;
- isStuck.value = true;
- } else if (direction === 'down' && bottom <= 0) {
- stuckPosition.value = 0;
- isStuck.value = 'bottom';
- } else if (direction === 'up' && top <= 0) {
- if (!bodyScroll) {
- stuckPosition.value = rect.top + top;
- isStuck.value = 'top';
- } else if (isStuck.value !== 'top') {
- stuckPosition.value = -top + bodyScroll + layoutTop;
- isStuck.value = 'top';
- }
- }
- lastScrollTop = window.scrollY;
- }
- return {
- isStuck,
- stickyStyles
- };
- }
- // Utilities
- const HORIZON = 100; // ms
- const HISTORY = 20; // number of samples to keep
- /** @see https://android.googlesource.com/platform/frameworks/native/+/master/libs/input/VelocityTracker.cpp */
- function kineticEnergyToVelocity(work) {
- const sqrt2 = 1.41421356237;
- return (work < 0 ? -1.0 : 1.0) * Math.sqrt(Math.abs(work)) * sqrt2;
- }
- /**
- * Returns pointer velocity in px/s
- */
- function calculateImpulseVelocity(samples) {
- // The input should be in reversed time order (most recent sample at index i=0)
- if (samples.length < 2) {
- // if 0 or 1 points, velocity is zero
- return 0;
- }
- // if (samples[1].t > samples[0].t) {
- // // Algorithm will still work, but not perfectly
- // consoleWarn('Samples provided to calculateImpulseVelocity in the wrong order')
- // }
- if (samples.length === 2) {
- // if 2 points, basic linear calculation
- if (samples[1].t === samples[0].t) {
- // consoleWarn(`Events have identical time stamps t=${samples[0].t}, setting velocity = 0`)
- return 0;
- }
- return (samples[1].d - samples[0].d) / (samples[1].t - samples[0].t);
- }
- // Guaranteed to have at least 3 points here
- // start with the oldest sample and go forward in time
- let work = 0;
- for (let i = samples.length - 1; i > 0; i--) {
- if (samples[i].t === samples[i - 1].t) {
- // consoleWarn(`Events have identical time stamps t=${samples[i].t}, skipping sample`)
- continue;
- }
- const vprev = kineticEnergyToVelocity(work); // v[i-1]
- const vcurr = (samples[i].d - samples[i - 1].d) / (samples[i].t - samples[i - 1].t); // v[i]
- work += (vcurr - vprev) * Math.abs(vcurr);
- if (i === samples.length - 1) {
- work *= 0.5;
- }
- }
- return kineticEnergyToVelocity(work) * 1000;
- }
- function useVelocity() {
- const touches = {};
- function addMovement(e) {
- Array.from(e.changedTouches).forEach(touch => {
- const samples = touches[touch.identifier] ?? (touches[touch.identifier] = new CircularBuffer(HISTORY));
- samples.push([e.timeStamp, touch]);
- });
- }
- function endTouch(e) {
- Array.from(e.changedTouches).forEach(touch => {
- delete touches[touch.identifier];
- });
- }
- function getVelocity(id) {
- const samples = touches[id]?.values().reverse();
- if (!samples) {
- throw new Error(`No samples for touch id ${id}`);
- }
- const newest = samples[0];
- const x = [];
- const y = [];
- for (const val of samples) {
- if (newest[0] - val[0] > HORIZON) break;
- x.push({
- t: val[0],
- d: val[1].clientX
- });
- y.push({
- t: val[0],
- d: val[1].clientY
- });
- }
- return {
- x: calculateImpulseVelocity(x),
- y: calculateImpulseVelocity(y),
- get direction() {
- const {
- x,
- y
- } = this;
- const [absX, absY] = [Math.abs(x), Math.abs(y)];
- return absX > absY && x >= 0 ? 'right' : absX > absY && x <= 0 ? 'left' : absY > absX && y >= 0 ? 'down' : absY > absX && y <= 0 ? 'up' : oops$1();
- }
- };
- }
- return {
- addMovement,
- endTouch,
- getVelocity
- };
- }
- function oops$1() {
- throw new Error();
- }
- // Composables
- // Types
- function useTouch(_ref) {
- let {
- isActive,
- isTemporary,
- width,
- touchless,
- position
- } = _ref;
- vue.onMounted(() => {
- window.addEventListener('touchstart', onTouchstart, {
- passive: true
- });
- window.addEventListener('touchmove', onTouchmove, {
- passive: false
- });
- window.addEventListener('touchend', onTouchend, {
- passive: true
- });
- });
- vue.onBeforeUnmount(() => {
- window.removeEventListener('touchstart', onTouchstart);
- window.removeEventListener('touchmove', onTouchmove);
- window.removeEventListener('touchend', onTouchend);
- });
- const isHorizontal = vue.computed(() => ['left', 'right'].includes(position.value));
- const {
- addMovement,
- endTouch,
- getVelocity
- } = useVelocity();
- let maybeDragging = false;
- const isDragging = vue.shallowRef(false);
- const dragProgress = vue.shallowRef(0);
- const offset = vue.shallowRef(0);
- let start;
- function getOffset(pos, active) {
- return (position.value === 'left' ? pos : position.value === 'right' ? document.documentElement.clientWidth - pos : position.value === 'top' ? pos : position.value === 'bottom' ? document.documentElement.clientHeight - pos : oops()) - (active ? width.value : 0);
- }
- function getProgress(pos) {
- let limit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
- const progress = position.value === 'left' ? (pos - offset.value) / width.value : position.value === 'right' ? (document.documentElement.clientWidth - pos - offset.value) / width.value : position.value === 'top' ? (pos - offset.value) / width.value : position.value === 'bottom' ? (document.documentElement.clientHeight - pos - offset.value) / width.value : oops();
- return limit ? Math.max(0, Math.min(1, progress)) : progress;
- }
- function onTouchstart(e) {
- if (touchless.value) return;
- const touchX = e.changedTouches[0].clientX;
- const touchY = e.changedTouches[0].clientY;
- const touchZone = 25;
- const inTouchZone = position.value === 'left' ? touchX < touchZone : position.value === 'right' ? touchX > document.documentElement.clientWidth - touchZone : position.value === 'top' ? touchY < touchZone : position.value === 'bottom' ? touchY > document.documentElement.clientHeight - touchZone : oops();
- const inElement = isActive.value && (position.value === 'left' ? touchX < width.value : position.value === 'right' ? touchX > document.documentElement.clientWidth - width.value : position.value === 'top' ? touchY < width.value : position.value === 'bottom' ? touchY > document.documentElement.clientHeight - width.value : oops());
- if (inTouchZone || inElement || isActive.value && isTemporary.value) {
- maybeDragging = true;
- start = [touchX, touchY];
- offset.value = getOffset(isHorizontal.value ? touchX : touchY, isActive.value);
- dragProgress.value = getProgress(isHorizontal.value ? touchX : touchY);
- endTouch(e);
- addMovement(e);
- }
- }
- function onTouchmove(e) {
- const touchX = e.changedTouches[0].clientX;
- const touchY = e.changedTouches[0].clientY;
- if (maybeDragging) {
- if (!e.cancelable) {
- maybeDragging = false;
- return;
- }
- const dx = Math.abs(touchX - start[0]);
- const dy = Math.abs(touchY - start[1]);
- const thresholdMet = isHorizontal.value ? dx > dy && dx > 3 : dy > dx && dy > 3;
- if (thresholdMet) {
- isDragging.value = true;
- maybeDragging = false;
- } else if ((isHorizontal.value ? dy : dx) > 3) {
- maybeDragging = false;
- }
- }
- if (!isDragging.value) return;
- e.preventDefault();
- addMovement(e);
- const progress = getProgress(isHorizontal.value ? touchX : touchY, false);
- dragProgress.value = Math.max(0, Math.min(1, progress));
- if (progress > 1) {
- offset.value = getOffset(isHorizontal.value ? touchX : touchY, true);
- } else if (progress < 0) {
- offset.value = getOffset(isHorizontal.value ? touchX : touchY, false);
- }
- }
- function onTouchend(e) {
- maybeDragging = false;
- if (!isDragging.value) return;
- addMovement(e);
- isDragging.value = false;
- const velocity = getVelocity(e.changedTouches[0].identifier);
- const vx = Math.abs(velocity.x);
- const vy = Math.abs(velocity.y);
- const thresholdMet = isHorizontal.value ? vx > vy && vx > 400 : vy > vx && vy > 3;
- if (thresholdMet) {
- isActive.value = velocity.direction === ({
- left: 'right',
- right: 'left',
- top: 'down',
- bottom: 'up'
- }[position.value] || oops());
- } else {
- isActive.value = dragProgress.value > 0.5;
- }
- }
- const dragStyles = vue.computed(() => {
- return isDragging.value ? {
- transform: position.value === 'left' ? `translateX(calc(-100% + ${dragProgress.value * width.value}px))` : position.value === 'right' ? `translateX(calc(100% - ${dragProgress.value * width.value}px))` : position.value === 'top' ? `translateY(calc(-100% + ${dragProgress.value * width.value}px))` : position.value === 'bottom' ? `translateY(calc(100% - ${dragProgress.value * width.value}px))` : oops(),
- transition: 'none'
- } : undefined;
- });
- return {
- isDragging,
- dragProgress,
- dragStyles
- };
- }
- function oops() {
- throw new Error();
- }
- // Types
- const locations = ['start', 'end', 'left', 'right', 'top', 'bottom'];
- const makeVNavigationDrawerProps = propsFactory({
- color: String,
- disableResizeWatcher: Boolean,
- disableRouteWatcher: Boolean,
- expandOnHover: Boolean,
- floating: Boolean,
- modelValue: {
- type: Boolean,
- default: null
- },
- permanent: Boolean,
- rail: {
- type: Boolean,
- default: null
- },
- railWidth: {
- type: [Number, String],
- default: 56
- },
- scrim: {
- type: [Boolean, String],
- default: true
- },
- image: String,
- temporary: Boolean,
- touchless: Boolean,
- width: {
- type: [Number, String],
- default: 256
- },
- location: {
- type: String,
- default: 'start',
- validator: value => locations.includes(value)
- },
- sticky: Boolean,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeElevationProps(),
- ...makeLayoutItemProps(),
- ...makeRoundedProps(),
- ...makeTagProps({
- tag: 'nav'
- }),
- ...makeThemeProps()
- }, 'VNavigationDrawer');
- const VNavigationDrawer = genericComponent()({
- name: 'VNavigationDrawer',
- props: makeVNavigationDrawerProps(),
- emits: {
- 'update:modelValue': val => true,
- 'update:rail': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- emit,
- slots
- } = _ref;
- const {
- isRtl
- } = useRtl();
- const {
- themeClasses
- } = provideTheme(props);
- const {
- borderClasses
- } = useBorder(props);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- const {
- elevationClasses
- } = useElevation(props);
- const {
- mobile
- } = useDisplay();
- const {
- roundedClasses
- } = useRounded(props);
- const router = useRouter();
- const isActive = useProxiedModel(props, 'modelValue', null, v => !!v);
- const {
- ssrBootStyles
- } = useSsrBoot();
- const {
- scopeId
- } = useScopeId();
- const rootEl = vue.ref();
- const isHovering = vue.shallowRef(false);
- const width = vue.computed(() => {
- return props.rail && props.expandOnHover && isHovering.value ? Number(props.width) : Number(props.rail ? props.railWidth : props.width);
- });
- const location = vue.computed(() => {
- return toPhysical(props.location, isRtl.value);
- });
- const isTemporary = vue.computed(() => !props.permanent && (mobile.value || props.temporary));
- const isSticky = vue.computed(() => props.sticky && !isTemporary.value && location.value !== 'bottom');
- if (props.expandOnHover && props.rail != null) {
- vue.watch(isHovering, val => emit('update:rail', !val));
- }
- if (!props.disableResizeWatcher) {
- vue.watch(isTemporary, val => !props.permanent && vue.nextTick(() => isActive.value = !val));
- }
- if (!props.disableRouteWatcher && router) {
- vue.watch(router.currentRoute, () => isTemporary.value && (isActive.value = false));
- }
- vue.watch(() => props.permanent, val => {
- if (val) isActive.value = true;
- });
- vue.onBeforeMount(() => {
- if (props.modelValue != null || isTemporary.value) return;
- isActive.value = props.permanent || !mobile.value;
- });
- const {
- isDragging,
- dragProgress,
- dragStyles
- } = useTouch({
- isActive,
- isTemporary,
- width,
- touchless: vue.toRef(props, 'touchless'),
- position: location
- });
- const layoutSize = vue.computed(() => {
- const size = isTemporary.value ? 0 : props.rail && props.expandOnHover ? Number(props.railWidth) : width.value;
- return isDragging.value ? size * dragProgress.value : size;
- });
- const {
- layoutItemStyles,
- layoutItemScrimStyles
- } = useLayoutItem({
- id: props.name,
- order: vue.computed(() => parseInt(props.order, 10)),
- position: location,
- layoutSize,
- elementSize: width,
- active: vue.computed(() => isActive.value || isDragging.value),
- disableTransitions: vue.computed(() => isDragging.value),
- absolute: vue.computed(() =>
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- props.absolute || isSticky.value && typeof isStuck.value !== 'string')
- });
- const {
- isStuck,
- stickyStyles
- } = useSticky({
- rootEl,
- isSticky,
- layoutItemStyles
- });
- const scrimColor = useBackgroundColor(vue.computed(() => {
- return typeof props.scrim === 'string' ? props.scrim : null;
- }));
- const scrimStyles = vue.computed(() => ({
- ...(isDragging.value ? {
- opacity: dragProgress.value * 0.2,
- transition: 'none'
- } : undefined),
- ...layoutItemScrimStyles.value
- }));
- provideDefaults({
- VList: {
- bgColor: 'transparent'
- }
- });
- function onMouseenter() {
- isHovering.value = true;
- }
- function onMouseleave() {
- isHovering.value = false;
- }
- useRender(() => {
- const hasImage = slots.image || props.image;
- return vue.createVNode(vue.Fragment, null, [vue.createVNode(props.tag, vue.mergeProps({
- "ref": rootEl,
- "onMouseenter": onMouseenter,
- "onMouseleave": onMouseleave,
- "class": ['v-navigation-drawer', `v-navigation-drawer--${location.value}`, {
- 'v-navigation-drawer--expand-on-hover': props.expandOnHover,
- 'v-navigation-drawer--floating': props.floating,
- 'v-navigation-drawer--is-hovering': isHovering.value,
- 'v-navigation-drawer--rail': props.rail,
- 'v-navigation-drawer--temporary': isTemporary.value,
- 'v-navigation-drawer--active': isActive.value,
- 'v-navigation-drawer--sticky': isSticky.value
- }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, elevationClasses.value, roundedClasses.value, props.class],
- "style": [backgroundColorStyles.value, layoutItemStyles.value, dragStyles.value, ssrBootStyles.value, stickyStyles.value, props.style]
- }, scopeId, attrs), {
- default: () => [hasImage && vue.createVNode("div", {
- "key": "image",
- "class": "v-navigation-drawer__img"
- }, [slots.image ? slots.image?.({
- image: props.image
- }) : vue.createVNode("img", {
- "src": props.image,
- "alt": ""
- }, null)]), slots.prepend && vue.createVNode("div", {
- "class": "v-navigation-drawer__prepend"
- }, [slots.prepend?.()]), vue.createVNode("div", {
- "class": "v-navigation-drawer__content"
- }, [slots.default?.()]), slots.append && vue.createVNode("div", {
- "class": "v-navigation-drawer__append"
- }, [slots.append?.()])]
- }), vue.createVNode(vue.Transition, {
- "name": "fade-transition"
- }, {
- default: () => [isTemporary.value && (isDragging.value || isActive.value) && !!props.scrim && vue.createVNode("div", vue.mergeProps({
- "class": ['v-navigation-drawer__scrim', scrimColor.backgroundColorClasses.value],
- "style": [scrimStyles.value, scrimColor.backgroundColorStyles.value],
- "onClick": () => isActive.value = false
- }, scopeId), null)]
- })]);
- });
- return {
- isStuck
- };
- }
- });
- // Composables
- const VNoSsr = defineComponent({
- name: 'VNoSsr',
- setup(_, _ref) {
- let {
- slots
- } = _ref;
- const show = useHydration();
- return () => show.value && slots.default?.();
- }
- });
- // Utilities
- // Types
- function useRefs() {
- const refs = vue.ref([]);
- vue.onBeforeUpdate(() => refs.value = []);
- function updateRef(e, i) {
- refs.value[i] = e;
- }
- return {
- refs,
- updateRef
- };
- }
- // Types
- const makeVPaginationProps = propsFactory({
- activeColor: String,
- start: {
- type: [Number, String],
- default: 1
- },
- modelValue: {
- type: Number,
- default: props => props.start
- },
- disabled: Boolean,
- length: {
- type: [Number, String],
- default: 1,
- validator: val => val % 1 === 0
- },
- totalVisible: [Number, String],
- firstIcon: {
- type: IconValue,
- default: '$first'
- },
- prevIcon: {
- type: IconValue,
- default: '$prev'
- },
- nextIcon: {
- type: IconValue,
- default: '$next'
- },
- lastIcon: {
- type: IconValue,
- default: '$last'
- },
- ariaLabel: {
- type: String,
- default: '$vuetify.pagination.ariaLabel.root'
- },
- pageAriaLabel: {
- type: String,
- default: '$vuetify.pagination.ariaLabel.page'
- },
- currentPageAriaLabel: {
- type: String,
- default: '$vuetify.pagination.ariaLabel.currentPage'
- },
- firstAriaLabel: {
- type: String,
- default: '$vuetify.pagination.ariaLabel.first'
- },
- previousAriaLabel: {
- type: String,
- default: '$vuetify.pagination.ariaLabel.previous'
- },
- nextAriaLabel: {
- type: String,
- default: '$vuetify.pagination.ariaLabel.next'
- },
- lastAriaLabel: {
- type: String,
- default: '$vuetify.pagination.ariaLabel.last'
- },
- ellipsis: {
- type: String,
- default: '...'
- },
- showFirstLastPage: Boolean,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeElevationProps(),
- ...makeRoundedProps(),
- ...makeSizeProps(),
- ...makeTagProps({
- tag: 'nav'
- }),
- ...makeThemeProps(),
- ...makeVariantProps({
- variant: 'text'
- })
- }, 'VPagination');
- const VPagination = genericComponent()({
- name: 'VPagination',
- props: makeVPaginationProps(),
- emits: {
- 'update:modelValue': value => true,
- first: value => true,
- prev: value => true,
- next: value => true,
- last: value => true
- },
- setup(props, _ref) {
- let {
- slots,
- emit
- } = _ref;
- const page = useProxiedModel(props, 'modelValue');
- const {
- t,
- n
- } = useLocale();
- const {
- isRtl
- } = useRtl();
- const {
- themeClasses
- } = provideTheme(props);
- const {
- width
- } = useDisplay();
- const maxButtons = vue.shallowRef(-1);
- provideDefaults(undefined, {
- scoped: true
- });
- const {
- resizeRef
- } = useResizeObserver(entries => {
- if (!entries.length) return;
- const {
- target,
- contentRect
- } = entries[0];
- const firstItem = target.querySelector('.v-pagination__list > *');
- if (!firstItem) return;
- const totalWidth = contentRect.width;
- const itemWidth = firstItem.offsetWidth + parseFloat(getComputedStyle(firstItem).marginRight) * 2;
- maxButtons.value = getMax(totalWidth, itemWidth);
- });
- const length = vue.computed(() => parseInt(props.length, 10));
- const start = vue.computed(() => parseInt(props.start, 10));
- const totalVisible = vue.computed(() => {
- if (props.totalVisible) return parseInt(props.totalVisible, 10);else if (maxButtons.value >= 0) return maxButtons.value;
- return getMax(width.value, 58);
- });
- function getMax(totalWidth, itemWidth) {
- const minButtons = props.showFirstLastPage ? 5 : 3;
- return Math.max(0, Math.floor(
- // Round to two decimal places to avoid floating point errors
- +((totalWidth - itemWidth * minButtons) / itemWidth).toFixed(2)));
- }
- const range = vue.computed(() => {
- if (length.value <= 0 || isNaN(length.value) || length.value > Number.MAX_SAFE_INTEGER) return [];
- if (totalVisible.value <= 1) return [page.value];
- if (length.value <= totalVisible.value) {
- return createRange(length.value, start.value);
- }
- const even = totalVisible.value % 2 === 0;
- const middle = even ? totalVisible.value / 2 : Math.floor(totalVisible.value / 2);
- const left = even ? middle : middle + 1;
- const right = length.value - middle;
- if (left - page.value >= 0) {
- return [...createRange(Math.max(1, totalVisible.value - 1), start.value), props.ellipsis, length.value];
- } else if (page.value - right >= (even ? 1 : 0)) {
- const rangeLength = totalVisible.value - 1;
- const rangeStart = length.value - rangeLength + start.value;
- return [start.value, props.ellipsis, ...createRange(rangeLength, rangeStart)];
- } else {
- const rangeLength = Math.max(1, totalVisible.value - 3);
- const rangeStart = rangeLength === 1 ? page.value : page.value - Math.ceil(rangeLength / 2) + start.value;
- return [start.value, props.ellipsis, ...createRange(rangeLength, rangeStart), props.ellipsis, length.value];
- }
- });
- // TODO: 'first' | 'prev' | 'next' | 'last' does not work here?
- function setValue(e, value, event) {
- e.preventDefault();
- page.value = value;
- event && emit(event, value);
- }
- const {
- refs,
- updateRef
- } = useRefs();
- provideDefaults({
- VPaginationBtn: {
- color: vue.toRef(props, 'color'),
- border: vue.toRef(props, 'border'),
- density: vue.toRef(props, 'density'),
- size: vue.toRef(props, 'size'),
- variant: vue.toRef(props, 'variant'),
- rounded: vue.toRef(props, 'rounded'),
- elevation: vue.toRef(props, 'elevation')
- }
- });
- const items = vue.computed(() => {
- return range.value.map((item, index) => {
- const ref = e => updateRef(e, index);
- if (typeof item === 'string') {
- return {
- isActive: false,
- key: `ellipsis-${index}`,
- page: item,
- props: {
- ref,
- ellipsis: true,
- icon: true,
- disabled: true
- }
- };
- } else {
- const isActive = item === page.value;
- return {
- isActive,
- key: item,
- page: n(item),
- props: {
- ref,
- ellipsis: false,
- icon: true,
- disabled: !!props.disabled || +props.length < 2,
- color: isActive ? props.activeColor : props.color,
- ariaCurrent: isActive,
- ariaLabel: t(isActive ? props.currentPageAriaLabel : props.pageAriaLabel, item),
- onClick: e => setValue(e, item)
- }
- };
- }
- });
- });
- const controls = vue.computed(() => {
- const prevDisabled = !!props.disabled || page.value <= start.value;
- const nextDisabled = !!props.disabled || page.value >= start.value + length.value - 1;
- return {
- first: props.showFirstLastPage ? {
- icon: isRtl.value ? props.lastIcon : props.firstIcon,
- onClick: e => setValue(e, start.value, 'first'),
- disabled: prevDisabled,
- ariaLabel: t(props.firstAriaLabel),
- ariaDisabled: prevDisabled
- } : undefined,
- prev: {
- icon: isRtl.value ? props.nextIcon : props.prevIcon,
- onClick: e => setValue(e, page.value - 1, 'prev'),
- disabled: prevDisabled,
- ariaLabel: t(props.previousAriaLabel),
- ariaDisabled: prevDisabled
- },
- next: {
- icon: isRtl.value ? props.prevIcon : props.nextIcon,
- onClick: e => setValue(e, page.value + 1, 'next'),
- disabled: nextDisabled,
- ariaLabel: t(props.nextAriaLabel),
- ariaDisabled: nextDisabled
- },
- last: props.showFirstLastPage ? {
- icon: isRtl.value ? props.firstIcon : props.lastIcon,
- onClick: e => setValue(e, start.value + length.value - 1, 'last'),
- disabled: nextDisabled,
- ariaLabel: t(props.lastAriaLabel),
- ariaDisabled: nextDisabled
- } : undefined
- };
- });
- function updateFocus() {
- const currentIndex = page.value - start.value;
- refs.value[currentIndex]?.$el.focus();
- }
- function onKeydown(e) {
- if (e.key === keyValues.left && !props.disabled && page.value > +props.start) {
- page.value = page.value - 1;
- vue.nextTick(updateFocus);
- } else if (e.key === keyValues.right && !props.disabled && page.value < start.value + length.value - 1) {
- page.value = page.value + 1;
- vue.nextTick(updateFocus);
- }
- }
- useRender(() => vue.createVNode(props.tag, {
- "ref": resizeRef,
- "class": ['v-pagination', themeClasses.value, props.class],
- "style": props.style,
- "role": "navigation",
- "aria-label": t(props.ariaLabel),
- "onKeydown": onKeydown,
- "data-test": "v-pagination-root"
- }, {
- default: () => [vue.createVNode("ul", {
- "class": "v-pagination__list"
- }, [props.showFirstLastPage && vue.createVNode("li", {
- "key": "first",
- "class": "v-pagination__first",
- "data-test": "v-pagination-first"
- }, [slots.first ? slots.first(controls.value.first) : vue.createVNode(VBtn, vue.mergeProps({
- "_as": "VPaginationBtn"
- }, controls.value.first), null)]), vue.createVNode("li", {
- "key": "prev",
- "class": "v-pagination__prev",
- "data-test": "v-pagination-prev"
- }, [slots.prev ? slots.prev(controls.value.prev) : vue.createVNode(VBtn, vue.mergeProps({
- "_as": "VPaginationBtn"
- }, controls.value.prev), null)]), items.value.map((item, index) => vue.createVNode("li", {
- "key": item.key,
- "class": ['v-pagination__item', {
- 'v-pagination__item--is-active': item.isActive
- }],
- "data-test": "v-pagination-item"
- }, [slots.item ? slots.item(item) : vue.createVNode(VBtn, vue.mergeProps({
- "_as": "VPaginationBtn"
- }, item.props), {
- default: () => [item.page]
- })])), vue.createVNode("li", {
- "key": "next",
- "class": "v-pagination__next",
- "data-test": "v-pagination-next"
- }, [slots.next ? slots.next(controls.value.next) : vue.createVNode(VBtn, vue.mergeProps({
- "_as": "VPaginationBtn"
- }, controls.value.next), null)]), props.showFirstLastPage && vue.createVNode("li", {
- "key": "last",
- "class": "v-pagination__last",
- "data-test": "v-pagination-last"
- }, [slots.last ? slots.last(controls.value.last) : vue.createVNode(VBtn, vue.mergeProps({
- "_as": "VPaginationBtn"
- }, controls.value.last), null)])])]
- }));
- return {};
- }
- });
- // Types
- function floor(val) {
- return Math.floor(Math.abs(val)) * Math.sign(val);
- }
- const makeVParallaxProps = propsFactory({
- scale: {
- type: [Number, String],
- default: 0.5
- },
- ...makeComponentProps()
- }, 'VParallax');
- const VParallax = genericComponent()({
- name: 'VParallax',
- props: makeVParallaxProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- intersectionRef,
- isIntersecting
- } = useIntersectionObserver();
- const {
- resizeRef,
- contentRect
- } = useResizeObserver();
- const {
- height: displayHeight
- } = useDisplay();
- const root = vue.ref();
- vue.watchEffect(() => {
- intersectionRef.value = resizeRef.value = root.value?.$el;
- });
- let scrollParent;
- vue.watch(isIntersecting, val => {
- if (val) {
- scrollParent = getScrollParent(intersectionRef.value);
- scrollParent = scrollParent === document.scrollingElement ? document : scrollParent;
- scrollParent.addEventListener('scroll', onScroll, {
- passive: true
- });
- onScroll();
- } else {
- scrollParent.removeEventListener('scroll', onScroll);
- }
- });
- vue.onBeforeUnmount(() => {
- scrollParent?.removeEventListener('scroll', onScroll);
- });
- vue.watch(displayHeight, onScroll);
- vue.watch(() => contentRect.value?.height, onScroll);
- const scale = vue.computed(() => {
- return 1 - clamp(+props.scale);
- });
- let frame = -1;
- function onScroll() {
- if (!isIntersecting.value) return;
- cancelAnimationFrame(frame);
- frame = requestAnimationFrame(() => {
- const el = (root.value?.$el).querySelector('.v-img__img');
- if (!el) return;
- const scrollHeight = scrollParent instanceof Document ? document.documentElement.clientHeight : scrollParent.clientHeight;
- const scrollPos = scrollParent instanceof Document ? window.scrollY : scrollParent.scrollTop;
- const top = intersectionRef.value.getBoundingClientRect().top + scrollPos;
- const height = contentRect.value.height;
- const center = top + (height - scrollHeight) / 2;
- const translate = floor((scrollPos - center) * scale.value);
- const sizeScale = Math.max(1, (scale.value * (scrollHeight - height) + height) / height);
- el.style.setProperty('transform', `translateY(${translate}px) scale(${sizeScale})`);
- });
- }
- useRender(() => vue.createVNode(VImg, {
- "class": ['v-parallax', {
- 'v-parallax--active': isIntersecting.value
- }, props.class],
- "style": props.style,
- "ref": root,
- "cover": true,
- "onLoadstart": onScroll,
- "onLoad": onScroll
- }, slots));
- return {};
- }
- });
- // Types
- const makeVRadioProps = propsFactory({
- ...makeVSelectionControlProps({
- falseIcon: '$radioOff',
- trueIcon: '$radioOn'
- })
- }, 'VRadio');
- const VRadio = genericComponent()({
- name: 'VRadio',
- props: makeVRadioProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode(VSelectionControl, vue.mergeProps(props, {
- "class": ['v-radio', props.class],
- "style": props.style,
- "type": "radio"
- }), slots));
- return {};
- }
- });
- // Types
- const makeVRadioGroupProps = propsFactory({
- height: {
- type: [Number, String],
- default: 'auto'
- },
- ...makeVInputProps(),
- ...omit(makeSelectionControlGroupProps(), ['multiple']),
- trueIcon: {
- type: IconValue,
- default: '$radioOn'
- },
- falseIcon: {
- type: IconValue,
- default: '$radioOff'
- },
- type: {
- type: String,
- default: 'radio'
- }
- }, 'VRadioGroup');
- const VRadioGroup = genericComponent()({
- name: 'VRadioGroup',
- inheritAttrs: false,
- props: makeVRadioGroupProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const uid = getUid();
- const id = vue.computed(() => props.id || `radio-group-${uid}`);
- const model = useProxiedModel(props, 'modelValue');
- useRender(() => {
- const [inputAttrs, controlAttrs] = filterInputAttrs(attrs);
- const [inputProps, _1] = VInput.filterProps(props);
- const [controlProps, _2] = VSelectionControl.filterProps(props);
- const label = slots.label ? slots.label({
- label: props.label,
- props: {
- for: id.value
- }
- }) : props.label;
- return vue.createVNode(VInput, vue.mergeProps({
- "class": ['v-radio-group', props.class],
- "style": props.style
- }, inputAttrs, inputProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "id": id.value
- }), {
- ...slots,
- default: _ref2 => {
- let {
- id,
- messagesId,
- isDisabled,
- isReadonly
- } = _ref2;
- return vue.createVNode(vue.Fragment, null, [label && vue.createVNode(VLabel, {
- "id": id.value
- }, {
- default: () => [label]
- }), vue.createVNode(VSelectionControlGroup, vue.mergeProps(controlProps, {
- "id": id.value,
- "aria-describedby": messagesId.value,
- "defaultsTarget": "VRadio",
- "trueIcon": props.trueIcon,
- "falseIcon": props.falseIcon,
- "type": props.type,
- "disabled": isDisabled.value,
- "readonly": isReadonly.value,
- "aria-labelledby": label ? id.value : undefined,
- "multiple": false
- }, controlAttrs, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event
- }), slots)]);
- }
- });
- });
- return {};
- }
- });
- // Types
- const makeVRangeSliderProps = propsFactory({
- ...makeFocusProps(),
- ...makeVInputProps(),
- ...makeSliderProps(),
- strict: Boolean,
- modelValue: {
- type: Array,
- default: () => [0, 0]
- }
- }, 'VRangeSlider');
- const VRangeSlider = genericComponent()({
- name: 'VRangeSlider',
- props: makeVRangeSliderProps(),
- emits: {
- 'update:focused': value => true,
- 'update:modelValue': value => true,
- end: value => true,
- start: value => true
- },
- setup(props, _ref) {
- let {
- slots,
- emit
- } = _ref;
- const startThumbRef = vue.ref();
- const stopThumbRef = vue.ref();
- const inputRef = vue.ref();
- const {
- rtlClasses
- } = useRtl();
- function getActiveThumb(e) {
- if (!startThumbRef.value || !stopThumbRef.value) return;
- const startOffset = getOffset(e, startThumbRef.value.$el, props.direction);
- const stopOffset = getOffset(e, stopThumbRef.value.$el, props.direction);
- const a = Math.abs(startOffset);
- const b = Math.abs(stopOffset);
- return a < b || a === b && startOffset < 0 ? startThumbRef.value.$el : stopThumbRef.value.$el;
- }
- const steps = useSteps(props);
- const model = useProxiedModel(props, 'modelValue', undefined, arr => {
- if (!arr?.length) return [0, 0];
- return arr.map(value => steps.roundValue(value));
- });
- const {
- activeThumbRef,
- hasLabels,
- max,
- min,
- mousePressed,
- onSliderMousedown,
- onSliderTouchstart,
- position,
- trackContainerRef
- } = useSlider({
- props,
- steps,
- onSliderStart: () => {
- emit('start', model.value);
- },
- onSliderEnd: _ref2 => {
- let {
- value
- } = _ref2;
- const newValue = activeThumbRef.value === startThumbRef.value?.$el ? [value, model.value[1]] : [model.value[0], value];
- if (!props.strict && newValue[0] < newValue[1]) {
- model.value = newValue;
- }
- emit('end', model.value);
- },
- onSliderMove: _ref3 => {
- let {
- value
- } = _ref3;
- const [start, stop] = model.value;
- if (!props.strict && start === stop && start !== min.value) {
- activeThumbRef.value = value > start ? stopThumbRef.value?.$el : startThumbRef.value?.$el;
- activeThumbRef.value?.focus();
- }
- if (activeThumbRef.value === startThumbRef.value?.$el) {
- model.value = [Math.min(value, stop), stop];
- } else {
- model.value = [start, Math.max(start, value)];
- }
- },
- getActiveThumb
- });
- const {
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const trackStart = vue.computed(() => position(model.value[0]));
- const trackStop = vue.computed(() => position(model.value[1]));
- useRender(() => {
- const [inputProps, _] = VInput.filterProps(props);
- const hasPrepend = !!(props.label || slots.label || slots.prepend);
- return vue.createVNode(VInput, vue.mergeProps({
- "class": ['v-slider', 'v-range-slider', {
- 'v-slider--has-labels': !!slots['tick-label'] || hasLabels.value,
- 'v-slider--focused': isFocused.value,
- 'v-slider--pressed': mousePressed.value,
- 'v-slider--disabled': props.disabled
- }, rtlClasses.value, props.class],
- "style": props.style,
- "ref": inputRef
- }, inputProps, {
- "focused": isFocused.value
- }), {
- ...slots,
- prepend: hasPrepend ? slotProps => vue.createVNode(vue.Fragment, null, [slots.label?.(slotProps) ?? props.label ? vue.createVNode(VLabel, {
- "class": "v-slider__label",
- "text": props.label
- }, null) : undefined, slots.prepend?.(slotProps)]) : undefined,
- default: _ref4 => {
- let {
- id,
- messagesId
- } = _ref4;
- return vue.createVNode("div", {
- "class": "v-slider__container",
- "onMousedown": onSliderMousedown,
- "onTouchstartPassive": onSliderTouchstart
- }, [vue.createVNode("input", {
- "id": `${id.value}_start`,
- "name": props.name || id.value,
- "disabled": !!props.disabled,
- "readonly": !!props.readonly,
- "tabindex": "-1",
- "value": model.value[0]
- }, null), vue.createVNode("input", {
- "id": `${id.value}_stop`,
- "name": props.name || id.value,
- "disabled": !!props.disabled,
- "readonly": !!props.readonly,
- "tabindex": "-1",
- "value": model.value[1]
- }, null), vue.createVNode(VSliderTrack, {
- "ref": trackContainerRef,
- "start": trackStart.value,
- "stop": trackStop.value
- }, {
- 'tick-label': slots['tick-label']
- }), vue.createVNode(VSliderThumb, {
- "ref": startThumbRef,
- "aria-describedby": messagesId.value,
- "focused": isFocused && activeThumbRef.value === startThumbRef.value?.$el,
- "modelValue": model.value[0],
- "onUpdate:modelValue": v => model.value = [v, model.value[1]],
- "onFocus": e => {
- focus();
- activeThumbRef.value = startThumbRef.value?.$el;
- // Make sure second thumb is focused if
- // the thumbs are on top of each other
- // and they are both at minimum value
- // but only if focused from outside.
- if (model.value[0] === model.value[1] && model.value[1] === min.value && e.relatedTarget !== stopThumbRef.value?.$el) {
- startThumbRef.value?.$el.blur();
- stopThumbRef.value?.$el.focus();
- }
- },
- "onBlur": () => {
- blur();
- activeThumbRef.value = undefined;
- },
- "min": min.value,
- "max": model.value[1],
- "position": trackStart.value
- }, {
- 'thumb-label': slots['thumb-label']
- }), vue.createVNode(VSliderThumb, {
- "ref": stopThumbRef,
- "aria-describedby": messagesId.value,
- "focused": isFocused && activeThumbRef.value === stopThumbRef.value?.$el,
- "modelValue": model.value[1],
- "onUpdate:modelValue": v => model.value = [model.value[0], v],
- "onFocus": e => {
- focus();
- activeThumbRef.value = stopThumbRef.value?.$el;
- // Make sure first thumb is focused if
- // the thumbs are on top of each other
- // and they are both at maximum value
- // but only if focused from outside.
- if (model.value[0] === model.value[1] && model.value[0] === max.value && e.relatedTarget !== startThumbRef.value?.$el) {
- stopThumbRef.value?.$el.blur();
- startThumbRef.value?.$el.focus();
- }
- },
- "onBlur": () => {
- blur();
- activeThumbRef.value = undefined;
- },
- "min": model.value[0],
- "max": max.value,
- "position": trackStop.value
- }, {
- 'thumb-label': slots['thumb-label']
- })]);
- }
- });
- });
- return {};
- }
- });
- // Types
- const makeVRatingProps = propsFactory({
- name: String,
- itemAriaLabel: {
- type: String,
- default: '$vuetify.rating.ariaLabel.item'
- },
- activeColor: String,
- color: String,
- clearable: Boolean,
- disabled: Boolean,
- emptyIcon: {
- type: IconValue,
- default: '$ratingEmpty'
- },
- fullIcon: {
- type: IconValue,
- default: '$ratingFull'
- },
- halfIncrements: Boolean,
- hover: Boolean,
- length: {
- type: [Number, String],
- default: 5
- },
- readonly: Boolean,
- modelValue: {
- type: [Number, String],
- default: 0
- },
- itemLabels: Array,
- itemLabelPosition: {
- type: String,
- default: 'top',
- validator: v => ['top', 'bottom'].includes(v)
- },
- ripple: Boolean,
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeSizeProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VRating');
- const VRating = genericComponent()({
- name: 'VRating',
- props: makeVRatingProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const {
- themeClasses
- } = provideTheme(props);
- const rating = useProxiedModel(props, 'modelValue');
- const normalizedValue = vue.computed(() => clamp(parseFloat(rating.value), 0, +props.length));
- const range = vue.computed(() => createRange(Number(props.length), 1));
- const increments = vue.computed(() => range.value.flatMap(v => props.halfIncrements ? [v - 0.5, v] : [v]));
- const hoverIndex = vue.shallowRef(-1);
- const itemState = vue.computed(() => increments.value.map(value => {
- const isHovering = props.hover && hoverIndex.value > -1;
- const isFilled = normalizedValue.value >= value;
- const isHovered = hoverIndex.value >= value;
- const isFullIcon = isHovering ? isHovered : isFilled;
- const icon = isFullIcon ? props.fullIcon : props.emptyIcon;
- const activeColor = props.activeColor ?? props.color;
- const color = isFilled || isHovered ? activeColor : props.color;
- return {
- isFilled,
- isHovered,
- icon,
- color
- };
- }));
- const eventState = vue.computed(() => [0, ...increments.value].map(value => {
- function onMouseenter() {
- hoverIndex.value = value;
- }
- function onMouseleave() {
- hoverIndex.value = -1;
- }
- function onClick() {
- if (props.disabled || props.readonly) return;
- rating.value = normalizedValue.value === value && props.clearable ? 0 : value;
- }
- return {
- onMouseenter: props.hover ? onMouseenter : undefined,
- onMouseleave: props.hover ? onMouseleave : undefined,
- onClick
- };
- }));
- const name = vue.computed(() => props.name ?? `v-rating-${getUid()}`);
- function VRatingItem(_ref2) {
- let {
- value,
- index,
- showStar = true
- } = _ref2;
- const {
- onMouseenter,
- onMouseleave,
- onClick
- } = eventState.value[index + 1];
- const id = `${name.value}-${String(value).replace('.', '-')}`;
- const btnProps = {
- color: itemState.value[index]?.color,
- density: props.density,
- disabled: props.disabled,
- icon: itemState.value[index]?.icon,
- ripple: props.ripple,
- size: props.size,
- variant: 'plain'
- };
- return vue.createVNode(vue.Fragment, null, [vue.createVNode("label", {
- "for": id,
- "class": {
- 'v-rating__item--half': props.halfIncrements && value % 1 > 0,
- 'v-rating__item--full': props.halfIncrements && value % 1 === 0
- },
- "onMouseenter": onMouseenter,
- "onMouseleave": onMouseleave,
- "onClick": onClick
- }, [vue.createVNode("span", {
- "class": "v-rating__hidden"
- }, [t(props.itemAriaLabel, value, props.length)]), !showStar ? undefined : slots.item ? slots.item({
- ...itemState.value[index],
- props: btnProps,
- value,
- index,
- rating: normalizedValue.value
- }) : vue.createVNode(VBtn, vue.mergeProps({
- "aria-label": t(props.itemAriaLabel, value, props.length)
- }, btnProps), null)]), vue.createVNode("input", {
- "class": "v-rating__hidden",
- "name": name.value,
- "id": id,
- "type": "radio",
- "value": value,
- "checked": normalizedValue.value === value,
- "tabindex": -1,
- "readonly": props.readonly,
- "disabled": props.disabled
- }, null)]);
- }
- function createLabel(labelProps) {
- if (slots['item-label']) return slots['item-label'](labelProps);
- if (labelProps.label) return vue.createVNode("span", null, [labelProps.label]);
- return vue.createVNode("span", null, [vue.createTextVNode("\xA0")]);
- }
- useRender(() => {
- const hasLabels = !!props.itemLabels?.length || slots['item-label'];
- return vue.createVNode(props.tag, {
- "class": ['v-rating', {
- 'v-rating--hover': props.hover,
- 'v-rating--readonly': props.readonly
- }, themeClasses.value, props.class],
- "style": props.style
- }, {
- default: () => [vue.createVNode(VRatingItem, {
- "value": 0,
- "index": -1,
- "showStar": false
- }, null), range.value.map((value, i) => vue.createVNode("div", {
- "class": "v-rating__wrapper"
- }, [hasLabels && props.itemLabelPosition === 'top' ? createLabel({
- value,
- index: i,
- label: props.itemLabels?.[i]
- }) : undefined, vue.createVNode("div", {
- "class": "v-rating__item"
- }, [props.halfIncrements ? vue.createVNode(vue.Fragment, null, [vue.createVNode(VRatingItem, {
- "value": value - 0.5,
- "index": i * 2
- }, null), vue.createVNode(VRatingItem, {
- "value": value,
- "index": i * 2 + 1
- }, null)]) : vue.createVNode(VRatingItem, {
- "value": value,
- "index": i
- }, null)]), hasLabels && props.itemLabelPosition === 'bottom' ? createLabel({
- value,
- index: i,
- label: props.itemLabels?.[i]
- }) : undefined]))]
- });
- });
- return {};
- }
- });
- function bias(val) {
- const c = 0.501;
- const x = Math.abs(val);
- return Math.sign(val) * (x / ((1 / c - 2) * (1 - x) + 1));
- }
- function calculateUpdatedOffset(_ref) {
- let {
- selectedElement,
- containerSize,
- contentSize,
- isRtl,
- currentScrollOffset,
- isHorizontal
- } = _ref;
- const clientSize = isHorizontal ? selectedElement.clientWidth : selectedElement.clientHeight;
- const offsetStart = isHorizontal ? selectedElement.offsetLeft : selectedElement.offsetTop;
- const adjustedOffsetStart = isRtl && isHorizontal ? contentSize - offsetStart - clientSize : offsetStart;
- const totalSize = containerSize + currentScrollOffset;
- const itemOffset = clientSize + adjustedOffsetStart;
- const additionalOffset = clientSize * 0.4;
- if (adjustedOffsetStart <= currentScrollOffset) {
- currentScrollOffset = Math.max(adjustedOffsetStart - additionalOffset, 0);
- } else if (totalSize <= itemOffset) {
- currentScrollOffset = Math.min(currentScrollOffset - (totalSize - itemOffset - additionalOffset), contentSize - containerSize);
- }
- return currentScrollOffset;
- }
- function calculateCenteredOffset(_ref2) {
- let {
- selectedElement,
- containerSize,
- contentSize,
- isRtl,
- isHorizontal
- } = _ref2;
- const clientSize = isHorizontal ? selectedElement.clientWidth : selectedElement.clientHeight;
- const offsetStart = isHorizontal ? selectedElement.offsetLeft : selectedElement.offsetTop;
- const offsetCentered = isRtl && isHorizontal ? contentSize - offsetStart - clientSize / 2 - containerSize / 2 : offsetStart + clientSize / 2 - containerSize / 2;
- return Math.min(contentSize - containerSize, Math.max(0, offsetCentered));
- }
- // Types
- const VSlideGroupSymbol = Symbol.for('vuetify:v-slide-group');
- const makeVSlideGroupProps = propsFactory({
- centerActive: Boolean,
- direction: {
- type: String,
- default: 'horizontal'
- },
- symbol: {
- type: null,
- default: VSlideGroupSymbol
- },
- nextIcon: {
- type: IconValue,
- default: '$next'
- },
- prevIcon: {
- type: IconValue,
- default: '$prev'
- },
- showArrows: {
- type: [Boolean, String],
- validator: v => typeof v === 'boolean' || ['always', 'desktop', 'mobile'].includes(v)
- },
- ...makeComponentProps(),
- ...makeTagProps(),
- ...makeGroupProps({
- selectedClass: 'v-slide-group-item--active'
- })
- }, 'VSlideGroup');
- const VSlideGroup = genericComponent()({
- name: 'VSlideGroup',
- props: makeVSlideGroupProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- isRtl
- } = useRtl();
- const {
- mobile
- } = useDisplay();
- const group = useGroup(props, props.symbol);
- const isOverflowing = vue.shallowRef(false);
- const scrollOffset = vue.shallowRef(0);
- const containerSize = vue.shallowRef(0);
- const contentSize = vue.shallowRef(0);
- const isHorizontal = vue.computed(() => props.direction === 'horizontal');
- const {
- resizeRef: containerRef,
- contentRect: containerRect
- } = useResizeObserver();
- const {
- resizeRef: contentRef,
- contentRect
- } = useResizeObserver();
- const firstSelectedIndex = vue.computed(() => {
- if (!group.selected.value.length) return -1;
- return group.items.value.findIndex(item => item.id === group.selected.value[0]);
- });
- const lastSelectedIndex = vue.computed(() => {
- if (!group.selected.value.length) return -1;
- return group.items.value.findIndex(item => item.id === group.selected.value[group.selected.value.length - 1]);
- });
- if (IN_BROWSER) {
- let frame = -1;
- vue.watch(() => [group.selected.value, containerRect.value, contentRect.value, isHorizontal.value], () => {
- cancelAnimationFrame(frame);
- frame = requestAnimationFrame(() => {
- if (containerRect.value && contentRect.value) {
- const sizeProperty = isHorizontal.value ? 'width' : 'height';
- containerSize.value = containerRect.value[sizeProperty];
- contentSize.value = contentRect.value[sizeProperty];
- isOverflowing.value = containerSize.value + 1 < contentSize.value;
- }
- if (firstSelectedIndex.value >= 0 && contentRef.value) {
- // TODO: Is this too naive? Should we store element references in group composable?
- const selectedElement = contentRef.value.children[lastSelectedIndex.value];
- if (firstSelectedIndex.value === 0 || !isOverflowing.value) {
- scrollOffset.value = 0;
- } else if (props.centerActive) {
- scrollOffset.value = calculateCenteredOffset({
- selectedElement,
- containerSize: containerSize.value,
- contentSize: contentSize.value,
- isRtl: isRtl.value,
- isHorizontal: isHorizontal.value
- });
- } else if (isOverflowing.value) {
- scrollOffset.value = calculateUpdatedOffset({
- selectedElement,
- containerSize: containerSize.value,
- contentSize: contentSize.value,
- isRtl: isRtl.value,
- currentScrollOffset: scrollOffset.value,
- isHorizontal: isHorizontal.value
- });
- }
- }
- });
- });
- }
- const disableTransition = vue.shallowRef(false);
- let startTouch = 0;
- let startOffset = 0;
- function onTouchstart(e) {
- const sizeProperty = isHorizontal.value ? 'clientX' : 'clientY';
- const sign = isRtl.value && isHorizontal.value ? -1 : 1;
- startOffset = sign * scrollOffset.value;
- startTouch = e.touches[0][sizeProperty];
- disableTransition.value = true;
- }
- function onTouchmove(e) {
- if (!isOverflowing.value) return;
- const sizeProperty = isHorizontal.value ? 'clientX' : 'clientY';
- const sign = isRtl.value && isHorizontal.value ? -1 : 1;
- scrollOffset.value = sign * (startOffset + startTouch - e.touches[0][sizeProperty]);
- }
- function onTouchend(e) {
- const maxScrollOffset = contentSize.value - containerSize.value;
- if (scrollOffset.value < 0 || !isOverflowing.value) {
- scrollOffset.value = 0;
- } else if (scrollOffset.value >= maxScrollOffset) {
- scrollOffset.value = maxScrollOffset;
- }
- disableTransition.value = false;
- }
- function onScroll() {
- if (!containerRef.value) return;
- containerRef.value[isHorizontal.value ? 'scrollLeft' : 'scrollTop'] = 0;
- }
- const isFocused = vue.shallowRef(false);
- function onFocusin(e) {
- isFocused.value = true;
- if (!isOverflowing.value || !contentRef.value) return;
- // Focused element is likely to be the root of an item, so a
- // breadth-first search will probably find it in the first iteration
- for (const el of e.composedPath()) {
- for (const item of contentRef.value.children) {
- if (item === el) {
- scrollOffset.value = calculateUpdatedOffset({
- selectedElement: item,
- containerSize: containerSize.value,
- contentSize: contentSize.value,
- isRtl: isRtl.value,
- currentScrollOffset: scrollOffset.value,
- isHorizontal: isHorizontal.value
- });
- return;
- }
- }
- }
- }
- function onFocusout(e) {
- isFocused.value = false;
- }
- function onFocus(e) {
- if (!isFocused.value && !(e.relatedTarget && contentRef.value?.contains(e.relatedTarget))) focus();
- }
- function onKeydown(e) {
- if (!contentRef.value) return;
- if (isHorizontal.value) {
- if (e.key === 'ArrowRight') {
- focus(isRtl.value ? 'prev' : 'next');
- } else if (e.key === 'ArrowLeft') {
- focus(isRtl.value ? 'next' : 'prev');
- }
- } else {
- if (e.key === 'ArrowDown') {
- focus('next');
- } else if (e.key === 'ArrowUp') {
- focus('prev');
- }
- }
- if (e.key === 'Home') {
- focus('first');
- } else if (e.key === 'End') {
- focus('last');
- }
- }
- function focus(location) {
- if (!contentRef.value) return;
- if (!location) {
- const focusable = focusableChildren(contentRef.value);
- focusable[0]?.focus();
- } else if (location === 'next') {
- const el = contentRef.value.querySelector(':focus')?.nextElementSibling;
- if (el) el.focus();else focus('first');
- } else if (location === 'prev') {
- const el = contentRef.value.querySelector(':focus')?.previousElementSibling;
- if (el) el.focus();else focus('last');
- } else if (location === 'first') {
- contentRef.value.firstElementChild?.focus();
- } else if (location === 'last') {
- contentRef.value.lastElementChild?.focus();
- }
- }
- function scrollTo(location) {
- const newAbsoluteOffset = scrollOffset.value + (location === 'prev' ? -1 : 1) * containerSize.value;
- scrollOffset.value = clamp(newAbsoluteOffset, 0, contentSize.value - containerSize.value);
- }
- const contentStyles = vue.computed(() => {
- // This adds friction when scrolling the 'wrong' way when at max offset
- let scrollAmount = scrollOffset.value > contentSize.value - containerSize.value ? -(contentSize.value - containerSize.value) + bias(contentSize.value - containerSize.value - scrollOffset.value) : -scrollOffset.value;
- // This adds friction when scrolling the 'wrong' way when at min offset
- if (scrollOffset.value <= 0) {
- scrollAmount = bias(-scrollOffset.value);
- }
- const sign = isRtl.value && isHorizontal.value ? -1 : 1;
- return {
- transform: `translate${isHorizontal.value ? 'X' : 'Y'}(${sign * scrollAmount}px)`,
- transition: disableTransition.value ? 'none' : '',
- willChange: disableTransition.value ? 'transform' : ''
- };
- });
- const slotProps = vue.computed(() => ({
- next: group.next,
- prev: group.prev,
- select: group.select,
- isSelected: group.isSelected
- }));
- const hasAffixes = vue.computed(() => {
- switch (props.showArrows) {
- // Always show arrows on desktop & mobile
- case 'always':
- return true;
- // Always show arrows on desktop
- case 'desktop':
- return !mobile.value;
- // Show arrows on mobile when overflowing.
- // This matches the default 2.2 behavior
- case true:
- return isOverflowing.value || Math.abs(scrollOffset.value) > 0;
- // Always show on mobile
- case 'mobile':
- return mobile.value || isOverflowing.value || Math.abs(scrollOffset.value) > 0;
- // https://material.io/components/tabs#scrollable-tabs
- // Always show arrows when
- // overflowed on desktop
- default:
- return !mobile.value && (isOverflowing.value || Math.abs(scrollOffset.value) > 0);
- }
- });
- const hasPrev = vue.computed(() => {
- return Math.abs(scrollOffset.value) > 0;
- });
- const hasNext = vue.computed(() => {
- // Check one scroll ahead to know the width of right-most item
- return contentSize.value > Math.abs(scrollOffset.value) + containerSize.value;
- });
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-slide-group', {
- 'v-slide-group--vertical': !isHorizontal.value,
- 'v-slide-group--has-affixes': hasAffixes.value,
- 'v-slide-group--is-overflowing': isOverflowing.value
- }, props.class],
- "style": props.style,
- "tabindex": isFocused.value || group.selected.value.length ? -1 : 0,
- "onFocus": onFocus
- }, {
- default: () => [hasAffixes.value && vue.createVNode("div", {
- "key": "prev",
- "class": ['v-slide-group__prev', {
- 'v-slide-group__prev--disabled': !hasPrev.value
- }],
- "onClick": () => scrollTo('prev')
- }, [slots.prev?.(slotProps.value) ?? vue.createVNode(VFadeTransition, null, {
- default: () => [vue.createVNode(VIcon, {
- "icon": isRtl.value ? props.nextIcon : props.prevIcon
- }, null)]
- })]), vue.createVNode("div", {
- "key": "container",
- "ref": containerRef,
- "class": "v-slide-group__container",
- "onScroll": onScroll
- }, [vue.createVNode("div", {
- "ref": contentRef,
- "class": "v-slide-group__content",
- "style": contentStyles.value,
- "onTouchstartPassive": onTouchstart,
- "onTouchmovePassive": onTouchmove,
- "onTouchendPassive": onTouchend,
- "onFocusin": onFocusin,
- "onFocusout": onFocusout,
- "onKeydown": onKeydown
- }, [slots.default?.(slotProps.value)])]), hasAffixes.value && vue.createVNode("div", {
- "key": "next",
- "class": ['v-slide-group__next', {
- 'v-slide-group__next--disabled': !hasNext.value
- }],
- "onClick": () => scrollTo('next')
- }, [slots.next?.(slotProps.value) ?? vue.createVNode(VFadeTransition, null, {
- default: () => [vue.createVNode(VIcon, {
- "icon": isRtl.value ? props.prevIcon : props.nextIcon
- }, null)]
- })])]
- }));
- return {
- selected: group.selected,
- scrollTo,
- scrollOffset,
- focus
- };
- }
- });
- // Composables
- // Types
- const VSlideGroupItem = genericComponent()({
- name: 'VSlideGroupItem',
- props: makeGroupItemProps(),
- emits: {
- 'group:selected': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const slideGroupItem = useGroupItem(props, VSlideGroupSymbol);
- return () => slots.default?.({
- isSelected: slideGroupItem.isSelected.value,
- select: slideGroupItem.select,
- toggle: slideGroupItem.toggle,
- selectedClass: slideGroupItem.selectedClass.value
- });
- }
- });
- const makeVSnackbarProps = propsFactory({
- multiLine: Boolean,
- timeout: {
- type: [Number, String],
- default: 5000
- },
- vertical: Boolean,
- ...makeLocationProps({
- location: 'bottom'
- }),
- ...makePositionProps(),
- ...makeRoundedProps(),
- ...makeVariantProps(),
- ...makeThemeProps(),
- ...omit(makeVOverlayProps({
- transition: 'v-snackbar-transition'
- }), ['persistent', 'noClickAnimation', 'scrim', 'scrollStrategy'])
- }, 'VSnackbar');
- const VSnackbar = genericComponent()({
- name: 'VSnackbar',
- props: makeVSnackbarProps(),
- emits: {
- 'update:modelValue': v => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const isActive = useProxiedModel(props, 'modelValue');
- const {
- locationStyles
- } = useLocation(props);
- const {
- positionClasses
- } = usePosition(props);
- const {
- scopeId
- } = useScopeId();
- const {
- themeClasses
- } = provideTheme(props);
- const {
- colorClasses,
- colorStyles,
- variantClasses
- } = useVariant(props);
- const {
- roundedClasses
- } = useRounded(props);
- const overlay = vue.ref();
- vue.watch(isActive, startTimeout);
- vue.watch(() => props.timeout, startTimeout);
- vue.onMounted(() => {
- if (isActive.value) startTimeout();
- });
- let activeTimeout = -1;
- function startTimeout() {
- window.clearTimeout(activeTimeout);
- const timeout = Number(props.timeout);
- if (!isActive.value || timeout === -1) return;
- activeTimeout = window.setTimeout(() => {
- isActive.value = false;
- }, timeout);
- }
- function onPointerenter() {
- window.clearTimeout(activeTimeout);
- }
- useRender(() => {
- const [overlayProps] = VOverlay.filterProps(props);
- return vue.createVNode(VOverlay, vue.mergeProps({
- "ref": overlay,
- "class": ['v-snackbar', {
- 'v-snackbar--active': isActive.value,
- 'v-snackbar--multi-line': props.multiLine && !props.vertical,
- 'v-snackbar--vertical': props.vertical
- }, positionClasses.value, props.class],
- "style": props.style
- }, overlayProps, {
- "modelValue": isActive.value,
- "onUpdate:modelValue": $event => isActive.value = $event,
- "contentProps": vue.mergeProps({
- class: ['v-snackbar__wrapper', themeClasses.value, colorClasses.value, roundedClasses.value, variantClasses.value],
- style: [locationStyles.value, colorStyles.value],
- onPointerenter,
- onPointerleave: startTimeout
- }, overlayProps.contentProps),
- "persistent": true,
- "noClickAnimation": true,
- "scrim": false,
- "scrollStrategy": "none",
- "_disableGlobalStack": true
- }, scopeId), {
- default: () => [genOverlays(false, 'v-snackbar'), slots.default && vue.createVNode("div", {
- "class": "v-snackbar__content",
- "role": "status",
- "aria-live": "polite"
- }, [slots.default()]), slots.actions && vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- variant: 'text',
- ripple: false
- }
- }
- }, {
- default: () => [vue.createVNode("div", {
- "class": "v-snackbar__actions"
- }, [slots.actions()])]
- })],
- activator: slots.activator
- });
- });
- return forwardRefs({}, overlay);
- }
- });
- // Types
- const makeVSwitchProps = propsFactory({
- indeterminate: Boolean,
- inset: Boolean,
- flat: Boolean,
- loading: {
- type: [Boolean, String],
- default: false
- },
- ...makeVInputProps(),
- ...makeVSelectionControlProps()
- }, 'VSwitch');
- const VSwitch = genericComponent()({
- name: 'VSwitch',
- inheritAttrs: false,
- props: makeVSwitchProps(),
- emits: {
- 'update:focused': focused => true,
- 'update:modelValue': () => true,
- 'update:indeterminate': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const indeterminate = useProxiedModel(props, 'indeterminate');
- const model = useProxiedModel(props, 'modelValue');
- const {
- loaderClasses
- } = useLoader(props);
- const {
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const loaderColor = vue.computed(() => {
- return typeof props.loading === 'string' && props.loading !== '' ? props.loading : props.color;
- });
- const uid = getUid();
- const id = vue.computed(() => props.id || `switch-${uid}`);
- function onChange() {
- if (indeterminate.value) {
- indeterminate.value = false;
- }
- }
- useRender(() => {
- const [inputAttrs, controlAttrs] = filterInputAttrs(attrs);
- const [inputProps, _1] = VInput.filterProps(props);
- const [controlProps, _2] = VSelectionControl.filterProps(props);
- const control = vue.ref();
- function onClick(e) {
- e.stopPropagation();
- e.preventDefault();
- control.value?.input?.click();
- }
- return vue.createVNode(VInput, vue.mergeProps({
- "class": ['v-switch', {
- 'v-switch--inset': props.inset
- }, {
- 'v-switch--indeterminate': indeterminate.value
- }, loaderClasses.value, props.class],
- "style": props.style
- }, inputAttrs, inputProps, {
- "id": id.value,
- "focused": isFocused.value
- }), {
- ...slots,
- default: _ref2 => {
- let {
- id,
- messagesId,
- isDisabled,
- isReadonly,
- isValid
- } = _ref2;
- return vue.createVNode(VSelectionControl, vue.mergeProps({
- "ref": control
- }, controlProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": [$event => model.value = $event, onChange],
- "id": id.value,
- "aria-describedby": messagesId.value,
- "type": "checkbox",
- "aria-checked": indeterminate.value ? 'mixed' : undefined,
- "disabled": isDisabled.value,
- "readonly": isReadonly.value,
- "onFocus": focus,
- "onBlur": blur
- }, controlAttrs), {
- ...slots,
- default: () => vue.createVNode("div", {
- "class": "v-switch__track",
- "onClick": onClick
- }, null),
- input: _ref3 => {
- let {
- textColorClasses,
- textColorStyles
- } = _ref3;
- return vue.createVNode("div", {
- "class": ['v-switch__thumb', textColorClasses.value],
- "style": textColorStyles.value
- }, [props.loading && vue.createVNode(LoaderSlot, {
- "name": "v-switch",
- "active": true,
- "color": isValid.value === false ? undefined : loaderColor.value
- }, {
- default: slotProps => slots.loader ? slots.loader(slotProps) : vue.createVNode(VProgressCircular, {
- "active": slotProps.isActive,
- "color": slotProps.color,
- "indeterminate": true,
- "size": "16",
- "width": "2"
- }, null)
- })]);
- }
- });
- }
- });
- });
- return {};
- }
- });
- const makeVSystemBarProps = propsFactory({
- color: String,
- height: [Number, String],
- window: Boolean,
- ...makeComponentProps(),
- ...makeElevationProps(),
- ...makeLayoutItemProps(),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VSystemBar');
- const VSystemBar = genericComponent()({
- name: 'VSystemBar',
- props: makeVSystemBarProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- const {
- elevationClasses
- } = useElevation(props);
- const {
- roundedClasses
- } = useRounded(props);
- const {
- ssrBootStyles
- } = useSsrBoot();
- const height = vue.computed(() => props.height ?? (props.window ? 32 : 24));
- const {
- layoutItemStyles
- } = useLayoutItem({
- id: props.name,
- order: vue.computed(() => parseInt(props.order, 10)),
- position: vue.shallowRef('top'),
- layoutSize: height,
- elementSize: height,
- active: vue.computed(() => true),
- absolute: vue.toRef(props, 'absolute')
- });
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-system-bar', {
- 'v-system-bar--window': props.window
- }, themeClasses.value, backgroundColorClasses.value, elevationClasses.value, roundedClasses.value, props.class],
- "style": [backgroundColorStyles.value, layoutItemStyles.value, ssrBootStyles.value, props.style]
- }, slots));
- return {};
- }
- });
- // Types
- const VTabsSymbol = Symbol.for('vuetify:v-tabs');
- // Types
- const makeVTabProps = propsFactory({
- fixed: Boolean,
- sliderColor: String,
- hideSlider: Boolean,
- direction: {
- type: String,
- default: 'horizontal'
- },
- ...omit(makeVBtnProps({
- selectedClass: 'v-tab--selected',
- variant: 'text'
- }), ['active', 'block', 'flat', 'location', 'position', 'symbol'])
- }, 'VTab');
- const VTab = genericComponent()({
- name: 'VTab',
- props: makeVTabProps(),
- setup(props, _ref) {
- let {
- slots,
- attrs
- } = _ref;
- const {
- textColorClasses: sliderColorClasses,
- textColorStyles: sliderColorStyles
- } = useTextColor(props, 'sliderColor');
- const isHorizontal = vue.computed(() => props.direction === 'horizontal');
- const isSelected = vue.shallowRef(false);
- const rootEl = vue.ref();
- const sliderEl = vue.ref();
- function updateSlider(_ref2) {
- let {
- value
- } = _ref2;
- isSelected.value = value;
- if (value) {
- const prevEl = rootEl.value?.$el.parentElement?.querySelector('.v-tab--selected .v-tab__slider');
- const nextEl = sliderEl.value;
- if (!prevEl || !nextEl) return;
- const color = getComputedStyle(prevEl).color;
- const prevBox = prevEl.getBoundingClientRect();
- const nextBox = nextEl.getBoundingClientRect();
- const xy = isHorizontal.value ? 'x' : 'y';
- const XY = isHorizontal.value ? 'X' : 'Y';
- const rightBottom = isHorizontal.value ? 'right' : 'bottom';
- const widthHeight = isHorizontal.value ? 'width' : 'height';
- const prevPos = prevBox[xy];
- const nextPos = nextBox[xy];
- const delta = prevPos > nextPos ? prevBox[rightBottom] - nextBox[rightBottom] : prevBox[xy] - nextBox[xy];
- const origin = Math.sign(delta) > 0 ? isHorizontal.value ? 'right' : 'bottom' : Math.sign(delta) < 0 ? isHorizontal.value ? 'left' : 'top' : 'center';
- const size = Math.abs(delta) + (Math.sign(delta) < 0 ? prevBox[widthHeight] : nextBox[widthHeight]);
- const scale = size / Math.max(prevBox[widthHeight], nextBox[widthHeight]);
- const initialScale = prevBox[widthHeight] / nextBox[widthHeight];
- const sigma = 1.5;
- animate(nextEl, {
- backgroundColor: [color, 'currentcolor'],
- transform: [`translate${XY}(${delta}px) scale${XY}(${initialScale})`, `translate${XY}(${delta / sigma}px) scale${XY}(${(scale - 1) / sigma + 1})`, 'none'],
- transformOrigin: Array(3).fill(origin)
- }, {
- duration: 225,
- easing: standardEasing
- });
- }
- }
- useRender(() => {
- const [btnProps] = VBtn.filterProps(props);
- return vue.createVNode(VBtn, vue.mergeProps({
- "symbol": VTabsSymbol,
- "ref": rootEl,
- "class": ['v-tab', props.class],
- "style": props.style,
- "tabindex": isSelected.value ? 0 : -1,
- "role": "tab",
- "aria-selected": String(isSelected.value),
- "active": false,
- "block": props.fixed,
- "maxWidth": props.fixed ? 300 : undefined,
- "rounded": 0
- }, btnProps, attrs, {
- "onGroup:selected": updateSlider
- }), {
- default: () => [slots.default?.() ?? props.text, !props.hideSlider && vue.createVNode("div", {
- "ref": sliderEl,
- "class": ['v-tab__slider', sliderColorClasses.value],
- "style": sliderColorStyles.value
- }, null)]
- });
- });
- return {};
- }
- });
- function parseItems(items) {
- if (!items) return [];
- return items.map(item => {
- if (typeof item === 'string') return {
- title: item,
- value: item
- };
- return item;
- });
- }
- const makeVTabsProps = propsFactory({
- alignTabs: {
- type: String,
- default: 'start'
- },
- color: String,
- fixedTabs: Boolean,
- items: {
- type: Array,
- default: () => []
- },
- stacked: Boolean,
- bgColor: String,
- grow: Boolean,
- height: {
- type: [Number, String],
- default: undefined
- },
- hideSlider: Boolean,
- sliderColor: String,
- ...makeVSlideGroupProps({
- mandatory: 'force'
- }),
- ...makeDensityProps(),
- ...makeTagProps()
- }, 'VTabs');
- const VTabs = genericComponent()({
- name: 'VTabs',
- props: makeVTabsProps(),
- emits: {
- 'update:modelValue': v => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const parsedItems = vue.computed(() => parseItems(props.items));
- const {
- densityClasses
- } = useDensity(props);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'bgColor'));
- provideDefaults({
- VTab: {
- color: vue.toRef(props, 'color'),
- direction: vue.toRef(props, 'direction'),
- stacked: vue.toRef(props, 'stacked'),
- fixed: vue.toRef(props, 'fixedTabs'),
- sliderColor: vue.toRef(props, 'sliderColor'),
- hideSlider: vue.toRef(props, 'hideSlider')
- }
- });
- useRender(() => {
- const [slideGroupProps] = VSlideGroup.filterProps(props);
- return vue.createVNode(VSlideGroup, vue.mergeProps(slideGroupProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "class": ['v-tabs', `v-tabs--${props.direction}`, `v-tabs--align-tabs-${props.alignTabs}`, {
- 'v-tabs--fixed-tabs': props.fixedTabs,
- 'v-tabs--grow': props.grow,
- 'v-tabs--stacked': props.stacked
- }, densityClasses.value, backgroundColorClasses.value, props.class],
- "style": [{
- '--v-tabs-height': convertToUnit(props.height)
- }, backgroundColorStyles.value, props.style],
- "role": "tablist",
- "symbol": VTabsSymbol
- }), {
- default: () => [slots.default ? slots.default() : parsedItems.value.map(item => vue.createVNode(VTab, vue.mergeProps(item, {
- "key": item.title
- }), null))]
- });
- });
- return {};
- }
- });
- const makeVTableProps = propsFactory({
- fixedHeader: Boolean,
- fixedFooter: Boolean,
- height: [Number, String],
- hover: Boolean,
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VTable');
- const VTable = genericComponent()({
- name: 'VTable',
- props: makeVTableProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- densityClasses
- } = useDensity(props);
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-table', {
- 'v-table--fixed-height': !!props.height,
- 'v-table--fixed-header': props.fixedHeader,
- 'v-table--fixed-footer': props.fixedFooter,
- 'v-table--has-top': !!slots.top,
- 'v-table--has-bottom': !!slots.bottom,
- 'v-table--hover': props.hover
- }, themeClasses.value, densityClasses.value, props.class],
- "style": props.style
- }, {
- default: () => [slots.top?.(), slots.default ? vue.createVNode("div", {
- "class": "v-table__wrapper",
- "style": {
- height: convertToUnit(props.height)
- }
- }, [vue.createVNode("table", null, [slots.default()])]) : slots.wrapper?.(), slots.bottom?.()]
- }));
- return {};
- }
- });
- // Types
- const makeVTextareaProps = propsFactory({
- autoGrow: Boolean,
- autofocus: Boolean,
- counter: [Boolean, Number, String],
- counterValue: Function,
- prefix: String,
- placeholder: String,
- persistentPlaceholder: Boolean,
- persistentCounter: Boolean,
- noResize: Boolean,
- rows: {
- type: [Number, String],
- default: 5,
- validator: v => !isNaN(parseFloat(v))
- },
- maxRows: {
- type: [Number, String],
- validator: v => !isNaN(parseFloat(v))
- },
- suffix: String,
- modelModifiers: Object,
- ...makeVInputProps(),
- ...makeVFieldProps()
- }, 'VTextarea');
- const VTextarea = genericComponent()({
- name: 'VTextarea',
- directives: {
- Intersect
- },
- inheritAttrs: false,
- props: makeVTextareaProps(),
- emits: {
- 'click:control': e => true,
- 'mousedown:control': e => true,
- 'update:focused': focused => true,
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- emit,
- slots
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const {
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const counterValue = vue.computed(() => {
- return typeof props.counterValue === 'function' ? props.counterValue(model.value) : (model.value || '').toString().length;
- });
- const max = vue.computed(() => {
- if (attrs.maxlength) return attrs.maxlength;
- if (!props.counter || typeof props.counter !== 'number' && typeof props.counter !== 'string') return undefined;
- return props.counter;
- });
- function onIntersect(isIntersecting, entries) {
- if (!props.autofocus || !isIntersecting) return;
- entries[0].target?.focus?.();
- }
- const vInputRef = vue.ref();
- const vFieldRef = vue.ref();
- const controlHeight = vue.shallowRef('');
- const textareaRef = vue.ref();
- const isActive = vue.computed(() => props.persistentPlaceholder || isFocused.value || props.active);
- function onFocus() {
- if (textareaRef.value !== document.activeElement) {
- textareaRef.value?.focus();
- }
- if (!isFocused.value) focus();
- }
- function onControlClick(e) {
- onFocus();
- emit('click:control', e);
- }
- function onControlMousedown(e) {
- emit('mousedown:control', e);
- }
- function onClear(e) {
- e.stopPropagation();
- onFocus();
- vue.nextTick(() => {
- model.value = '';
- callEvent(props['onClick:clear'], e);
- });
- }
- function onInput(e) {
- const el = e.target;
- model.value = el.value;
- if (props.modelModifiers?.trim) {
- const caretPosition = [el.selectionStart, el.selectionEnd];
- vue.nextTick(() => {
- el.selectionStart = caretPosition[0];
- el.selectionEnd = caretPosition[1];
- });
- }
- }
- const sizerRef = vue.ref();
- const rows = vue.ref(+props.rows);
- const isPlainOrUnderlined = vue.computed(() => ['plain', 'underlined'].includes(props.variant));
- vue.watchEffect(() => {
- if (!props.autoGrow) rows.value = +props.rows;
- });
- function calculateInputHeight() {
- if (!props.autoGrow) return;
- vue.nextTick(() => {
- if (!sizerRef.value || !vFieldRef.value) return;
- const style = getComputedStyle(sizerRef.value);
- const fieldStyle = getComputedStyle(vFieldRef.value.$el);
- const padding = parseFloat(style.getPropertyValue('--v-field-padding-top')) + parseFloat(style.getPropertyValue('--v-input-padding-top')) + parseFloat(style.getPropertyValue('--v-field-padding-bottom'));
- const height = sizerRef.value.scrollHeight;
- const lineHeight = parseFloat(style.lineHeight);
- const minHeight = Math.max(parseFloat(props.rows) * lineHeight + padding, parseFloat(fieldStyle.getPropertyValue('--v-input-control-height')));
- const maxHeight = parseFloat(props.maxRows) * lineHeight + padding || Infinity;
- const newHeight = clamp(height ?? 0, minHeight, maxHeight);
- rows.value = Math.floor((newHeight - padding) / lineHeight);
- controlHeight.value = convertToUnit(newHeight);
- });
- }
- vue.onMounted(calculateInputHeight);
- vue.watch(model, calculateInputHeight);
- vue.watch(() => props.rows, calculateInputHeight);
- vue.watch(() => props.maxRows, calculateInputHeight);
- vue.watch(() => props.density, calculateInputHeight);
- let observer;
- vue.watch(sizerRef, val => {
- if (val) {
- observer = new ResizeObserver(calculateInputHeight);
- observer.observe(sizerRef.value);
- } else {
- observer?.disconnect();
- }
- });
- vue.onBeforeUnmount(() => {
- observer?.disconnect();
- });
- useRender(() => {
- const hasCounter = !!(slots.counter || props.counter || props.counterValue);
- const hasDetails = !!(hasCounter || slots.details);
- const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
- const [{
- modelValue: _,
- ...inputProps
- }] = VInput.filterProps(props);
- const [fieldProps] = filterFieldProps(props);
- return vue.createVNode(VInput, vue.mergeProps({
- "ref": vInputRef,
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "class": ['v-textarea v-text-field', {
- 'v-textarea--prefixed': props.prefix,
- 'v-textarea--suffixed': props.suffix,
- 'v-text-field--prefixed': props.prefix,
- 'v-text-field--suffixed': props.suffix,
- 'v-textarea--auto-grow': props.autoGrow,
- 'v-textarea--no-resize': props.noResize || props.autoGrow,
- 'v-text-field--plain-underlined': isPlainOrUnderlined.value
- }, props.class],
- "style": props.style
- }, rootAttrs, inputProps, {
- "centerAffix": rows.value === 1 && !isPlainOrUnderlined.value,
- "focused": isFocused.value
- }), {
- ...slots,
- default: _ref2 => {
- let {
- isDisabled,
- isDirty,
- isReadonly,
- isValid
- } = _ref2;
- return vue.createVNode(VField, vue.mergeProps({
- "ref": vFieldRef,
- "style": {
- '--v-textarea-control-height': controlHeight.value
- },
- "onClick": onControlClick,
- "onMousedown": onControlMousedown,
- "onClick:clear": onClear,
- "onClick:prependInner": props['onClick:prependInner'],
- "onClick:appendInner": props['onClick:appendInner'],
- "role": "textbox"
- }, fieldProps, {
- "active": isActive.value || isDirty.value,
- "centerAffix": rows.value === 1 && !isPlainOrUnderlined.value,
- "dirty": isDirty.value || props.dirty,
- "disabled": isDisabled.value,
- "focused": isFocused.value,
- "error": isValid.value === false
- }), {
- ...slots,
- default: _ref3 => {
- let {
- props: {
- class: fieldClass,
- ...slotProps
- }
- } = _ref3;
- return vue.createVNode(vue.Fragment, null, [props.prefix && vue.createVNode("span", {
- "class": "v-text-field__prefix"
- }, [props.prefix]), vue.withDirectives(vue.createVNode("textarea", vue.mergeProps({
- "ref": textareaRef,
- "class": fieldClass,
- "value": model.value,
- "onInput": onInput,
- "autofocus": props.autofocus,
- "readonly": isReadonly.value,
- "disabled": isDisabled.value,
- "placeholder": props.placeholder,
- "rows": props.rows,
- "name": props.name,
- "onFocus": onFocus,
- "onBlur": blur
- }, slotProps, inputAttrs), null), [[vue.resolveDirective("intersect"), {
- handler: onIntersect
- }, null, {
- once: true
- }]]), props.autoGrow && vue.withDirectives(vue.createVNode("textarea", {
- "class": [fieldClass, 'v-textarea__sizer'],
- "onUpdate:modelValue": $event => model.value = $event,
- "ref": sizerRef,
- "readonly": true,
- "aria-hidden": "true"
- }, null), [[vue.vModelText, model.value]]), props.suffix && vue.createVNode("span", {
- "class": "v-text-field__suffix"
- }, [props.suffix])]);
- }
- });
- },
- details: hasDetails ? slotProps => vue.createVNode(vue.Fragment, null, [slots.details?.(slotProps), hasCounter && vue.createVNode(vue.Fragment, null, [vue.createVNode("span", null, null), vue.createVNode(VCounter, {
- "active": props.persistentCounter || isFocused.value,
- "value": counterValue.value,
- "max": max.value
- }, slots.counter)])]) : undefined
- });
- });
- return forwardRefs({}, vInputRef, vFieldRef, textareaRef);
- }
- });
- const makeVThemeProviderProps = propsFactory({
- withBackground: Boolean,
- ...makeComponentProps(),
- ...makeThemeProps(),
- ...makeTagProps()
- }, 'VThemeProvider');
- const VThemeProvider = genericComponent()({
- name: 'VThemeProvider',
- props: makeVThemeProviderProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- return () => {
- if (!props.withBackground) return slots.default?.();
- return vue.createVNode(props.tag, {
- "class": ['v-theme-provider', themeClasses.value, props.class],
- "style": props.style
- }, {
- default: () => [slots.default?.()]
- });
- };
- }
- });
- // Types
- const makeVTimelineProps = propsFactory({
- align: {
- type: String,
- default: 'center',
- validator: v => ['center', 'start'].includes(v)
- },
- direction: {
- type: String,
- default: 'vertical',
- validator: v => ['vertical', 'horizontal'].includes(v)
- },
- justify: {
- type: String,
- default: 'auto',
- validator: v => ['auto', 'center'].includes(v)
- },
- side: {
- type: String,
- validator: v => v == null || ['start', 'end'].includes(v)
- },
- lineInset: {
- type: [String, Number],
- default: 0
- },
- lineThickness: {
- type: [String, Number],
- default: 2
- },
- lineColor: String,
- truncateLine: {
- type: String,
- validator: v => ['start', 'end', 'both'].includes(v)
- },
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VTimeline');
- const VTimeline = genericComponent()({
- name: 'VTimeline',
- props: makeVTimelineProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- densityClasses
- } = useDensity(props);
- const {
- rtlClasses
- } = useRtl();
- provideDefaults({
- VTimelineDivider: {
- lineColor: vue.toRef(props, 'lineColor')
- },
- VTimelineItem: {
- density: vue.toRef(props, 'density'),
- lineInset: vue.toRef(props, 'lineInset')
- }
- });
- const sideClasses = vue.computed(() => {
- const side = props.side ? props.side : props.density !== 'default' ? 'end' : null;
- return side && `v-timeline--side-${side}`;
- });
- const truncateClasses = vue.computed(() => {
- const classes = ['v-timeline--truncate-line-start', 'v-timeline--truncate-line-end'];
- switch (props.truncateLine) {
- case 'both':
- return classes;
- case 'start':
- return classes[0];
- case 'end':
- return classes[1];
- default:
- return null;
- }
- });
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-timeline', `v-timeline--${props.direction}`, `v-timeline--align-${props.align}`, `v-timeline--justify-${props.justify}`, truncateClasses.value, {
- 'v-timeline--inset-line': !!props.lineInset
- }, themeClasses.value, densityClasses.value, sideClasses.value, rtlClasses.value, props.class],
- "style": [{
- '--v-timeline-line-thickness': convertToUnit(props.lineThickness)
- }, props.style]
- }, slots));
- return {};
- }
- });
- const makeVTimelineDividerProps = propsFactory({
- dotColor: String,
- fillDot: Boolean,
- hideDot: Boolean,
- icon: IconValue,
- iconColor: String,
- lineColor: String,
- ...makeComponentProps(),
- ...makeRoundedProps(),
- ...makeSizeProps(),
- ...makeElevationProps()
- }, 'VTimelineDivider');
- const VTimelineDivider = genericComponent()({
- name: 'VTimelineDivider',
- props: makeVTimelineDividerProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- sizeClasses,
- sizeStyles
- } = useSize(props, 'v-timeline-divider__dot');
- const {
- backgroundColorStyles,
- backgroundColorClasses
- } = useBackgroundColor(vue.toRef(props, 'dotColor'));
- const {
- roundedClasses
- } = useRounded(props, 'v-timeline-divider__dot');
- const {
- elevationClasses
- } = useElevation(props);
- const {
- backgroundColorClasses: lineColorClasses,
- backgroundColorStyles: lineColorStyles
- } = useBackgroundColor(vue.toRef(props, 'lineColor'));
- useRender(() => vue.createVNode("div", {
- "class": ['v-timeline-divider', {
- 'v-timeline-divider--fill-dot': props.fillDot
- }, props.class],
- "style": props.style
- }, [vue.createVNode("div", {
- "class": ['v-timeline-divider__before', lineColorClasses.value],
- "style": lineColorStyles.value
- }, null), !props.hideDot && vue.createVNode("div", {
- "key": "dot",
- "class": ['v-timeline-divider__dot', elevationClasses.value, roundedClasses.value, sizeClasses.value],
- "style": sizeStyles.value
- }, [vue.createVNode("div", {
- "class": ['v-timeline-divider__inner-dot', backgroundColorClasses.value, roundedClasses.value],
- "style": backgroundColorStyles.value
- }, [!slots.default ? vue.createVNode(VIcon, {
- "key": "icon",
- "color": props.iconColor,
- "icon": props.icon,
- "size": props.size
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "icon-defaults",
- "disabled": !props.icon,
- "defaults": {
- VIcon: {
- color: props.iconColor,
- icon: props.icon,
- size: props.size
- }
- }
- }, slots.default)])]), vue.createVNode("div", {
- "class": ['v-timeline-divider__after', lineColorClasses.value],
- "style": lineColorStyles.value
- }, null)]));
- return {};
- }
- });
- // Types
- const makeVTimelineItemProps = propsFactory({
- density: String,
- dotColor: String,
- fillDot: Boolean,
- hideDot: Boolean,
- hideOpposite: {
- type: Boolean,
- default: undefined
- },
- icon: IconValue,
- iconColor: String,
- lineInset: [Number, String],
- ...makeComponentProps(),
- ...makeDimensionProps(),
- ...makeElevationProps(),
- ...makeRoundedProps(),
- ...makeSizeProps(),
- ...makeTagProps()
- }, 'VTimelineItem');
- const VTimelineItem = genericComponent()({
- name: 'VTimelineItem',
- props: makeVTimelineItemProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- dimensionStyles
- } = useDimension(props);
- const dotSize = vue.shallowRef(0);
- const dotRef = vue.ref();
- vue.watch(dotRef, newValue => {
- if (!newValue) return;
- dotSize.value = newValue.$el.querySelector('.v-timeline-divider__dot')?.getBoundingClientRect().width ?? 0;
- }, {
- flush: 'post'
- });
- useRender(() => vue.createVNode("div", {
- "class": ['v-timeline-item', {
- 'v-timeline-item--fill-dot': props.fillDot
- }, props.class],
- "style": [{
- '--v-timeline-dot-size': convertToUnit(dotSize.value),
- '--v-timeline-line-inset': props.lineInset ? `calc(var(--v-timeline-dot-size) / 2 + ${convertToUnit(props.lineInset)})` : convertToUnit(0)
- }, props.style]
- }, [vue.createVNode("div", {
- "class": "v-timeline-item__body",
- "style": dimensionStyles.value
- }, [slots.default?.()]), vue.createVNode(VTimelineDivider, {
- "ref": dotRef,
- "hideDot": props.hideDot,
- "icon": props.icon,
- "iconColor": props.iconColor,
- "size": props.size,
- "elevation": props.elevation,
- "dotColor": props.dotColor,
- "fillDot": props.fillDot,
- "rounded": props.rounded
- }, {
- default: slots.icon
- }), props.density !== 'compact' && vue.createVNode("div", {
- "class": "v-timeline-item__opposite"
- }, [!props.hideOpposite && slots.opposite?.()])]));
- return {};
- }
- });
- const makeVToolbarItemsProps = propsFactory({
- ...makeComponentProps(),
- ...makeVariantProps({
- variant: 'text'
- })
- }, 'VToolbarItems');
- const VToolbarItems = genericComponent()({
- name: 'VToolbarItems',
- props: makeVToolbarItemsProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- provideDefaults({
- VBtn: {
- color: vue.toRef(props, 'color'),
- height: 'inherit',
- variant: vue.toRef(props, 'variant')
- }
- });
- useRender(() => vue.createVNode("div", {
- "class": ['v-toolbar-items', props.class],
- "style": props.style
- }, [slots.default?.()]));
- return {};
- }
- });
- // Types
- const makeVTooltipProps = propsFactory({
- id: String,
- text: String,
- ...omit(makeVOverlayProps({
- closeOnBack: false,
- location: 'end',
- locationStrategy: 'connected',
- eager: true,
- minWidth: 0,
- offset: 10,
- openOnClick: false,
- openOnHover: true,
- origin: 'auto',
- scrim: false,
- scrollStrategy: 'reposition',
- transition: false
- }), ['absolute', 'persistent'])
- }, 'VTooltip');
- const VTooltip = genericComponent()({
- name: 'VTooltip',
- props: makeVTooltipProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const isActive = useProxiedModel(props, 'modelValue');
- const {
- scopeId
- } = useScopeId();
- const uid = getUid();
- const id = vue.computed(() => props.id || `v-tooltip-${uid}`);
- const overlay = vue.ref();
- const location = vue.computed(() => {
- return props.location.split(' ').length > 1 ? props.location : props.location + ' center';
- });
- const origin = vue.computed(() => {
- return props.origin === 'auto' || props.origin === 'overlap' || props.origin.split(' ').length > 1 || props.location.split(' ').length > 1 ? props.origin : props.origin + ' center';
- });
- const transition = vue.computed(() => {
- if (props.transition) return props.transition;
- return isActive.value ? 'scale-transition' : 'fade-transition';
- });
- const activatorProps = vue.computed(() => vue.mergeProps({
- 'aria-describedby': id.value
- }, props.activatorProps));
- useRender(() => {
- const [overlayProps] = VOverlay.filterProps(props);
- return vue.createVNode(VOverlay, vue.mergeProps({
- "ref": overlay,
- "class": ['v-tooltip', props.class],
- "style": props.style,
- "id": id.value
- }, overlayProps, {
- "modelValue": isActive.value,
- "onUpdate:modelValue": $event => isActive.value = $event,
- "transition": transition.value,
- "absolute": true,
- "location": location.value,
- "origin": origin.value,
- "persistent": true,
- "role": "tooltip",
- "activatorProps": activatorProps.value,
- "_disableGlobalStack": true
- }, scopeId), {
- activator: slots.activator,
- default: function () {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- return slots.default?.(...args) ?? props.text;
- }
- });
- });
- return forwardRefs({}, overlay);
- }
- });
- // Composables
- const VValidation = genericComponent()({
- name: 'VValidation',
- props: makeValidationProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const validation = useValidation(props, 'validation');
- return () => slots.default?.(validation);
- }
- });
- var components = /*#__PURE__*/Object.freeze({
- __proto__: null,
- VAlert: VAlert,
- VAlertTitle: VAlertTitle,
- VApp: VApp,
- VAppBar: VAppBar,
- VAppBarNavIcon: VAppBarNavIcon,
- VAppBarTitle: VAppBarTitle,
- VAutocomplete: VAutocomplete,
- VAvatar: VAvatar,
- VBadge: VBadge,
- VBanner: VBanner,
- VBannerActions: VBannerActions,
- VBannerText: VBannerText,
- VBottomNavigation: VBottomNavigation,
- VBreadcrumbs: VBreadcrumbs,
- VBreadcrumbsDivider: VBreadcrumbsDivider,
- VBreadcrumbsItem: VBreadcrumbsItem,
- VBtn: VBtn,
- VBtnGroup: VBtnGroup,
- VBtnToggle: VBtnToggle,
- VCard: VCard,
- VCardActions: VCardActions,
- VCardItem: VCardItem,
- VCardSubtitle: VCardSubtitle,
- VCardText: VCardText,
- VCardTitle: VCardTitle,
- VCarousel: VCarousel,
- VCarouselItem: VCarouselItem,
- VCheckbox: VCheckbox,
- VCheckboxBtn: VCheckboxBtn,
- VChip: VChip,
- VChipGroup: VChipGroup,
- VClassIcon: VClassIcon,
- VCode: VCode,
- VCol: VCol,
- VColorPicker: VColorPicker,
- VCombobox: VCombobox,
- VComponentIcon: VComponentIcon,
- VContainer: VContainer,
- VCounter: VCounter,
- VDefaultsProvider: VDefaultsProvider,
- VDialog: VDialog,
- VDialogBottomTransition: VDialogBottomTransition,
- VDialogTopTransition: VDialogTopTransition,
- VDialogTransition: VDialogTransition,
- VDivider: VDivider,
- VExpandTransition: VExpandTransition,
- VExpandXTransition: VExpandXTransition,
- VExpansionPanel: VExpansionPanel,
- VExpansionPanelText: VExpansionPanelText,
- VExpansionPanelTitle: VExpansionPanelTitle,
- VExpansionPanels: VExpansionPanels,
- VFabTransition: VFabTransition,
- VFadeTransition: VFadeTransition,
- VField: VField,
- VFieldLabel: VFieldLabel,
- VFileInput: VFileInput,
- VFooter: VFooter,
- VForm: VForm,
- VHover: VHover,
- VIcon: VIcon,
- VImg: VImg,
- VInput: VInput,
- VItem: VItem,
- VItemGroup: VItemGroup,
- VKbd: VKbd,
- VLabel: VLabel,
- VLayout: VLayout,
- VLayoutItem: VLayoutItem,
- VLazy: VLazy,
- VLigatureIcon: VLigatureIcon,
- VList: VList,
- VListGroup: VListGroup,
- VListImg: VListImg,
- VListItem: VListItem,
- VListItemAction: VListItemAction,
- VListItemMedia: VListItemMedia,
- VListItemSubtitle: VListItemSubtitle,
- VListItemTitle: VListItemTitle,
- VListSubheader: VListSubheader,
- VLocaleProvider: VLocaleProvider,
- VMain: VMain,
- VMenu: VMenu,
- VMessages: VMessages,
- VNavigationDrawer: VNavigationDrawer,
- VNoSsr: VNoSsr,
- VOverlay: VOverlay,
- VPagination: VPagination,
- VParallax: VParallax,
- VProgressCircular: VProgressCircular,
- VProgressLinear: VProgressLinear,
- VRadio: VRadio,
- VRadioGroup: VRadioGroup,
- VRangeSlider: VRangeSlider,
- VRating: VRating,
- VResponsive: VResponsive,
- VRow: VRow,
- VScaleTransition: VScaleTransition,
- VScrollXReverseTransition: VScrollXReverseTransition,
- VScrollXTransition: VScrollXTransition,
- VScrollYReverseTransition: VScrollYReverseTransition,
- VScrollYTransition: VScrollYTransition,
- VSelect: VSelect,
- VSelectionControl: VSelectionControl,
- VSelectionControlGroup: VSelectionControlGroup,
- VSheet: VSheet,
- VSlideGroup: VSlideGroup,
- VSlideGroupItem: VSlideGroupItem,
- VSlideXReverseTransition: VSlideXReverseTransition,
- VSlideXTransition: VSlideXTransition,
- VSlideYReverseTransition: VSlideYReverseTransition,
- VSlideYTransition: VSlideYTransition,
- VSlider: VSlider,
- VSnackbar: VSnackbar,
- VSpacer: VSpacer,
- VSvgIcon: VSvgIcon,
- VSwitch: VSwitch,
- VSystemBar: VSystemBar,
- VTab: VTab,
- VTable: VTable,
- VTabs: VTabs,
- VTextField: VTextField,
- VTextarea: VTextarea,
- VThemeProvider: VThemeProvider,
- VTimeline: VTimeline,
- VTimelineItem: VTimelineItem,
- VToolbar: VToolbar,
- VToolbarItems: VToolbarItems,
- VToolbarTitle: VToolbarTitle,
- VTooltip: VTooltip,
- VValidation: VValidation,
- VVirtualScroll: VVirtualScroll,
- VWindow: VWindow,
- VWindowItem: VWindowItem
- });
- // Types
- function mounted$2(el, binding) {
- const modifiers = binding.modifiers || {};
- const value = binding.value;
- const {
- once,
- immediate,
- ...modifierKeys
- } = modifiers;
- const defaultValue = !Object.keys(modifierKeys).length;
- const {
- handler,
- options
- } = typeof value === 'object' ? value : {
- handler: value,
- options: {
- attributes: modifierKeys?.attr ?? defaultValue,
- characterData: modifierKeys?.char ?? defaultValue,
- childList: modifierKeys?.child ?? defaultValue,
- subtree: modifierKeys?.sub ?? defaultValue
- }
- };
- const observer = new MutationObserver(function () {
- let mutations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
- let observer = arguments.length > 1 ? arguments[1] : undefined;
- handler?.(mutations, observer);
- if (once) unmounted$2(el, binding);
- });
- if (immediate) handler?.([], observer);
- el._mutate = Object(el._mutate);
- el._mutate[binding.instance.$.uid] = {
- observer
- };
- observer.observe(el, options);
- }
- function unmounted$2(el, binding) {
- if (!el._mutate?.[binding.instance.$.uid]) return;
- el._mutate[binding.instance.$.uid].observer.disconnect();
- delete el._mutate[binding.instance.$.uid];
- }
- const Mutate = {
- mounted: mounted$2,
- unmounted: unmounted$2
- };
- // Types
- function mounted$1(el, binding) {
- const handler = binding.value;
- const options = {
- passive: !binding.modifiers?.active
- };
- window.addEventListener('resize', handler, options);
- el._onResize = Object(el._onResize);
- el._onResize[binding.instance.$.uid] = {
- handler,
- options
- };
- if (!binding.modifiers?.quiet) {
- handler();
- }
- }
- function unmounted$1(el, binding) {
- if (!el._onResize?.[binding.instance.$.uid]) return;
- const {
- handler,
- options
- } = el._onResize[binding.instance.$.uid];
- window.removeEventListener('resize', handler, options);
- delete el._onResize[binding.instance.$.uid];
- }
- const Resize = {
- mounted: mounted$1,
- unmounted: unmounted$1
- };
- // Types
- function mounted(el, binding) {
- const {
- self = false
- } = binding.modifiers ?? {};
- const value = binding.value;
- const options = typeof value === 'object' && value.options || {
- passive: true
- };
- const handler = typeof value === 'function' || 'handleEvent' in value ? value : value.handler;
- const target = self ? el : binding.arg ? document.querySelector(binding.arg) : window;
- if (!target) return;
- target.addEventListener('scroll', handler, options);
- el._onScroll = Object(el._onScroll);
- el._onScroll[binding.instance.$.uid] = {
- handler,
- options,
- // Don't reference self
- target: self ? undefined : target
- };
- }
- function unmounted(el, binding) {
- if (!el._onScroll?.[binding.instance.$.uid]) return;
- const {
- handler,
- options,
- target = el
- } = el._onScroll[binding.instance.$.uid];
- target.removeEventListener('scroll', handler, options);
- delete el._onScroll[binding.instance.$.uid];
- }
- function updated(el, binding) {
- if (binding.value === binding.oldValue) return;
- unmounted(el, binding);
- mounted(el, binding);
- }
- const Scroll = {
- mounted,
- unmounted,
- updated
- };
- var directives = /*#__PURE__*/Object.freeze({
- __proto__: null,
- ClickOutside: ClickOutside,
- Intersect: Intersect,
- Mutate: Mutate,
- Resize: Resize,
- Ripple: Ripple,
- Scroll: Scroll,
- Touch: Touch
- });
- // Utilities
- // Types
- const firstDay = {
- '001': 1,
- AD: 1,
- AE: 6,
- AF: 6,
- AG: 0,
- AI: 1,
- AL: 1,
- AM: 1,
- AN: 1,
- AR: 1,
- AS: 0,
- AT: 1,
- AU: 1,
- AX: 1,
- AZ: 1,
- BA: 1,
- BD: 0,
- BE: 1,
- BG: 1,
- BH: 6,
- BM: 1,
- BN: 1,
- BR: 0,
- BS: 0,
- BT: 0,
- BW: 0,
- BY: 1,
- BZ: 0,
- CA: 0,
- CH: 1,
- CL: 1,
- CM: 1,
- CN: 1,
- CO: 0,
- CR: 1,
- CY: 1,
- CZ: 1,
- DE: 1,
- DJ: 6,
- DK: 1,
- DM: 0,
- DO: 0,
- DZ: 6,
- EC: 1,
- EE: 1,
- EG: 6,
- ES: 1,
- ET: 0,
- FI: 1,
- FJ: 1,
- FO: 1,
- FR: 1,
- GB: 1,
- 'GB-alt-variant': 0,
- GE: 1,
- GF: 1,
- GP: 1,
- GR: 1,
- GT: 0,
- GU: 0,
- HK: 0,
- HN: 0,
- HR: 1,
- HU: 1,
- ID: 0,
- IE: 1,
- IL: 0,
- IN: 0,
- IQ: 6,
- IR: 6,
- IS: 1,
- IT: 1,
- JM: 0,
- JO: 6,
- JP: 0,
- KE: 0,
- KG: 1,
- KH: 0,
- KR: 0,
- KW: 6,
- KZ: 1,
- LA: 0,
- LB: 1,
- LI: 1,
- LK: 1,
- LT: 1,
- LU: 1,
- LV: 1,
- LY: 6,
- MC: 1,
- MD: 1,
- ME: 1,
- MH: 0,
- MK: 1,
- MM: 0,
- MN: 1,
- MO: 0,
- MQ: 1,
- MT: 0,
- MV: 5,
- MX: 0,
- MY: 1,
- MZ: 0,
- NI: 0,
- NL: 1,
- NO: 1,
- NP: 0,
- NZ: 1,
- OM: 6,
- PA: 0,
- PE: 0,
- PH: 0,
- PK: 0,
- PL: 1,
- PR: 0,
- PT: 0,
- PY: 0,
- QA: 6,
- RE: 1,
- RO: 1,
- RS: 1,
- RU: 1,
- SA: 0,
- SD: 6,
- SE: 1,
- SG: 0,
- SI: 1,
- SK: 1,
- SM: 1,
- SV: 0,
- SY: 6,
- TH: 0,
- TJ: 1,
- TM: 1,
- TR: 1,
- TT: 0,
- TW: 0,
- UA: 1,
- UM: 0,
- US: 0,
- UY: 1,
- UZ: 1,
- VA: 1,
- VE: 0,
- VI: 0,
- VN: 1,
- WS: 0,
- XK: 1,
- YE: 0,
- ZA: 0,
- ZW: 0
- };
- function getWeekArray(date, locale) {
- const weeks = [];
- let currentWeek = [];
- const firstDayOfMonth = startOfMonth(date);
- const lastDayOfMonth = endOfMonth(date);
- const firstDayWeekIndex = firstDayOfMonth.getDay() - firstDay[locale.slice(-2).toUpperCase()];
- const lastDayWeekIndex = lastDayOfMonth.getDay() - firstDay[locale.slice(-2).toUpperCase()];
- for (let i = 0; i < firstDayWeekIndex; i++) {
- const adjacentDay = new Date(firstDayOfMonth);
- adjacentDay.setDate(adjacentDay.getDate() - (firstDayWeekIndex - i));
- currentWeek.push(adjacentDay);
- }
- for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
- const day = new Date(date.getFullYear(), date.getMonth(), i);
- // Add the day to the current week
- currentWeek.push(day);
- // If the current week has 7 days, add it to the weeks array and start a new week
- if (currentWeek.length === 7) {
- weeks.push(currentWeek);
- currentWeek = [];
- }
- }
- for (let i = 1; i < 7 - lastDayWeekIndex; i++) {
- const adjacentDay = new Date(lastDayOfMonth);
- adjacentDay.setDate(adjacentDay.getDate() + i);
- currentWeek.push(adjacentDay);
- }
- weeks.push(currentWeek);
- return weeks;
- }
- function startOfMonth(date) {
- return new Date(date.getFullYear(), date.getMonth(), 1);
- }
- function endOfMonth(date) {
- return new Date(date.getFullYear(), date.getMonth() + 1, 0);
- }
- function parseLocalDate(value) {
- const parts = value.split('-').map(Number);
- // new Date() uses local time zone when passing individual date component values
- return new Date(parts[0], parts[1] - 1, parts[2]);
- }
- const _YYYMMDD = /([12]\d{3}-([1-9]|0[1-9]|1[0-2])-([1-9]|0[1-9]|[12]\d|3[01]))/;
- function date(value) {
- if (value == null) return new Date();
- if (value instanceof Date) return value;
- if (typeof value === 'string') {
- let parsed;
- if (_YYYMMDD.test(value)) {
- return parseLocalDate(value);
- } else {
- parsed = Date.parse(value);
- }
- if (!isNaN(parsed)) return new Date(parsed);
- }
- return null;
- }
- const sundayJanuarySecond2000 = new Date(2000, 0, 2);
- function getWeekdays(locale) {
- const daysFromSunday = firstDay[locale.slice(-2).toUpperCase()];
- return createRange(7).map(i => {
- const weekday = new Date(sundayJanuarySecond2000);
- weekday.setDate(sundayJanuarySecond2000.getDate() + daysFromSunday + i);
- return new Intl.DateTimeFormat(locale, {
- weekday: 'short'
- }).format(weekday);
- });
- }
- function format(value, formatString, locale) {
- const date = new Date(value);
- let options = {};
- switch (formatString) {
- case 'fullDateWithWeekday':
- options = {
- weekday: 'long',
- day: 'numeric',
- month: 'long',
- year: 'numeric'
- };
- break;
- case 'normalDateWithWeekday':
- options = {
- weekday: 'short',
- day: 'numeric',
- month: 'short'
- };
- break;
- case 'keyboardDate':
- options = {};
- break;
- case 'monthAndDate':
- options = {
- month: 'long',
- day: 'numeric'
- };
- break;
- case 'monthAndYear':
- options = {
- month: 'long',
- year: 'numeric'
- };
- break;
- case 'dayOfMonth':
- options = {
- day: 'numeric'
- };
- break;
- default:
- options = {
- timeZone: 'UTC',
- timeZoneName: 'short'
- };
- }
- return new Intl.DateTimeFormat(locale, options).format(date);
- }
- function addDays(date, amount) {
- const d = new Date(date);
- d.setDate(d.getDate() + amount);
- return d;
- }
- function addMonths(date, amount) {
- const d = new Date(date);
- d.setMonth(d.getMonth() + amount);
- return d;
- }
- function getYear(date) {
- return date.getFullYear();
- }
- function getMonth(date) {
- return date.getMonth();
- }
- function startOfYear(date) {
- return new Date(date.getFullYear(), 0, 1);
- }
- function endOfYear(date) {
- return new Date(date.getFullYear(), 11, 31);
- }
- function isWithinRange(date, range) {
- return isAfter(date, range[0]) && isBefore(date, range[1]);
- }
- function isValid(date) {
- const d = new Date(date);
- return d instanceof Date && !isNaN(d.getTime());
- }
- function isAfter(date, comparing) {
- return date.getTime() > comparing.getTime();
- }
- function isBefore(date, comparing) {
- return date.getTime() < comparing.getTime();
- }
- function isEqual(date, comparing) {
- return date.getTime() === comparing.getTime();
- }
- function isSameDay(date, comparing) {
- return date.getDate() === comparing.getDate() && date.getMonth() === comparing.getMonth() && date.getFullYear() === comparing.getFullYear();
- }
- function isSameMonth(date, comparing) {
- return date.getMonth() === comparing.getMonth() && date.getFullYear() === comparing.getFullYear();
- }
- function getDiff(date, comparing, unit) {
- const d = new Date(date);
- const c = new Date(comparing);
- if (unit === 'month') {
- return d.getMonth() - c.getMonth() + (d.getFullYear() - c.getFullYear()) * 12;
- }
- return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60 * 24));
- }
- function setYear(date, year) {
- const d = new Date(date);
- d.setFullYear(year);
- return d;
- }
- class VuetifyDateAdapter {
- constructor(options) {
- this.locale = options.locale;
- }
- date(value) {
- return date(value);
- }
- toJsDate(date) {
- return date;
- }
- addDays(date, amount) {
- return addDays(date, amount);
- }
- addMonths(date, amount) {
- return addMonths(date, amount);
- }
- getWeekArray(date) {
- return getWeekArray(date, this.locale);
- }
- startOfMonth(date) {
- return startOfMonth(date);
- }
- endOfMonth(date) {
- return endOfMonth(date);
- }
- format(date, formatString) {
- return format(date, formatString, this.locale);
- }
- isEqual(date, comparing) {
- return isEqual(date, comparing);
- }
- isValid(date) {
- return isValid(date);
- }
- isWithinRange(date, range) {
- return isWithinRange(date, range);
- }
- isAfter(date, comparing) {
- return isAfter(date, comparing);
- }
- isBefore(date, comparing) {
- return !isAfter(date, comparing) && !isEqual(date, comparing);
- }
- isSameDay(date, comparing) {
- return isSameDay(date, comparing);
- }
- isSameMonth(date, comparing) {
- return isSameMonth(date, comparing);
- }
- setYear(date, year) {
- return setYear(date, year);
- }
- getDiff(date, comparing, unit) {
- return getDiff(date, comparing, unit);
- }
- getWeekdays() {
- return getWeekdays(this.locale);
- }
- getYear(date) {
- return getYear(date);
- }
- getMonth(date) {
- return getMonth(date);
- }
- startOfYear(date) {
- return startOfYear(date);
- }
- endOfYear(date) {
- return endOfYear(date);
- }
- }
- // Composables
- // Types
- const DateAdapterSymbol = Symbol.for('vuetify:date-adapter');
- function createDate(options) {
- return mergeDeep({
- adapter: VuetifyDateAdapter,
- locale: {
- af: 'af-ZA',
- // ar: '', # not the same value for all variants
- bg: 'bg-BG',
- ca: 'ca-ES',
- ckb: '',
- cs: '',
- de: 'de-DE',
- el: 'el-GR',
- en: 'en-US',
- // es: '', # not the same value for all variants
- et: 'et-EE',
- fa: 'fa-IR',
- fi: 'fi-FI',
- // fr: '', #not the same value for all variants
- hr: 'hr-HR',
- hu: 'hu-HU',
- he: 'he-IL',
- id: 'id-ID',
- it: 'it-IT',
- ja: 'ja-JP',
- ko: 'ko-KR',
- lv: 'lv-LV',
- lt: 'lt-LT',
- nl: 'nl-NL',
- no: 'nn-NO',
- pl: 'pl-PL',
- pt: 'pt-PT',
- ro: 'ro-RO',
- ru: 'ru-RU',
- sk: 'sk-SK',
- sl: 'sl-SI',
- srCyrl: 'sr-SP',
- srLatn: 'sr-SP',
- sv: 'sv-SE',
- th: 'th-TH',
- tr: 'tr-TR',
- az: 'az-AZ',
- uk: 'uk-UA',
- vi: 'vi-VN',
- zhHans: 'zh-CN',
- zhHant: 'zh-TW'
- }
- }, options);
- }
- // Composables
- function createVuetify$1() {
- let vuetify = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- const {
- blueprint,
- ...rest
- } = vuetify;
- const options = mergeDeep(blueprint, rest);
- const {
- aliases = {},
- components = {},
- directives = {}
- } = options;
- const defaults = createDefaults(options.defaults);
- const display = createDisplay(options.display, options.ssr);
- const theme = createTheme(options.theme);
- const icons = createIcons(options.icons);
- const locale = createLocale(options.locale);
- const date = createDate(options.date);
- const install = app => {
- for (const key in directives) {
- app.directive(key, directives[key]);
- }
- for (const key in components) {
- app.component(key, components[key]);
- }
- for (const key in aliases) {
- app.component(key, defineComponent({
- ...aliases[key],
- name: key,
- aliasName: aliases[key].name
- }));
- }
- theme.install(app);
- app.provide(DefaultsSymbol, defaults);
- app.provide(DisplaySymbol, display);
- app.provide(ThemeSymbol, theme);
- app.provide(IconSymbol, icons);
- app.provide(LocaleSymbol, locale);
- app.provide(DateAdapterSymbol, date);
- if (IN_BROWSER && options.ssr) {
- if (app.$nuxt) {
- app.$nuxt.hook('app:suspense:resolve', () => {
- display.update();
- });
- } else {
- const {
- mount
- } = app;
- app.mount = function () {
- const vm = mount(...arguments);
- vue.nextTick(() => display.update());
- app.mount = mount;
- return vm;
- };
- }
- }
- getUid.reset();
- if (typeof __VUE_OPTIONS_API__ !== 'boolean' || __VUE_OPTIONS_API__) {
- app.mixin({
- computed: {
- $vuetify() {
- return vue.reactive({
- defaults: inject.call(this, DefaultsSymbol),
- display: inject.call(this, DisplaySymbol),
- theme: inject.call(this, ThemeSymbol),
- icons: inject.call(this, IconSymbol),
- locale: inject.call(this, LocaleSymbol),
- date: inject.call(this, DateAdapterSymbol)
- });
- }
- }
- });
- }
- };
- return {
- install,
- defaults,
- display,
- theme,
- icons,
- locale,
- date
- };
- }
- const version$1 = "3.3.11";
- createVuetify$1.version = version$1;
- // Vue's inject() can only be used in setup
- function inject(key) {
- const vm = this.$;
- const provides = vm.parent?.provides ?? vm.vnode.appContext?.provides;
- if (provides && key in provides) {
- return provides[key];
- }
- }
- /* eslint-disable local-rules/sort-imports */
- // Types
- const createVuetify = function () {
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- return createVuetify$1({
- components,
- directives,
- ...options
- });
- };
- const version = "3.3.11";
- createVuetify.version = version;
- exports.components = components;
- exports.createVuetify = createVuetify;
- exports.directives = directives;
- exports.useDefaults = useDefaults;
- exports.useDisplay = useDisplay;
- exports.useLayout = useLayout;
- exports.useLocale = useLocale;
- exports.useRtl = useRtl;
- exports.useTheme = useTheme;
- exports.version = version;
- }));
- //# sourceMappingURL=vuetify.js.map
|