12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033 |
- /*!
- * Vuetify v3.7.6
- * 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;
- }, {});
- };
- }
- /**
- * Like `Partial<T>` but doesn't care what the value is
- */
- // Copied from Vue
- // Utilities
- // Types
- // Composables
- const makeComponentProps = propsFactory({
- class: [String, Array, Object],
- 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);
- const SUPPORTS_EYE_DROPPER = IN_BROWSER && 'EyeDropper' in window;
- function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
- function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
- function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
- function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
- function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
- // 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 === true) return item === undefined ? fallback : item;
- if (property == null || typeof property === 'boolean') return fallback;
- 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 isPlainObject(obj) {
- let proto;
- return obj !== null && typeof obj === 'object' && ((proto = Object.getPrototypeOf(obj)) === Object.prototype || proto === null);
- }
- function refElement(obj) {
- if (obj && '$el' in obj) {
- const el = obj.$el;
- if (el?.nodeType === Node.TEXT_NODE) {
- // Multi-root component, use the first element
- return el.nextElementSibling;
- }
- return el;
- }
- return 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));
- }
- // Array of keys
- function pick(obj, paths) {
- const found = {};
- const keys = new Set(Object.keys(obj));
- for (const path of paths) {
- if (keys.has(path)) {
- found[path] = obj[path];
- }
- }
- return found;
- }
- // Array of keys
- // Array of keys or RegExp to test keys against
- function pickWithRest(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;
- }
- function only(obj, include) {
- const clone = {};
- include.forEach(prop => clone[prop] = obj[prop]);
- return clone;
- }
- const onRE = /^on[^a-z]/;
- const isOn = key => onRE.test(key);
- const bubblingEvents = ['onAfterscriptexecute', 'onAnimationcancel', 'onAnimationend', 'onAnimationiteration', 'onAnimationstart', 'onAuxclick', 'onBeforeinput', 'onBeforescriptexecute', 'onChange', 'onClick', 'onCompositionend', 'onCompositionstart', 'onCompositionupdate', 'onContextmenu', 'onCopy', 'onCut', 'onDblclick', 'onFocusin', 'onFocusout', 'onFullscreenchange', 'onFullscreenerror', 'onGesturechange', 'onGestureend', 'onGesturestart', 'onGotpointercapture', 'onInput', 'onKeydown', 'onKeypress', 'onKeyup', 'onLostpointercapture', 'onMousedown', 'onMousemove', 'onMouseout', 'onMouseover', 'onMouseup', 'onMousewheel', 'onPaste', 'onPointercancel', 'onPointerdown', 'onPointerenter', 'onPointerleave', 'onPointermove', 'onPointerout', 'onPointerover', 'onPointerup', 'onReset', 'onSelect', 'onSubmit', 'onTouchcancel', 'onTouchend', 'onTouchmove', 'onTouchstart', 'onTransitioncancel', 'onTransitionend', 'onTransitionrun', 'onTransitionstart', 'onWheel'];
- const compositionIgnoreKeys = ['ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft', 'Enter', 'Escape', 'Tab', ' '];
- function isComposingIgnoreKey(e) {
- return e.isComposing && compositionIgnoreKeys.includes(e.key);
- }
- /**
- * Filter attributes that should be applied to
- * the root element of an input component. Remaining
- * attributes should be passed to the <input> element inside.
- */
- function filterInputAttrs(attrs) {
- const [events, props] = pickWithRest(attrs, [onRE]);
- const inputEvents = omit(events, bubblingEvents);
- const [rootAttrs, inputAttrs] = pickWithRest(props, ['class', 'style', 'id', /^data-/]);
- Object.assign(rootAttrs, events);
- Object.assign(inputAttrs, inputEvents);
- return [rootAttrs, inputAttrs];
- }
- function wrapInArray(v) {
- return v == null ? [] : Array.isArray(v) ? v : [v];
- }
- function debounce(fn, delay) {
- let timeoutId = 0;
- const wrap = function () {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- clearTimeout(timeoutId);
- timeoutId = setTimeout(() => fn(...args), vue.unref(delay));
- };
- wrap.clear = () => {
- clearTimeout(timeoutId);
- };
- wrap.immediate = fn;
- return wrap;
- }
- 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 padStart(str, length) {
- let char = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '0';
- return char.repeat(Math.max(0, length - str.length)) + str;
- }
- 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 chunkArray(array) {
- let size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
- return Array.from({
- length: Math.ceil(array.length / size)
- }, (v, i) => array.slice(i * size, i * size + size));
- }
- 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 plain objects
- if (isPlainObject(sourceProperty) && isPlainObject(targetProperty)) {
- out[key] = mergeDeep(sourceProperty, targetProperty, arrayFn);
- continue;
- }
- if (arrayFn && Array.isArray(sourceProperty) && Array.isArray(targetProperty)) {
- 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 (vnode.suspense) {
- return findChildrenWithProvide(key, vnode.ssContent);
- } 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, []);
- _classPrivateFieldInitSpec(this, _pointer, 0);
- this.size = size;
- }
- push(val) {
- _classPrivateFieldGet(_arr, this)[_classPrivateFieldGet(_pointer, this)] = val;
- _classPrivateFieldSet(_pointer, this, (_classPrivateFieldGet(_pointer, this) + 1) % this.size);
- }
- values() {
- return _classPrivateFieldGet(_arr, this).slice(_classPrivateFieldGet(_pointer, this)).concat(_classPrivateFieldGet(_arr, this).slice(0, _classPrivateFieldGet(_pointer, this)));
- }
- }
- 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
- /**
- * Convert a computed ref to a record of refs.
- * The getter function must always return an object with the same keys.
- */
- 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);
- }
- 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 isEmpty(val) {
- return val === null || val === undefined || typeof val === 'string' && val.trim() === '';
- }
- 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;
- }
- }
- function ensureValidVNode(vnodes) {
- return vnodes.some(child => {
- if (!vue.isVNode(child)) return true;
- if (child.type === vue.Comment) return false;
- return child.type !== vue.Fragment || ensureValidVNode(child.children);
- }) ? vnodes : null;
- }
- function defer(timeout, cb) {
- if (!IN_BROWSER || timeout === 0) {
- cb();
- return () => {};
- }
- const timeoutId = window.setTimeout(cb, timeout);
- return () => window.clearTimeout(timeoutId);
- }
- function isClickInsideElement(event, targetDiv) {
- const mouseX = event.clientX;
- const mouseY = event.clientY;
- const divRect = targetDiv.getBoundingClientRect();
- const divLeft = divRect.left;
- const divTop = divRect.top;
- const divRight = divRect.right;
- const divBottom = divRect.bottom;
- return mouseX >= divLeft && mouseX <= divRight && mouseY >= divTop && mouseY <= divBottom;
- }
- function templateRef() {
- const el = vue.shallowRef();
- const fn = target => {
- el.value = target;
- };
- Object.defineProperty(fn, 'value', {
- enumerable: true,
- get: () => el.value,
- set: val => el.value = val
- });
- Object.defineProperty(fn, 'el', {
- enumerable: true,
- get: () => refElement(el.value)
- });
- return fn;
- }
- function checkPrintable(e) {
- const isPrintableChar = e.key.length === 1;
- const noModifier = !e.ctrlKey && !e.metaKey && !e.altKey;
- return isPrintableChar && noModifier;
- }
- // 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)
- }
- };
- }
- function getTargetBox(target) {
- if (Array.isArray(target)) {
- return new Box({
- x: target[0],
- y: target[1],
- width: 0,
- height: 0
- });
- } else {
- return target.getBoundingClientRect();
- }
- }
- // 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);
- }
- });
- }
- /**
- * 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;
- }
- /* 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);
- }
- function isParsableColor(color) {
- return isCssColor(color) && !/^((rgb|hsl)a?\()?var\(--/.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);
- }
- function getForeground(color) {
- const blackContrast = Math.abs(APCAcontrast(parseColor(0), parseColor(color)));
- const whiteContrast = Math.abs(APCAcontrast(parseColor(0xffffff), parseColor(color)));
- // 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
- return whiteContrast > Math.min(blackContrast, 50) ? '#fff' : '#000';
- }
- // 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();
- };
- // Utilities
- // Types
- function injectSelf(key) {
- let vm = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstance('injectSelf');
- const {
- provides
- } = vm;
- if (provides && key in provides) {
- // TS doesn't allow symbol as index type
- return provides[key];
- }
- return undefined;
- }
- // Utilities
- // 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);
- if (providedDefaults.value == null && !(scoped || reset || root)) return injectedDefaults.value;
- 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] !== undefined ? componentDefaults.value?.[prop] : defaults.value?.global?.[prop] !== undefined ? 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());
- });
- _subcomponentDefaults.value = subComponents.length ? Object.fromEntries(subComponents) : undefined;
- } else {
- _subcomponentDefaults.value = undefined;
- }
- });
- function provideSubDefaults() {
- const injected = injectSelf(DefaultsSymbol, vm);
- vue.provide(DefaultsSymbol, vue.computed(() => {
- return _subcomponentDefaults.value ? mergeDeep(injected?.value ?? {}, _subcomponentDefaults.value) : injected?.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
- // No props
- // Object Props
- // 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).filter(key => key !== 'class' && key !== 'style');
- options.filterProps = function filterProps(props) {
- return pick(props, propKeys);
- };
- 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;
- }
- // No argument - simple default slot
- // Generic constructor argument - generic props and slots
- // Slots argument - simple slots
- // Implementation
- function genericComponent() {
- let exposeDefaults = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
- return options => (exposeDefaults ? defineComponent : vue.defineComponent)(options);
- }
- function defineFunctionalComponent(props, render) {
- render.props = props;
- return render;
- }
- // Adds a filterProps method to the component options
- // https://github.com/vuejs/core/pull/10557
- // not a vue Component
- // 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
- function getPrefixedEventHandlers(attrs, suffix, getData) {
- return Object.keys(attrs).filter(key => isOn(key) && key.endsWith(suffix)).reduce((acc, key) => {
- acc[key.slice(0, -suffix.length)] = event => attrs[key](event, getData(event));
- return acc;
- }, {});
- }
- 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);
- }
- 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 = templateRef();
- 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.el, (newValue, oldValue) => {
- if (oldValue) {
- observer.unobserve(oldValue);
- contentRect.value = undefined;
- }
- if (newValue) observer.observe(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 size = elementSize.value ?? layoutSize.value;
- const unit = size === 0 ? '%' : 'px';
- const styles = {
- [position.value]: 0,
- zIndex: zIndex.value,
- transform: `translate${isHorizontal ? 'X' : 'Y'}(${(active.value ? 0 : -(size === 0 ? 100 : size)) * (isOppositeHorizontal || isOppositeVertical ? -1 : 1)}${unit})`,
- 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: parentLayout ? rootZIndex.value : undefined,
- position: parentLayout ? 'relative' : undefined,
- overflow: parentLayout ? 'hidden' : undefined
- }));
- return {
- layoutClasses,
- layoutStyles,
- getLayoutItem,
- items,
- layoutRect,
- layoutRef: resizeRef
- };
- }
- // 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
- // 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;
- }
- var en = {
- badge: 'Badge',
- open: 'Open',
- close: 'Close',
- dismiss: 'Dismiss',
- confirmEdit: {
- ok: 'OK',
- cancel: 'Cancel'
- },
- 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: {
- itemsSelected: '{0} selected',
- 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',
- today: 'Today'
- },
- 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)'
- },
- fileUpload: {
- title: 'Drag and drop files here',
- divider: 'or',
- browse: 'Browse Files'
- },
- timePicker: {
- am: 'AM',
- pm: 'PM',
- title: 'Select Time'
- },
- 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'
- }
- };
- // 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 genDefaults$3() {
- return {
- 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,
- km: 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
- };
- }
- function createRtl(i18n, options) {
- const rtl = vue.ref(options?.rtl ?? genDefaults$3());
- 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
- };
- }
- // Utilities
- // Types
- const ThemeSymbol = Symbol.for('vuetify:theme');
- const makeThemeProps = propsFactory({
- theme: String
- }, 'theme');
- function genDefaults$2() {
- return {
- defaultTheme: 'light',
- variations: {
- colors: [],
- lighten: 0,
- darken: 0
- },
- themes: {
- light: {
- dark: false,
- colors: {
- background: '#FFFFFF',
- surface: '#FFFFFF',
- 'surface-bright': '#FFFFFF',
- 'surface-light': '#EEEEEE',
- 'surface-variant': '#424242',
- 'on-surface-variant': '#EEEEEE',
- primary: '#1867C0',
- 'primary-darken-1': '#1F5592',
- secondary: '#48A9A6',
- '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-bright': '#ccbfd6',
- 'surface-light': '#424242',
- 'surface-variant': '#a3a3a3',
- 'on-surface-variant': '#424242',
- primary: '#2196F3',
- 'primary-darken-1': '#277CC1',
- secondary: '#54B6B2',
- 'secondary-darken-1': '#48A9A6',
- 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] : genDefaults$2();
- const defaults = genDefaults$2();
- if (!options) return {
- ...defaults,
- isDisabled: true
- };
- const themes = {};
- for (const [key, theme] of Object.entries(options.themes ?? {})) {
- const defaultTheme = theme.dark || key === 'dark' ? defaults.themes?.dark : defaults.themes?.light;
- themes[key] = mergeDeep(defaultTheme, theme);
- }
- return mergeDeep(defaults, {
- ...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]);
- theme.colors[onColor] = getForeground(colorVal);
- }
- }
- 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 current = vue.computed(() => theme.themes.value[name.value]);
- const themeClasses = vue.computed(() => theme.isDisabled ? undefined : `v-theme--${name.value}`);
- const newTheme = {
- ...theme,
- name,
- current,
- 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,
- 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": [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,
- group: Boolean
- },
- setup(props, _ref2) {
- let {
- slots
- } = _ref2;
- const tag = props.group ? vue.TransitionGroup : vue.Transition;
- return () => {
- return vue.h(tag, {
- 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, Array]
- }, '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 = getTargetBox(target);
- 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(() => {
- const styles = {};
- const height = convertToUnit(props.height);
- const maxHeight = convertToUnit(props.maxHeight);
- const maxWidth = convertToUnit(props.maxWidth);
- const minHeight = convertToUnit(props.minHeight);
- const minWidth = convertToUnit(props.minWidth);
- const width = convertToUnit(props.width);
- if (height != null) styles.height = height;
- if (maxHeight != null) styles.maxHeight = maxHeight;
- if (maxWidth != null) styles.maxWidth = maxWidth;
- if (minHeight != null) styles.minHeight = minHeight;
- if (minWidth != null) styles.minWidth = minWidth;
- if (width != null) styles.width = width;
- return styles;
- });
- 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: null,
- 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
- // Composables
- function useColor(colors) {
- return destructComputed(() => {
- const classes = [];
- const styles = {};
- if (colors.value.background) {
- if (isCssColor(colors.value.background)) {
- styles.backgroundColor = colors.value.background;
- if (!colors.value.text && isParsableColor(colors.value.background)) {
- const backgroundColor = parseColor(colors.value.background);
- if (backgroundColor.a == null || backgroundColor.a === 1) {
- const textColor = getForeground(backgroundColor);
- styles.color = textColor;
- styles.caretColor = textColor;
- }
- }
- } 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 makeRoundedProps = propsFactory({
- rounded: {
- type: [Boolean, Number, String],
- default: undefined
- },
- tile: Boolean
- }, '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 tile = vue.isRef(props) ? props.value : props.tile;
- 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}`);
- }
- } else if (tile || rounded === false) {
- classes.push('rounded-0');
- }
- return classes;
- });
- return {
- roundedClasses
- };
- }
- // 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,
- group,
- ...rest
- } = props;
- const {
- component = group ? vue.TransitionGroup : vue.Transition,
- ...customProps
- } = typeof transition === 'object' ? transition : {};
- return vue.h(component, vue.mergeProps(typeof transition === 'string' ? {
- name: disabled ? '' : transition
- } : customProps, typeof transition === 'string' ? {} : Object.fromEntries(Object.entries({
- disabled,
- group
- }).filter(_ref2 => {
- let [_, v] = _ref2;
- return v !== undefined;
- })), rest), 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
- // not intended for public use, this is passed in by vuetify-loader
- const makeVImgProps = propsFactory({
- absolute: Boolean,
- alt: String,
- cover: Boolean,
- color: String,
- draggable: {
- type: [Boolean, String],
- default: undefined
- },
- 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: ''
- },
- crossorigin: String,
- referrerpolicy: String,
- srcset: String,
- position: String,
- ...makeVResponsiveProps(),
- ...makeComponentProps(),
- ...makeRoundedProps(),
- ...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 {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- const {
- roundedClasses
- } = useRounded(props);
- const vm = getCurrentInstance('VImg');
- 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);
- setTimeout(() => {
- if (vm.isUnmounted) return;
- if (image.value?.complete) {
- if (!image.value.naturalWidth) {
- onError();
- }
- if (state.value === 'error') return;
- if (!aspectRatio.value) pollForSize(image.value, null);
- if (state.value === 'loading') onLoad();
- } else {
- if (!aspectRatio.value) pollForSize(image.value);
- getSrc();
- }
- });
- });
- }
- function onLoad() {
- if (vm.isUnmounted) return;
- getSrc();
- pollForSize(image.value);
- state.value = 'loaded';
- emit('load', image.value?.currentSrc || normalisedSrc.value.src);
- }
- function onError() {
- if (vm.isUnmounted) return;
- 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;
- vue.onBeforeUnmount(() => {
- clearTimeout(timer);
- });
- function pollForSize(img) {
- let timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100;
- const poll = () => {
- clearTimeout(timer);
- if (vm.isUnmounted) return;
- 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],
- "style": {
- objectPosition: props.position
- },
- "src": normalisedSrc.value.src,
- "srcset": normalisedSrc.value.srcset,
- "alt": props.alt,
- "crossorigin": props.crossorigin,
- "referrerpolicy": props.referrerpolicy,
- "draggable": props.draggable,
- "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],
- "style": {
- objectPosition: props.position
- },
- "src": normalisedSrc.value.lazySrc,
- "alt": props.alt,
- "crossorigin": props.crossorigin,
- "referrerpolicy": props.referrerpolicy,
- "draggable": props.draggable
- }, 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--absolute': props.absolute,
- 'v-img--booting': !isBooted.value
- }, backgroundColorClasses.value, roundedClasses.value, props.class],
- "style": [{
- width: convertToUnit(props.width === 'auto' ? naturalWidth.value : props.width)
- }, backgroundColorStyles.value, 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
- 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
- };
- }
- // 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;
- let previousScrollHeight = 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;
- const currentScrollHeight = targetEl instanceof Window ? document.documentElement.scrollHeight : targetEl.scrollHeight;
- if (previousScrollHeight !== currentScrollHeight) {
- previousScrollHeight = currentScrollHeight;
- return;
- }
- 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 canHide = vue.computed(() => scrollBehavior.value.hide || scrollBehavior.value.fullyHide);
- 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.fullyHide && !isActive.value || 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;
- if (!canHide.value) return height + extensionHeight;
- return currentScroll.value < scrollThreshold.value || scrollBehavior.value.fullyHide ? height + extensionHeight : height;
- });
- useToggleScope(vue.computed(() => !!props.scrollBehavior), () => {
- vue.watchEffect(() => {
- if (canHide.value) {
- 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({
- baseColor: String,
- 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',
- baseColor: vue.toRef(props, 'baseColor'),
- 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');
- // Composables
- 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 isFirst = vue.computed(() => {
- return group.items.value[0].id === id;
- });
- const isLast = vue.computed(() => {
- return group.items.value[group.items.value.length - 1].id === id;
- });
- const selectedClass = vue.computed(() => isSelected.value && [group.selectedClass.value, props.selectedClass]);
- vue.watch(isSelected, value => {
- vm.emit('group:selected', {
- value
- });
- }, {
- flush: 'sync'
- });
- return {
- id,
- isSelected,
- isFirst,
- isLast,
- 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 (vue.unref(unwrapped.value) == null) {
- unwrapped.value = index;
- unwrapped.useIndexAsValue = true;
- }
- 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;
- });
- vue.onUpdated(() => {
- // #19655 update the items that use the index as the value.
- for (let i = 0; i < items.length; i++) {
- if (items[i].useIndexAsValue) {
- items[i].value = i;
- }
- }
- });
- 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',
- treeviewCollapse: 'mdi-menu-down',
- treeviewExpand: 'mdi-menu-right',
- eyeDropper: 'mdi-eyedropper',
- upload: 'mdi-cloud-upload'
- };
- 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);
- };
- }
- });
- function genDefaults$1() {
- return {
- svg: {
- component: VSvgIcon
- },
- class: {
- component: VClassIcon
- }
- };
- }
- // Composables
- function createIcons(options) {
- const sets = genDefaults$1();
- const defaultSet = options?.defaultSet ?? 'mdi';
- if (defaultSet === 'mdi' && !sets.mdi) {
- sets.mdi = mdi;
- }
- return mergeDeep({
- defaultSet,
- sets,
- 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',
- 'vuetify-play': ['m6.376 13.184-4.11-7.192C1.505 4.66 2.467 3 4.003 3h8.532l-.953 1.576-.006.01-.396.677c-.429.732-.214 1.507.194 2.015.404.503 1.092.878 1.869.806a3.72 3.72 0 0 1 1.005.022c.276.053.434.143.523.237.138.146.38.635-.25 2.09-.893 1.63-1.553 1.722-1.847 1.677-.213-.033-.468-.158-.756-.406a4.95 4.95 0 0 1-.8-.927c-.39-.564-1.04-.84-1.66-.846-.625-.006-1.316.27-1.693.921l-.478.826-.911 1.506Z', ['M9.093 11.552c.046-.079.144-.15.32-.148a.53.53 0 0 1 .43.207c.285.414.636.847 1.046 1.2.405.35.914.662 1.516.754 1.334.205 2.502-.698 3.48-2.495l.014-.028.013-.03c.687-1.574.774-2.852-.005-3.675-.37-.391-.861-.586-1.333-.676a5.243 5.243 0 0 0-1.447-.044c-.173.016-.393-.073-.54-.257-.145-.18-.127-.316-.082-.392l.393-.672L14.287 3h5.71c1.536 0 2.499 1.659 1.737 2.992l-7.997 13.996c-.768 1.344-2.706 1.344-3.473 0l-3.037-5.314 1.377-2.278.004-.006.004-.007.481-.831Z', 0.6]]
- /* 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) consoleWarn(`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,
- disabled: Boolean,
- 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;
- }
- const hasClick = !!(attrs.onClick || attrs.onClickOnce);
- 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': hasClick,
- 'v-icon--disabled': props.disabled,
- '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": hasClick ? 'button' : undefined,
- "aria-hidden": !hasClick,
- "tabindex": hasClick ? props.disabled ? -1 : 0 : undefined
- }, {
- 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
- },
- bufferColor: String,
- bufferOpacity: [Number, String],
- clickable: Boolean,
- color: String,
- height: {
- type: [Number, String],
- default: 4
- },
- indeterminate: Boolean,
- max: {
- type: [Number, String],
- default: 100
- },
- modelValue: {
- type: [Number, String],
- default: 0
- },
- opacity: [Number, String],
- 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: bufferColorClasses,
- backgroundColorStyles: bufferColorStyles
- } = useBackgroundColor(vue.computed(() => props.bufferColor || props.bgColor || props.color));
- const {
- backgroundColorClasses: barColorClasses,
- backgroundColorStyles: barColorStyles
- } = useBackgroundColor(props, 'color');
- const {
- roundedClasses
- } = useRounded(props);
- const {
- intersectionRef,
- isIntersecting
- } = useIntersectionObserver();
- const max = vue.computed(() => parseFloat(props.max));
- const height = vue.computed(() => parseFloat(props.height));
- const normalizedBuffer = vue.computed(() => clamp(parseFloat(props.bufferValue) / max.value * 100, 0, 100));
- const normalizedValue = vue.computed(() => clamp(parseFloat(progress.value) / max.value * 100, 0, 100));
- const isReversed = vue.computed(() => isRtl.value !== props.reverse);
- const transition = vue.computed(() => props.indeterminate ? 'fade-transition' : 'slide-x-transition');
- const isForcedColorsModeActive = IN_BROWSER && window.matchMedia?.('(forced-colors: active)').matches;
- 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),
- ...(props.absolute ? 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: parseFloat(props.bufferOpacity),
- 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', !isForcedColorsModeActive ? backgroundColorClasses.value : undefined],
- "style": [backgroundColorStyles.value, {
- opacity: parseFloat(props.bgOpacity),
- width: props.stream ? 0 : undefined
- }]
- }, null), vue.createVNode("div", {
- "class": ['v-progress-linear__buffer', !isForcedColorsModeActive ? bufferColorClasses.value : undefined],
- "style": [bufferColorStyles.value, {
- opacity: parseFloat(props.bufferOpacity),
- width: convertToUnit(normalizedBuffer.value, '%')
- }]
- }, null), vue.createVNode(vue.Transition, {
- "name": transition.value
- }, {
- default: () => [!props.indeterminate ? vue.createVNode("div", {
- "class": ['v-progress-linear__determinate', !isForcedColorsModeActive ? barColorClasses.value : undefined],
- "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, !isForcedColorsModeActive ? barColorClasses.value : undefined],
- "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, {
- "absolute": props.absolute,
- "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
- // Types
- function useRoute() {
- const vm = getCurrentInstance('useRoute');
- return vue.computed(() => vm?.proxy?.$route);
- }
- 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' || !('useLink' in RouterLink)) {
- const href = vue.toRef(props, 'href');
- return {
- isLink,
- isClickable,
- href,
- linkProps: vue.reactive({
- href
- })
- };
- }
- // vue-router useLink `to` prop needs to be reactive and useLink will crash if undefined
- const linkProps = vue.computed(() => ({
- ...props,
- to: vue.toRef(() => props.to || '')
- }));
- const routerLink = RouterLink.useLink(linkProps.value);
- // Actual link needs to be undefined when to prop is not used
- const link = vue.computed(() => props.to ? routerLink : undefined);
- const route = useRoute();
- const isActive = vue.computed(() => {
- if (!link.value) return false;
- if (!props.exact) return link.value.isActive?.value ?? false;
- if (!route.value) return link.value.isExactActive?.value ?? false;
- return link.value.isExactActive?.value && deepEqual(link.value.route.value.query, route.value.query);
- });
- const href = vue.computed(() => props.to ? link.value?.route.value.href : props.href);
- return {
- isLink,
- isClickable,
- isActive,
- route: link.value?.route,
- navigate: link.value?.navigate,
- href,
- linkProps: vue.reactive({
- href,
- 'aria-current': vue.computed(() => isActive.value ? 'page' : undefined)
- })
- };
- }
- 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
- },
- activeColor: String,
- baseColor: String,
- symbol: {
- type: null,
- default: VBtnToggleSymbol
- },
- flat: Boolean,
- icon: [Boolean, String, Function, Object],
- prependIcon: IconValue,
- appendIcon: IconValue,
- block: Boolean,
- readonly: Boolean,
- slim: 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',
- props: makeVBtnProps(),
- emits: {
- 'group:selected': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- borderClasses
- } = useBorder(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 color = vue.computed(() => isActive.value ? props.activeColor ?? props.color : props.color);
- const variantProps = vue.computed(() => {
- const showColor = group?.isSelected.value && (!link.isLink.value || link.isActive?.value) || !group || link.isActive?.value;
- return {
- color: showColor ? color.value ?? props.baseColor : props.baseColor,
- variant: props.variant
- };
- });
- const {
- colorClasses,
- colorStyles,
- variantClasses
- } = useVariant(variantProps);
- 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 || typeof props.value === 'symbol') 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);
- return vue.withDirectives(vue.createVNode(Tag, vue.mergeProps({
- "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--readonly': props.readonly,
- 'v-btn--slim': props.slim,
- 'v-btn--stacked': props.stacked
- }, themeClasses.value, borderClasses.value, colorClasses.value, densityClasses.value, elevationClasses.value, loaderClasses.value, positionClasses.value, roundedClasses.value, sizeClasses.value, variantClasses.value, props.class],
- "style": [colorStyles.value, dimensionStyles.value, locationStyles.value, sizeStyles.value, props.style],
- "aria-busy": props.loading ? true : undefined,
- "disabled": isDisabled.value || undefined,
- "tabindex": props.loading || props.readonly ? -1 : undefined,
- "onClick": onClick,
- "value": valueAttr.value
- }, link.linkProps), {
- 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,
- "width": "2"
- }, null)])]
- }), [[Ripple, !isDisabled.value && props.ripple, '', {
- center: !!props.icon
- }]]);
- });
- return {
- group
- };
- }
- });
- // 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 makeVAvatarProps = propsFactory({
- start: Boolean,
- end: Boolean,
- icon: IconValue,
- image: String,
- text: String,
- ...makeBorderProps(),
- ...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 {
- borderClasses
- } = useBorder(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, borderClasses.value, colorClasses.value, densityClasses.value, roundedClasses.value, sizeClasses.value, variantClasses.value, props.class],
- "style": [colorStyles.value, sizeStyles.value, props.style]
- }, {
- default: () => [!slots.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) : props.text : vue.createVNode(VDefaultsProvider, {
- "key": "content-defaults",
- "defaults": {
- VImg: {
- cover: true,
- src: props.image
- },
- VIcon: {
- icon: props.icon
- }
- }
- }, {
- default: () => [slots.default()]
- }), genOverlays(false, 'v-avatar')]
- }));
- return {};
- }
- });
- const makeVLabelProps = propsFactory({
- text: String,
- onClick: EventProp(),
- ...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.onClick
- }, props.class],
- "style": props.style,
- "onClick": props.onClick
- }, [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, Object],
- default: true
- },
- multiple: {
- type: Boolean,
- default: null
- },
- name: String,
- readonly: {
- type: Boolean,
- default: null
- },
- 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': value => 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,
- baseColor: 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 ? wrapInArray(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(() => {
- if (props.error || props.disabled) return undefined;
- return model.value ? props.color : props.baseColor;
- }));
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.computed(() => {
- return model.value && !props.error && !props.disabled ? props.color : props.baseColor;
- }));
- const icon = vue.computed(() => model.value ? props.trueIcon : props.falseIcon);
- return {
- group,
- densityClasses,
- trueValue,
- falseValue,
- model,
- textColorClasses,
- textColorStyles,
- backgroundColorClasses,
- backgroundColorStyles,
- icon
- };
- }
- const VSelectionControl = genericComponent()({
- name: 'VSelectionControl',
- directives: {
- Ripple
- },
- inheritAttrs: false,
- props: makeVSelectionControlProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- group,
- densityClasses,
- icon,
- model,
- textColorClasses,
- textColorStyles,
- backgroundColorClasses,
- backgroundColorStyles,
- trueValue
- } = useSelectionControl(props);
- const uid = getUid();
- const isFocused = vue.shallowRef(false);
- const isFocusVisible = vue.shallowRef(false);
- const input = vue.ref();
- const id = vue.computed(() => props.id || `input-${uid}`);
- const isInteractive = vue.computed(() => !props.disabled && !props.readonly);
- group?.onForceUpdate(() => {
- if (input.value) {
- input.value.checked = model.value;
- }
- });
- function onFocus(e) {
- if (!isInteractive.value) return;
- isFocused.value = true;
- if (matchesSelector(e.target, ':focus-visible') !== false) {
- isFocusVisible.value = true;
- }
- }
- function onBlur() {
- isFocused.value = false;
- isFocusVisible.value = false;
- }
- function onClickLabel(e) {
- e.stopPropagation();
- }
- function onInput(e) {
- if (!isInteractive.value) {
- if (input.value) {
- // model value is not updated when input is not interactive
- // but the internal checked state of the input is still updated,
- // so here it's value is restored
- input.value.checked = model.value;
- }
- return;
- }
- 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);
- const inputNode = vue.createVNode("input", vue.mergeProps({
- "ref": input,
- "checked": model.value,
- "disabled": !!props.disabled,
- "id": id.value,
- "onBlur": onBlur,
- "onFocus": onFocus,
- "onInput": onInput,
- "aria-disabled": !!props.disabled,
- "aria-label": props.label,
- "type": props.type,
- "value": trueValue.value,
- "name": props.name,
- "aria-checked": props.type === 'checkbox' ? model.value : undefined
- }, inputAttrs), null);
- 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?.({
- backgroundColorClasses,
- backgroundColorStyles
- }), vue.withDirectives(vue.createVNode("div", {
- "class": ['v-selection-control__input']
- }, [slots.input?.({
- model,
- textColorClasses,
- textColorStyles,
- backgroundColorClasses,
- backgroundColorStyles,
- inputNode,
- icon: icon.value,
- props: {
- onFocus,
- onBlur,
- id: id.value
- }
- }) ?? vue.createVNode(vue.Fragment, null, [icon.value && vue.createVNode(VIcon, {
- "key": "icon",
- "icon": icon.value
- }, null), inputNode])]), [[vue.resolveDirective("ripple"), props.ripple && [!props.disabled && !props.readonly, null, ['center', 'circle']]]])]), label && vue.createVNode(VLabel, {
- "for": id.value,
- "onClick": onClickLabel
- }, {
- 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': value => 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(() => {
- const controlProps = omit(VSelectionControl.filterProps(props), ['modelValue']);
- return vue.createVNode(VSelectionControl, vue.mergeProps(controlProps, {
- "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,
- flush: 'post'
- });
- vue.provide(FormKey, {
- register: _ref => {
- let {
- id,
- vm,
- validate,
- reset,
- resetValidation
- } = _ref;
- if (items.value.some(item => item.id === id)) {
- consoleWarn(`Duplicate input name "${id}"`);
- }
- items.value.push({
- id,
- validate,
- reset,
- resetValidation,
- vm: vue.markRaw(vm),
- 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(props) {
- const form = vue.inject(FormKey, null);
- return {
- ...form,
- isReadonly: vue.computed(() => !!(props?.readonly ?? form?.isReadonly.value)),
- isDisabled: vue.computed(() => !!(props?.disabled ?? form?.isDisabled.value))
- };
- }
- // 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(props);
- 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 errorMessages = vue.computed(() => {
- return props.errorMessages?.length ? wrapInArray(props.errorMessages).concat(internalErrorMessages.value).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';
- if (value === 'eager') value = 'input eager';
- const set = new Set(value?.split(' ') ?? []);
- return {
- input: set.has('input'),
- blur: set.has('blur') || set.has('input') || set.has('invalid-input'),
- invalidInput: set.has('invalid-input'),
- lazy: set.has('lazy'),
- eager: set.has('eager')
- };
- });
- 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`]: form.isDisabled.value,
- [`${name}--readonly`]: form.isReadonly.value
- };
- });
- const vm = getCurrentInstance('validation');
- const uid = vue.computed(() => props.name ?? vue.unref(id));
- vue.onBeforeMount(() => {
- form.register?.({
- id: uid.value,
- vm,
- validate,
- reset,
- resetValidation
- });
- });
- vue.onBeforeUnmount(() => {
- form.unregister?.(uid.value);
- });
- vue.onMounted(async () => {
- if (!validateOn.value.lazy) {
- await validate(!validateOn.value.eager);
- }
- form.update?.(uid.value, isValid.value, errorMessages.value);
- });
- useToggleScope(() => validateOn.value.input || validateOn.value.invalidInput && isValid.value === false, () => {
- 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, errorMessages], () => {
- form.update?.(uid.value, isValid.value, errorMessages.value);
- });
- async function reset() {
- model.value = null;
- await vue.nextTick();
- await resetValidation();
- }
- async function resetValidation() {
- isPristine.value = true;
- if (!validateOn.value.lazy) {
- await validate(!validateOn.value.eager);
- } 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: form.isDisabled,
- isReadonly: form.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],
- hideSpinButtons: Boolean,
- 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(),
- ...only(makeDimensionProps(), ['maxWidth', 'minWidth', 'width']),
- ...makeThemeProps(),
- ...makeValidationProps()
- }, 'VInput');
- const VInput = genericComponent()({
- name: 'VInput',
- props: {
- ...makeVInputProps()
- },
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots,
- emit
- } = _ref;
- const {
- densityClasses
- } = useDensity(props);
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- themeClasses
- } = provideTheme(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,
- 'v-input--hide-spin-buttons': props.hideSpinButtons
- }, densityClasses.value, themeClasses.value, rtlClasses.value, validationClasses.value, props.class],
- "style": [dimensionStyles.value, 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,
- isValid,
- errorMessages
- };
- }
- });
- // 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 [rootAttrs, controlAttrs] = filterInputAttrs(attrs);
- const inputProps = VInput.filterProps(props);
- const checkboxProps = VCheckboxBtn.filterProps(props);
- return vue.createVNode(VInput, vue.mergeProps({
- "class": ['v-checkbox', props.class]
- }, rootAttrs, 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,
- isValid
- } = _ref2;
- return vue.createVNode(VCheckboxBtn, vue.mergeProps(checkboxProps, {
- "id": id.value,
- "aria-describedby": messagesId.value,
- "disabled": isDisabled.value,
- "readonly": isReadonly.value
- }, controlAttrs, {
- "error": isValid.value === false,
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "onFocus": focus,
- "onBlur": blur
- }), slots);
- }
- });
- });
- return {};
- }
- });
- // 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
- };
- }
- const makeDisplayProps = propsFactory({
- mobile: {
- type: Boolean,
- default: false
- },
- mobileBreakpoint: [Number, String]
- }, 'display');
- function useDisplay() {
- let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();
- const display = vue.inject(DisplaySymbol);
- if (!display) throw new Error('Could not find Vuetify display injection');
- const mobile = vue.computed(() => {
- if (props.mobile != null) return props.mobile;
- if (!props.mobileBreakpoint) return display.mobile.value;
- const breakpointValue = typeof props.mobileBreakpoint === 'number' ? props.mobileBreakpoint : display.thresholds.value[props.mobileBreakpoint];
- return display.width.value < breakpointValue;
- });
- const displayClasses = vue.computed(() => {
- if (!name) return {};
- return {
- [`${name}--mobile`]: mobile.value
- };
- });
- return {
- ...display,
- displayClasses,
- mobile
- };
- }
- // Utilities
- // Types
- const GoToSymbol = Symbol.for('vuetify:goto');
- function genDefaults() {
- return {
- container: undefined,
- duration: 300,
- layout: false,
- offset: 0,
- easing: 'easeInOutCubic',
- patterns: {
- linear: t => t,
- easeInQuad: t => t ** 2,
- easeOutQuad: t => t * (2 - t),
- easeInOutQuad: t => t < 0.5 ? 2 * t ** 2 : -1 + (4 - 2 * t) * t,
- easeInCubic: t => t ** 3,
- easeOutCubic: t => --t ** 3 + 1,
- easeInOutCubic: t => t < 0.5 ? 4 * t ** 3 : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
- easeInQuart: t => t ** 4,
- easeOutQuart: t => 1 - --t ** 4,
- easeInOutQuart: t => t < 0.5 ? 8 * t ** 4 : 1 - 8 * --t ** 4,
- easeInQuint: t => t ** 5,
- easeOutQuint: t => 1 + --t ** 5,
- easeInOutQuint: t => t < 0.5 ? 16 * t ** 5 : 1 + 16 * --t ** 5
- }
- };
- }
- function getContainer(el) {
- return getTarget$1(el) ?? (document.scrollingElement || document.body);
- }
- function getTarget$1(el) {
- return typeof el === 'string' ? document.querySelector(el) : refElement(el);
- }
- function getOffset$2(target, horizontal, rtl) {
- if (typeof target === 'number') return horizontal && rtl ? -target : target;
- let el = getTarget$1(target);
- let totalOffset = 0;
- while (el) {
- totalOffset += horizontal ? el.offsetLeft : el.offsetTop;
- el = el.offsetParent;
- }
- return totalOffset;
- }
- function createGoTo(options, locale) {
- return {
- rtl: locale.isRtl,
- options: mergeDeep(genDefaults(), options)
- };
- }
- async function scrollTo(_target, _options, horizontal, goTo) {
- const property = horizontal ? 'scrollLeft' : 'scrollTop';
- const options = mergeDeep(goTo?.options ?? genDefaults(), _options);
- const rtl = goTo?.rtl.value;
- const target = (typeof _target === 'number' ? _target : getTarget$1(_target)) ?? 0;
- const container = options.container === 'parent' && target instanceof HTMLElement ? target.parentElement : getContainer(options.container);
- const ease = typeof options.easing === 'function' ? options.easing : options.patterns[options.easing];
- if (!ease) throw new TypeError(`Easing function "${options.easing}" not found.`);
- let targetLocation;
- if (typeof target === 'number') {
- targetLocation = getOffset$2(target, horizontal, rtl);
- } else {
- targetLocation = getOffset$2(target, horizontal, rtl) - getOffset$2(container, horizontal, rtl);
- if (options.layout) {
- const styles = window.getComputedStyle(target);
- const layoutOffset = styles.getPropertyValue('--v-layout-top');
- if (layoutOffset) targetLocation -= parseInt(layoutOffset, 10);
- }
- }
- targetLocation += options.offset;
- targetLocation = clampTarget(container, targetLocation, !!rtl, !!horizontal);
- const startLocation = container[property] ?? 0;
- if (targetLocation === startLocation) return Promise.resolve(targetLocation);
- const startTime = performance.now();
- return new Promise(resolve => requestAnimationFrame(function step(currentTime) {
- const timeElapsed = currentTime - startTime;
- const progress = timeElapsed / options.duration;
- const location = Math.floor(startLocation + (targetLocation - startLocation) * ease(clamp(progress, 0, 1)));
- container[property] = location;
- // Allow for some jitter if target time has elapsed
- if (progress >= 1 && Math.abs(location - container[property]) < 10) {
- return resolve(targetLocation);
- } else if (progress > 2) {
- // The target might not be reachable
- consoleWarn('Scroll target is not reachable');
- return resolve(container[property]);
- }
- requestAnimationFrame(step);
- }));
- }
- function useGoTo() {
- let _options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- const goToInstance = vue.inject(GoToSymbol);
- const {
- isRtl
- } = useRtl();
- if (!goToInstance) throw new Error('[Vuetify] Could not find injected goto instance');
- const goTo = {
- ...goToInstance,
- // can be set via VLocaleProvider
- rtl: vue.computed(() => goToInstance.rtl.value || isRtl.value)
- };
- async function go(target, options) {
- return scrollTo(target, mergeDeep(_options, options), false, goTo);
- }
- go.horizontal = async (target, options) => {
- return scrollTo(target, mergeDeep(_options, options), true, goTo);
- };
- return go;
- }
- /**
- * Clamp target value to achieve a smooth scroll animation
- * when the value goes outside the scroll container size
- */
- function clampTarget(container, value, rtl, horizontal) {
- const {
- scrollWidth,
- scrollHeight
- } = container;
- const [containerWidth, containerHeight] = container === document.scrollingElement ? [window.innerWidth, window.innerHeight] : [container.offsetWidth, container.offsetHeight];
- let min;
- let max;
- if (horizontal) {
- if (rtl) {
- min = -(scrollWidth - containerWidth);
- max = 0;
- } else {
- min = 0;
- max = scrollWidth - containerWidth;
- }
- } else {
- min = 0;
- max = scrollHeight + -containerHeight;
- }
- return Math.max(Math.min(value, max), min);
- }
- function calculateUpdatedTarget(_ref) {
- let {
- selectedElement,
- containerElement,
- isRtl,
- isHorizontal
- } = _ref;
- const containerSize = getOffsetSize(isHorizontal, containerElement);
- const scrollPosition = getScrollPosition(isHorizontal, isRtl, containerElement);
- const childrenSize = getOffsetSize(isHorizontal, selectedElement);
- const childrenStartPosition = getOffsetPosition(isHorizontal, selectedElement);
- const additionalOffset = childrenSize * 0.4;
- if (scrollPosition > childrenStartPosition) {
- return childrenStartPosition - additionalOffset;
- } else if (scrollPosition + containerSize < childrenStartPosition + childrenSize) {
- return childrenStartPosition - containerSize + childrenSize + additionalOffset;
- }
- return scrollPosition;
- }
- function calculateCenteredTarget(_ref2) {
- let {
- selectedElement,
- containerElement,
- isHorizontal
- } = _ref2;
- const containerOffsetSize = getOffsetSize(isHorizontal, containerElement);
- const childrenOffsetPosition = getOffsetPosition(isHorizontal, selectedElement);
- const childrenOffsetSize = getOffsetSize(isHorizontal, selectedElement);
- return childrenOffsetPosition - containerOffsetSize / 2 + childrenOffsetSize / 2;
- }
- function getScrollSize(isHorizontal, element) {
- const key = isHorizontal ? 'scrollWidth' : 'scrollHeight';
- return element?.[key] || 0;
- }
- function getClientSize(isHorizontal, element) {
- const key = isHorizontal ? 'clientWidth' : 'clientHeight';
- return element?.[key] || 0;
- }
- function getScrollPosition(isHorizontal, rtl, element) {
- if (!element) {
- return 0;
- }
- const {
- scrollLeft,
- offsetWidth,
- scrollWidth
- } = element;
- if (isHorizontal) {
- return rtl ? scrollWidth - offsetWidth + scrollLeft : scrollLeft;
- }
- return element.scrollTop;
- }
- function getOffsetSize(isHorizontal, element) {
- const key = isHorizontal ? 'offsetWidth' : 'offsetHeight';
- return element?.[key] || 0;
- }
- function getOffsetPosition(isHorizontal, element) {
- const key = isHorizontal ? 'offsetLeft' : 'offsetTop';
- return element?.[key] || 0;
- }
- // 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(),
- ...makeDisplayProps({
- mobile: null
- }),
- ...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 {
- displayClasses,
- mobile
- } = useDisplay(props);
- 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 goTo = useGoTo();
- const goToOptions = vue.computed(() => {
- return {
- container: containerRef.el,
- duration: 200,
- easing: 'easeOutQuart'
- };
- });
- 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.el) {
- // TODO: Is this too naive? Should we store element references in group composable?
- const selectedElement = contentRef.el.children[lastSelectedIndex.value];
- scrollToChildren(selectedElement, props.centerActive);
- }
- });
- });
- }
- const isFocused = vue.shallowRef(false);
- function scrollToChildren(children, center) {
- let target = 0;
- if (center) {
- target = calculateCenteredTarget({
- containerElement: containerRef.el,
- isHorizontal: isHorizontal.value,
- selectedElement: children
- });
- } else {
- target = calculateUpdatedTarget({
- containerElement: containerRef.el,
- isHorizontal: isHorizontal.value,
- isRtl: isRtl.value,
- selectedElement: children
- });
- }
- scrollToPosition(target);
- }
- function scrollToPosition(newPosition) {
- if (!IN_BROWSER || !containerRef.el) return;
- const offsetSize = getOffsetSize(isHorizontal.value, containerRef.el);
- const scrollPosition = getScrollPosition(isHorizontal.value, isRtl.value, containerRef.el);
- const scrollSize = getScrollSize(isHorizontal.value, containerRef.el);
- if (scrollSize <= offsetSize ||
- // Prevent scrolling by only a couple of pixels, which doesn't look smooth
- Math.abs(newPosition - scrollPosition) < 16) return;
- if (isHorizontal.value && isRtl.value && containerRef.el) {
- const {
- scrollWidth,
- offsetWidth: containerWidth
- } = containerRef.el;
- newPosition = scrollWidth - containerWidth - newPosition;
- }
- if (isHorizontal.value) {
- goTo.horizontal(newPosition, goToOptions.value);
- } else {
- goTo(newPosition, goToOptions.value);
- }
- }
- function onScroll(e) {
- const {
- scrollTop,
- scrollLeft
- } = e.target;
- scrollOffset.value = isHorizontal.value ? scrollLeft : scrollTop;
- }
- function onFocusin(e) {
- isFocused.value = true;
- if (!isOverflowing.value || !contentRef.el) 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.el.children) {
- if (item === el) {
- scrollToChildren(item);
- return;
- }
- }
- }
- }
- function onFocusout(e) {
- isFocused.value = false;
- }
- // Affix clicks produce onFocus that we have to ignore to avoid extra scrollToChildren
- let ignoreFocusEvent = false;
- function onFocus(e) {
- if (!ignoreFocusEvent && !isFocused.value && !(e.relatedTarget && contentRef.el?.contains(e.relatedTarget))) focus();
- ignoreFocusEvent = false;
- }
- function onFocusAffixes() {
- ignoreFocusEvent = true;
- }
- function onKeydown(e) {
- if (!contentRef.el) return;
- function toFocus(location) {
- e.preventDefault();
- focus(location);
- }
- if (isHorizontal.value) {
- if (e.key === 'ArrowRight') {
- toFocus(isRtl.value ? 'prev' : 'next');
- } else if (e.key === 'ArrowLeft') {
- toFocus(isRtl.value ? 'next' : 'prev');
- }
- } else {
- if (e.key === 'ArrowDown') {
- toFocus('next');
- } else if (e.key === 'ArrowUp') {
- toFocus('prev');
- }
- }
- if (e.key === 'Home') {
- toFocus('first');
- } else if (e.key === 'End') {
- toFocus('last');
- }
- }
- function focus(location) {
- if (!contentRef.el) return;
- let el;
- if (!location) {
- const focusable = focusableChildren(contentRef.el);
- el = focusable[0];
- } else if (location === 'next') {
- el = contentRef.el.querySelector(':focus')?.nextElementSibling;
- if (!el) return focus('first');
- } else if (location === 'prev') {
- el = contentRef.el.querySelector(':focus')?.previousElementSibling;
- if (!el) return focus('last');
- } else if (location === 'first') {
- el = contentRef.el.firstElementChild;
- } else if (location === 'last') {
- el = contentRef.el.lastElementChild;
- }
- if (el) {
- el.focus({
- preventScroll: true
- });
- }
- }
- function scrollTo(location) {
- const direction = isHorizontal.value && isRtl.value ? -1 : 1;
- const offsetStep = (location === 'prev' ? -direction : direction) * containerSize.value;
- let newPosition = scrollOffset.value + offsetStep;
- // TODO: improve it
- if (isHorizontal.value && isRtl.value && containerRef.el) {
- const {
- scrollWidth,
- offsetWidth: containerWidth
- } = containerRef.el;
- newPosition += scrollWidth - containerWidth;
- }
- scrollToPosition(newPosition);
- }
- 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(() => {
- // 1 pixel in reserve, may be lost after rounding
- return Math.abs(scrollOffset.value) > 1;
- });
- const hasNext = vue.computed(() => {
- if (!containerRef.value) return false;
- const scrollSize = getScrollSize(isHorizontal.value, containerRef.el);
- const clientSize = getClientSize(isHorizontal.value, containerRef.el);
- const scrollSizeMax = scrollSize - clientSize;
- // 1 pixel in reserve, may be lost after rounding
- return scrollSizeMax - Math.abs(scrollOffset.value) > 1;
- });
- 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
- }, displayClasses.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
- }],
- "onMousedown": onFocusAffixes,
- "onClick": () => hasPrev.value && 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",
- "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
- }],
- "onMousedown": onFocusAffixes,
- "onClick": () => hasNext.value && 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,
- hasPrev,
- hasNext
- };
- }
- });
- // Types
- const VChipGroupSymbol = Symbol.for('vuetify:v-chip-group');
- const makeVChipGroupProps = propsFactory({
- column: Boolean,
- filter: Boolean,
- valueComparator: {
- type: Function,
- default: deepEqual
- },
- ...makeVSlideGroupProps(),
- ...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(() => {
- const slideGroupProps = VSlideGroup.filterProps(props);
- return vue.createVNode(VSlideGroup, vue.mergeProps(slideGroupProps, {
- "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: IconValue,
- 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) {
- e.preventDefault();
- e.stopPropagation();
- 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, vue.mergeProps({
- "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,
- [`${props.activeClass}`]: props.activeClass && link.isActive?.value
- }, 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,
- "tabindex": isClickable.value ? 0 : undefined,
- "onClick": onClick,
- "onKeydown": isClickable.value && !isLink.value && onKeyDown
- }, link.linkProps), {
- 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",
- "data-no-activator": ""
- }, [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("button", vue.mergeProps({
- "key": "close",
- "class": "v-chip__close",
- "type": "button",
- "data-testid": "close-chip"
- }, 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);
- }
- /* eslint-disable sonarjs/no-identical-functions */
- // Utilities
- const independentActiveStrategy = mandatory => {
- const strategy = {
- activate: _ref => {
- let {
- id,
- value,
- activated
- } = _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 && activated.size === 1 && activated.has(id)) return activated;
- if (value) {
- activated.add(id);
- } else {
- activated.delete(id);
- }
- return activated;
- },
- in: (v, children, parents) => {
- let set = new Set();
- if (v != null) {
- for (const id of wrapInArray(v)) {
- set = strategy.activate({
- id,
- value: true,
- activated: new Set(set),
- children,
- parents
- });
- }
- }
- return set;
- },
- out: v => {
- return Array.from(v);
- }
- };
- return strategy;
- };
- const independentSingleActiveStrategy = mandatory => {
- const parentStrategy = independentActiveStrategy(mandatory);
- const strategy = {
- activate: _ref2 => {
- let {
- activated,
- id,
- ...rest
- } = _ref2;
- id = vue.toRaw(id);
- const singleSelected = activated.has(id) ? new Set([id]) : new Set();
- return parentStrategy.activate({
- ...rest,
- id,
- activated: singleSelected
- });
- },
- in: (v, children, parents) => {
- let set = new Set();
- if (v != null) {
- const arr = wrapInArray(v);
- if (arr.length) {
- set = parentStrategy.in(arr.slice(0, 1), children, parents);
- }
- }
- return set;
- },
- out: (v, children, parents) => {
- return parentStrategy.out(v, children, parents);
- }
- };
- return strategy;
- };
- const leafActiveStrategy = mandatory => {
- const parentStrategy = independentActiveStrategy(mandatory);
- const strategy = {
- activate: _ref3 => {
- let {
- id,
- activated,
- children,
- ...rest
- } = _ref3;
- id = vue.toRaw(id);
- if (children.has(id)) return activated;
- return parentStrategy.activate({
- id,
- activated,
- children,
- ...rest
- });
- },
- in: parentStrategy.in,
- out: parentStrategy.out
- };
- return strategy;
- };
- const leafSingleActiveStrategy = mandatory => {
- const parentStrategy = independentSingleActiveStrategy(mandatory);
- const strategy = {
- activate: _ref4 => {
- let {
- id,
- activated,
- children,
- ...rest
- } = _ref4;
- id = vue.toRaw(id);
- if (children.has(id)) return activated;
- return parentStrategy.activate({
- id,
- activated,
- children,
- ...rest
- });
- },
- in: parentStrategy.in,
- out: parentStrategy.out
- };
- return strategy;
- };
- 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;
- if (value === 'on') arr.push(key);
- return 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(vue.toRaw(item), value ? 'on' : 'off');
- if (children.has(item)) {
- items.push(...children.get(item));
- }
- }
- let parent = vue.toRaw(parents.get(id));
- while (parent) {
- const childrenIds = children.get(parent);
- const everySelected = childrenIds.every(cid => selected.get(vue.toRaw(cid)) === 'on');
- const noneSelected = childrenIds.every(cid => !selected.has(vue.toRaw(cid)) || selected.get(vue.toRaw(cid)) === 'off');
- selected.set(parent, everySelected ? 'on' : noneSelected ? 'off' : 'indeterminate');
- parent = vue.toRaw(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;
- if (value === 'on') arr.push(key);
- return 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,
- activate: () => null,
- select: () => null,
- activatable: vue.ref(false),
- selectable: vue.ref(false),
- opened: vue.ref(new Set()),
- activated: vue.ref(new Set()),
- selected: vue.ref(new Map()),
- selectedValues: vue.ref([]),
- getPath: () => []
- }
- };
- const makeNestedProps = propsFactory({
- activatable: Boolean,
- selectable: Boolean,
- activeStrategy: [String, Function, Object],
- selectStrategy: [String, Function, Object],
- openStrategy: [String, Object],
- opened: null,
- activated: null,
- selected: null,
- 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 activeStrategy = vue.computed(() => {
- if (typeof props.activeStrategy === 'object') return props.activeStrategy;
- if (typeof props.activeStrategy === 'function') return props.activeStrategy(props.mandatory);
- switch (props.activeStrategy) {
- case 'leaf':
- return leafActiveStrategy(props.mandatory);
- case 'single-leaf':
- return leafSingleActiveStrategy(props.mandatory);
- case 'independent':
- return independentActiveStrategy(props.mandatory);
- case 'single-independent':
- default:
- return independentSingleActiveStrategy(props.mandatory);
- }
- });
- const selectStrategy = vue.computed(() => {
- if (typeof props.selectStrategy === 'object') return props.selectStrategy;
- if (typeof props.selectStrategy === 'function') return props.selectStrategy(props.mandatory);
- 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 activated = useProxiedModel(props, 'activated', props.activated, v => activeStrategy.value.in(v, children.value, parents.value), v => activeStrategy.value.out(v, children.value, parents.value));
- 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 nodeIds = new Set();
- const nested = {
- id: vue.shallowRef(),
- root: {
- opened,
- activatable: vue.toRef(props, 'activatable'),
- selectable: vue.toRef(props, 'selectable'),
- activated,
- 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) => {
- if (nodeIds.has(id)) {
- const path = getPath(id).map(String).join(' -> ');
- const newPath = getPath(parentId).concat(id).map(String).join(' -> ');
- consoleError(`Multiple nodes with the same ID\n\t${path}\n\t${newPath}`);
- return;
- } else {
- nodeIds.add(id);
- }
- 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;
- nodeIds.delete(id);
- 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);
- },
- 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);
- },
- activate: (id, value, event) => {
- if (!props.activatable) {
- return nested.root.select(id, true, event);
- }
- vm.emit('click:activate', {
- id,
- value,
- path: getPath(id),
- event
- });
- const newActivated = activeStrategy.value.activate({
- id,
- value,
- activated: new Set(activated.value),
- children: children.value,
- parents: parents.value,
- event
- });
- newActivated && (activated.value = newActivated);
- },
- children,
- parents,
- getPath
- }
- };
- 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)),
- activate: (activated, e) => parent.root.activate(computedId.value, activated, e),
- isActivated: vue.computed(() => parent.root.activated.value.has(vue.toRaw(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
- };
- vue.onBeforeMount(() => {
- !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) {
- e.stopPropagation();
- 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 {
- isOpen
- };
- }
- });
- const makeVListItemSubtitleProps = propsFactory({
- opacity: [Number, String],
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VListItemSubtitle');
- const VListItemSubtitle = genericComponent()({
- name: 'VListItemSubtitle',
- props: makeVListItemSubtitleProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-list-item-subtitle', props.class],
- "style": [{
- '--v-list-item-subtitle-opacity': props.opacity
- }, props.style]
- }, slots));
- return {};
- }
- });
- // 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: [Boolean, String],
- link: {
- type: Boolean,
- default: undefined
- },
- nav: Boolean,
- prependAvatar: String,
- prependIcon: IconValue,
- ripple: {
- type: [Boolean, Object],
- default: true
- },
- slim: Boolean,
- subtitle: [String, Number],
- title: [String, Number],
- 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 {
- activate,
- isActivated,
- select,
- isOpen,
- isSelected,
- isIndeterminate,
- isGroupActivator,
- root,
- parent,
- openOnSelect,
- id: uid
- } = useNestedItem(id, false);
- const list = useList();
- const isActive = vue.computed(() => props.active !== false && (props.active || link.isActive?.value || (root.activatable.value ? isActivated.value : isSelected.value)));
- const isLink = vue.computed(() => props.link !== false && link.isLink.value);
- const isSelectable = vue.computed(() => !!list && (root.selectable.value || root.activatable.value || props.value != null));
- const isClickable = vue.computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value || isSelectable.value));
- 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
- }));
- // useNestedItem doesn't call register until beforeMount,
- // so this can't be an immediate watcher as we don't know parent yet
- vue.watch(() => link.isActive?.value, val => {
- if (!val) return;
- handleActiveLink();
- });
- vue.onBeforeMount(() => {
- if (link.isActive?.value) handleActiveLink();
- });
- function handleActiveLink() {
- if (parent.value != null) {
- root.open(parent.value, true);
- }
- openOnSelect(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,
- isOpen: isOpen.value,
- isSelected: isSelected.value,
- isIndeterminate: isIndeterminate.value
- }));
- function onClick(e) {
- emit('click', e);
- if (!isClickable.value) return;
- link.navigate?.(e);
- if (isGroupActivator) return;
- if (root.activatable.value) {
- activate(!isActivated.value, e);
- } else if (root.selectable.value) {
- select(!isSelected.value, e);
- } else if (props.value != null) {
- select(!isSelected.value, e);
- }
- }
- function onKeyDown(e) {
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- e.target.dispatchEvent(new MouseEvent('click', e));
- }
- }
- useRender(() => {
- const Tag = isLink.value ? 'a' : props.tag;
- const hasTitle = slots.title || props.title != null;
- const hasSubtitle = slots.subtitle || props.subtitle != null;
- 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, vue.mergeProps({
- "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,
- 'v-list-item--slim': props.slim,
- [`${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],
- "tabindex": isClickable.value ? list ? -2 : 0 : undefined,
- "aria-selected": isSelectable.value ? root.activatable.value ? isActivated.value : root.selectable.value ? isSelected.value : isActive.value : undefined,
- "onClick": onClick,
- "onKeydown": isClickable.value && !isLink.value && onKeyDown
- }, link.linkProps), {
- 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__spacer"
- }, null)]), 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.createVNode("div", {
- "class": "v-list-item__spacer"
- }, null)])]
- }), [[vue.resolveDirective("ripple"), isClickable.value && props.ripple]]);
- });
- return {
- activate,
- isActivated,
- isGroupActivator,
- isSelected,
- list,
- select,
- root,
- id: uid
- };
- }
- });
- 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],
- opacity: [Number, String],
- thickness: [Number, String],
- vertical: Boolean,
- ...makeComponentProps(),
- ...makeThemeProps()
- }, 'VDivider');
- const VDivider = genericComponent()({
- name: 'VDivider',
- props: makeVDividerProps(),
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _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 ? 'height' : 'width'] = convertToUnit(props.length);
- }
- if (props.thickness) {
- styles[props.vertical ? 'borderRightWidth' : 'borderTopWidth'] = convertToUnit(props.thickness);
- }
- return styles;
- });
- useRender(() => {
- const divider = 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, {
- '--v-border-opacity': props.opacity
- }, props.style],
- "aria-orientation": !attrs.role || attrs.role === 'separator' ? props.vertical ? 'vertical' : 'horizontal' : undefined,
- "role": `${attrs.role || 'separator'}`
- }, null);
- if (!slots.default) return divider;
- return vue.createVNode("div", {
- "class": ['v-divider__wrapper', {
- 'v-divider__wrapper--vertical': props.vertical,
- 'v-divider__wrapper--inset': props.inset
- }]
- }, [divider, vue.createVNode("div", {
- "class": "v-divider__content"
- }, [slots.default()]), divider]);
- });
- return {};
- }
- });
- // Types
- const makeVListChildrenProps = propsFactory({
- items: Array,
- returnObject: Boolean
- }, '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 = VListGroup.filterProps(itemProps);
- return children ? vue.createVNode(VListGroup, vue.mergeProps({
- "value": itemProps?.value
- }, listGroupProps), {
- activator: _ref3 => {
- let {
- props: activatorProps
- } = _ref3;
- const listItemProps = {
- ...itemProps,
- ...activatorProps,
- value: props.returnObject ? item : itemProps.value
- };
- return slots.header ? slots.header({
- props: listItemProps
- }) : vue.createVNode(VListItem, listItemProps, slotsWithItem);
- },
- default: () => vue.createVNode(VListChildren, {
- "items": children,
- "returnObject": props.returnObject
- }, slots)
- }) : slots.item ? slots.item({
- props: itemProps
- }) : vue.createVNode(VListItem, vue.mergeProps(itemProps, {
- "value": props.returnObject ? item : itemProps.value
- }), 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,
- valueComparator: {
- type: Function,
- default: deepEqual
- }
- }, 'list-items');
- function transformItem$3(props, item) {
- const title = getPropertyFromItem(item, props.itemTitle, item);
- const value = 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 ? omit(item, ['children']) : 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$3(props, children) : undefined,
- raw: item
- };
- }
- function transformItems$3(props, items) {
- const array = [];
- for (const item of items) {
- array.push(transformItem$3(props, item));
- }
- return array;
- }
- function useItems(props) {
- const items = vue.computed(() => transformItems$3(props, props.items));
- const hasNullItem = vue.computed(() => items.value.some(item => item.value === null));
- function transformIn(value) {
- if (!hasNullItem.value) {
- // When the model value is null, return an InternalItem
- // based on null only if null is one of the items
- value = value.filter(v => v !== null);
- }
- return value.map(v => {
- if (props.returnObject && typeof v === 'string') {
- // String model value means value is a custom input value from combobox
- // Don't look up existing items if the model value is a string
- return transformItem$3(props, v);
- }
- return items.value.find(item => props.valueComparator(v, item.value)) || transformItem$3(props, v);
- });
- }
- function transformOut(value) {
- return props.returnObject ? value.map(_ref => {
- let {
- raw
- } = _ref;
- return raw;
- }) : value.map(_ref2 => {
- let {
- value
- } = _ref2;
- return value;
- });
- }
- return {
- items,
- transformIn,
- transformOut
- };
- }
- // Types
- function isPrimitive(value) {
- return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
- }
- function transformItem$2(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 ? omit(item, ['children']) : getPropertyFromItem(item, props.itemProps);
- const _props = {
- title,
- value,
- ...itemProps
- };
- return {
- type,
- title: _props.title,
- value: _props.value,
- props: _props,
- children: type === 'item' && children ? transformItems$2(props, children) : undefined,
- raw: item
- };
- }
- function transformItems$2(props, items) {
- const array = [];
- for (const item of items) {
- array.push(transformItem$2(props, item));
- }
- return array;
- }
- function useListItems(props) {
- const items = vue.computed(() => transformItems$2(props, props.items));
- return {
- items
- };
- }
- const makeVListProps = propsFactory({
- baseColor: String,
- /* @deprecated */
- activeColor: String,
- activeClass: String,
- bgColor: String,
- disabled: Boolean,
- expandIcon: IconValue,
- collapseIcon: IconValue,
- lines: {
- type: [Boolean, String],
- default: 'one'
- },
- slim: Boolean,
- nav: Boolean,
- 'onClick:open': EventProp(),
- 'onClick:select': EventProp(),
- 'onUpdate:opened': EventProp(),
- ...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': value => true,
- 'update:activated': value => true,
- 'update:opened': value => true,
- 'click:open': value => true,
- 'click:activate': 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 {
- children,
- open,
- parents,
- select,
- getPath
- } = 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,
- expandIcon: vue.toRef(props, 'expandIcon'),
- collapseIcon: vue.toRef(props, 'collapseIcon')
- },
- 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'),
- slim: vue.toRef(props, 'slim'),
- 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) {
- const target = e.target;
- if (!contentRef.value || ['INPUT', 'TEXTAREA'].includes(target.tagName)) 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 onMousedown(e) {
- isFocused.value = true;
- }
- 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,
- 'v-list--slim': props.slim
- }, 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,
- "onMousedown": onMousedown
- }, {
- default: () => [vue.createVNode(VListChildren, {
- "items": items.value,
- "returnObject": props.returnObject
- }, slots)]
- });
- });
- return {
- open,
- select,
- focus,
- children,
- parents,
- getPath
- };
- }
- });
- // 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(() => {
- window.removeEventListener('resize', onResize);
- updateLocation.value = undefined;
- });
- window.addEventListener('resize', onResize, {
- passive: true
- });
- if (typeof props.locationStrategy === 'function') {
- updateLocation.value = props.locationStrategy(data, props, contentStyles)?.updateLocation;
- } else {
- updateLocation.value = locationStrategies[props.locationStrategy](data, props, contentStyles)?.updateLocation;
- }
- });
- }
- 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')
- /* 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 = Array.isArray(data.target.value) || isFixedPosition(data.target.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.target, data.contentEl], (_ref, _ref2) => {
- let [newTarget, newContentEl] = _ref;
- let [oldTarget, oldContentEl] = _ref2;
- if (oldTarget && !Array.isArray(oldTarget)) observer.unobserve(oldTarget);
- if (newTarget && !Array.isArray(newTarget)) observer.observe(newTarget);
- 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(() => observe = true);
- if (!data.target.value || !data.contentEl.value) return;
- const targetBox = getTargetBox(data.target.value);
- 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 new Promise(resolve => setTimeout(resolve));
- 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.targetEl.value ?? data.contentEl.value, onScroll);
- }
- function blockScrollStrategy(data, props) {
- const offsetParent = data.root.value?.offsetParent;
- const scrollElements = [...new Set([...getScrollParents(data.targetEl.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'));
- const scrollBehavior = el.style.scrollBehavior;
- el.style.scrollBehavior = 'auto';
- 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;
- el.style.scrollBehavior = scrollBehavior;
- });
- 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.targetEl.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) {
- let clearDelay = () => {};
- function runDelay(isOpening) {
- clearDelay?.();
- const delay = Number(isOpening ? props.openDelay : props.closeDelay);
- return new Promise(resolve => {
- clearDelay = defer(delay, () => {
- cb?.(isOpening);
- resolve(isOpening);
- });
- });
- }
- function runOpenDelay() {
- return runDelay(true);
- }
- function runCloseDelay() {
- return runDelay(false);
- }
- return {
- clearDelay,
- runOpenDelay,
- runCloseDelay
- };
- }
- // Components
- // Types
- const makeActivatorProps = propsFactory({
- target: [String, Object],
- 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,
- contentEl
- } = _ref;
- const vm = getCurrentInstance('useActivator');
- 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 cursorTarget = vue.ref();
- const availableEvents = {
- onClick: e => {
- e.stopPropagation();
- activatorEl.value = e.currentTarget || e.target;
- if (!isActive.value) {
- cursorTarget.value = [e.clientX, e.clientY];
- }
- 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)) && !contentEl.value?.contains(document.activeElement)) {
- isActive.value = false;
- }
- });
- vue.watch(isActive, val => {
- if (!val) {
- setTimeout(() => {
- cursorTarget.value = undefined;
- });
- }
- }, {
- flush: 'post'
- });
- const activatorRef = templateRef();
- vue.watchEffect(() => {
- if (!activatorRef.value) return;
- vue.nextTick(() => {
- activatorEl.value = activatorRef.el;
- });
- });
- const targetRef = templateRef();
- const target = vue.computed(() => {
- if (props.target === 'cursor' && cursorTarget.value) return cursorTarget.value;
- if (targetRef.value) return targetRef.el;
- return getTarget(props.target, vm) || activatorEl.value;
- });
- const targetEl = vue.computed(() => {
- return Array.isArray(target.value) ? undefined : target.value;
- });
- 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,
- target,
- targetEl,
- targetRef,
- 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;
- const activator = getTarget(selector, vm);
- // The activator should only be a valid element (Ignore comments and text nodes)
- activatorEl.value = activator?.nodeType === Node.ELEMENT_NODE ? activator : undefined;
- return activatorEl.value;
- }
- }
- function getTarget(selector, vm) {
- if (!selector) return;
- let target;
- if (selector === 'parent') {
- let el = vm?.proxy?.$el?.parentNode;
- while (el?.hasAttribute('data-no-activator')) {
- el = el.parentNode;
- }
- target = el;
- } else if (typeof selector === 'string') {
- // Selector
- target = document.querySelector(selector);
- } else if ('$el' in selector) {
- // Component (ref)
- target = selector.$el;
- } else {
- // HTMLElement | Element | [x, y]
- target = selector;
- }
- return target;
- }
- // 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
- function useTeleport(target) {
- const teleportTarget = vue.computed(() => {
- const _target = target();
- 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.children].find(el => el.matches('.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;
- // Clicks in the Shadow DOM change their target while using setTimeout, so the original target is saved here
- e.shadowTarget = e.target;
- 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
- };
- },
- beforeUnmount(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,
- opacity: [Number, String],
- 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,
- afterEnter: () => true,
- afterLeave: () => true
- },
- setup(props, _ref) {
- let {
- slots,
- attrs,
- emit
- } = _ref;
- const vm = getCurrentInstance('VOverlay');
- const root = vue.ref();
- const scrimEl = vue.ref();
- const contentEl = vue.ref();
- const model = useProxiedModel(props, 'modelValue');
- const isActive = vue.computed({
- get: () => model.value,
- set: v => {
- if (!(v && props.disabled)) model.value = v;
- }
- });
- const {
- themeClasses
- } = provideTheme(props);
- const {
- rtlClasses,
- isRtl
- } = useRtl();
- const {
- hasContent,
- onAfterLeave: _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,
- target,
- targetEl,
- targetRef,
- activatorEvents,
- contentEvents,
- scrimEvents
- } = useActivator(props, {
- isActive,
- isTop: localTop,
- contentEl
- });
- const {
- teleportTarget
- } = useTeleport(() => {
- const target = props.attach || props.contained;
- if (target) return target;
- const rootNode = activatorEl?.value?.getRootNode() || vm.proxy?.$el?.getRootNode();
- if (rootNode instanceof ShadowRoot) return rootNode;
- return false;
- });
- const {
- dimensionStyles
- } = useDimension(props);
- const isMounted = useHydration();
- const {
- scopeId
- } = useScopeId();
- vue.watch(() => props.disabled, v => {
- if (v) isActive.value = false;
- });
- const {
- contentStyles,
- updateLocation
- } = useLocationStrategies(props, {
- isRtl,
- contentEl,
- target,
- isActive
- });
- useScrollStrategies(props, {
- root,
- contentEl,
- targetEl,
- isActive,
- updateLocation
- });
- function onClickOutside(e) {
- emit('click:outside', e);
- if (!props.persistent) isActive.value = false;else animateClick();
- }
- function closeConditional(e) {
- return isActive.value && globalTop.value && (
- // If using scrim, only close if clicking on it rather than anything opened on top
- !props.scrim || e.target === scrimEl.value || e instanceof MouseEvent && e.shadowTarget === scrimEl.value);
- }
- IN_BROWSER && vue.watch(isActive, val => {
- if (val) {
- window.addEventListener('keydown', onKeydown);
- } else {
- window.removeEventListener('keydown', onKeydown);
- }
- }, {
- immediate: true
- });
- vue.onBeforeUnmount(() => {
- if (!IN_BROWSER) return;
- window.removeEventListener('keydown', onKeydown);
- });
- 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
- });
- }
- function onAfterEnter() {
- emit('afterEnter');
- }
- function onAfterLeave() {
- _onAfterLeave();
- emit('afterLeave');
- }
- useRender(() => vue.createVNode(vue.Fragment, null, [slots.activator?.({
- isActive: isActive.value,
- targetRef,
- 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, {
- '--v-overlay-opacity': props.opacity,
- top: convertToUnit(top.value)
- }, props.style],
- "ref": root
- }, scopeId, attrs), [vue.createVNode(Scrim, vue.mergeProps({
- "color": scrimColor,
- "modelValue": isActive.value && !!props.scrim,
- "ref": scrimEl
- }, scrimEvents.value), null), vue.createVNode(MaybeTransition, {
- "appear": true,
- "persisted": true,
- "transition": props.transition,
- "target": target.value,
- "onAfterEnter": onAfterEnter,
- "onAfterLeave": onAfterLeave
- }, {
- 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,
- scrimEl,
- target,
- animateClick,
- contentEl,
- globalTop,
- localTop,
- updateLocation
- };
- }
- });
- // Types
- const Refs = Symbol('Forwarded refs');
- /** Omit properties starting with P */
- /** Omit keyof $props from T */
- 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('$') || 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('$') || 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('$') || 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('$') || 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,
- submenu: Boolean,
- ...omit(makeVOverlayProps({
- closeDelay: 250,
- closeOnContentClick: true,
- locationStrategy: 'connected',
- location: undefined,
- 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 {
- isRtl
- } = useRtl();
- 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(new Set());
- vue.provide(VMenuSymbol, {
- register() {
- openChildren.value.add(uid);
- },
- unregister() {
- openChildren.value.delete(uid);
- },
- closeParents(e) {
- setTimeout(() => {
- if (!openChildren.value.size && !props.persistent && (e == null || overlay.value?.contentEl && !isClickInsideElement(e, overlay.value.contentEl))) {
- isActive.value = false;
- parent?.closeParents();
- }
- }, 40);
- }
- });
- vue.onBeforeUnmount(() => {
- parent?.unregister();
- document.removeEventListener('focusin', onFocusIn);
- });
- vue.onDeactivated(() => isActive.value = false);
- async function onFocusIn(e) {
- const before = e.relatedTarget;
- const after = e.target;
- await vue.nextTick();
- if (isActive.value && 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();
- if (IN_BROWSER) {
- document.addEventListener('focusin', onFocusIn, {
- once: true
- });
- }
- } else {
- parent?.unregister();
- if (IN_BROWSER) {
- document.removeEventListener('focusin', onFocusIn);
- }
- }
- }, {
- immediate: true
- });
- function onClickOutside(e) {
- parent?.closeParents(e);
- }
- function onKeydown(e) {
- if (props.disabled) return;
- if (e.key === 'Tab' || e.key === 'Enter' && !props.closeOnContentClick) {
- if (e.key === 'Enter' && (e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLInputElement && !!e.target.closest('form'))) return;
- if (e.key === 'Enter') e.preventDefault();
- 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();
- }
- } else if (props.submenu && e.key === (isRtl.value ? 'ArrowRight' : 'ArrowLeft')) {
- 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();
- e.stopImmediatePropagation();
- focusChild(el, 'next');
- } else if (e.key === 'ArrowUp') {
- e.preventDefault();
- e.stopImmediatePropagation();
- focusChild(el, 'prev');
- } else if (props.submenu) {
- if (e.key === (isRtl.value ? 'ArrowRight' : 'ArrowLeft')) {
- isActive.value = false;
- } else if (e.key === (isRtl.value ? 'ArrowLeft' : 'ArrowRight')) {
- e.preventDefault();
- focusChild(el, 'first');
- }
- }
- } else if (props.submenu ? e.key === (isRtl.value ? 'ArrowLeft' : 'ArrowRight') : ['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,
- "id": id.value,
- "class": ['v-menu', props.class],
- "style": props.style
- }, overlayProps, {
- "modelValue": isActive.value,
- "onUpdate:modelValue": $event => isActive.value = $event,
- "absolute": true,
- "activatorProps": activatorProps.value,
- "location": props.location ?? (props.submenu ? 'end' : 'bottom'),
- "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,
- disabled: 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', {
- 'text-error': props.max && !props.disabled && parseFloat(props.value) > parseFloat(props.max)
- }, 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': value => 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();
- }
- }
- function onKeydownClear(e) {
- if (e.key !== 'Enter' && e.key !== ' ') return;
- e.preventDefault();
- e.stopPropagation();
- props['onClick:clear']?.(new MouseEvent('click'));
- }
- 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, 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,
- "style": textColorStyles.value
- }, {
- default: () => [label()]
- }), hasLabel.value && vue.createVNode(VFieldLabel, {
- "key": "label",
- "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();
- }
- }, [vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VIcon: {
- icon: props.clearIcon
- }
- }
- }, {
- default: () => [slots.clear ? slots.clear({
- ...slotProps.value,
- props: {
- onKeydown: onKeydownClear,
- onFocus: focus,
- onBlur: blur,
- onClick: props['onClick:clear']
- }
- }) : vue.createVNode(InputIcon, {
- "name": "clear",
- "onKeydown": onKeydownClear,
- "onFocus": focus,
- "onBlur": blur
- }, 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],
- "style": textColorStyles.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: [Number, Function],
- prefix: String,
- placeholder: String,
- persistentPlaceholder: Boolean,
- persistentCounter: Boolean,
- suffix: String,
- role: 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) : typeof props.counterValue === 'number' ? props.counterValue : (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 !== false && props.counter != null);
- 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-input--plain-underlined': isPlainOrUnderlined.value
- }, 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": props.role
- }, 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])]), slots.default ? vue.createVNode("div", {
- "class": fieldClass,
- "data-no-activator": ""
- }, [slots.default(), inputNode]) : vue.cloneVNode(inputNode, {
- class: fieldClass
- }), 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,
- "disabled": props.disabled
- }, 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;
- /** Determines how large each batch of items should be */
- const BUFFER_PX = 100;
- const makeVirtualProps = propsFactory({
- itemHeight: {
- type: [Number, String],
- default: null
- },
- height: [Number, String]
- }, 'virtual');
- function useVirtual(props, items) {
- const display = useDisplay();
- const itemHeight = vue.shallowRef(0);
- vue.watchEffect(() => {
- itemHeight.value = parseFloat(props.itemHeight || 0);
- });
- const first = vue.shallowRef(0);
- const last = vue.shallowRef(Math.ceil(
- // Assume 16px items filling the entire screen height if
- // not provided. This is probably incorrect but it minimises
- // the chance of ending up with empty space at the bottom.
- // The default value is set here to avoid poisoning getSize()
- (parseInt(props.height) || display.height.value) / (itemHeight.value || 16)) || 1);
- const paddingTop = vue.shallowRef(0);
- const paddingBottom = vue.shallowRef(0);
- /** The scrollable element */
- const containerRef = vue.ref();
- /** An element marking the top of the scrollable area,
- * used to add an offset if there's padding or other elements above the virtual list */
- const markerRef = vue.ref();
- /** markerRef's offsetTop, lazily evaluated */
- let markerOffset = 0;
- const {
- resizeRef,
- contentRect
- } = useResizeObserver();
- vue.watchEffect(() => {
- resizeRef.value = containerRef.value;
- });
- const viewportHeight = vue.computed(() => {
- return containerRef.value === document.documentElement ? display.height.value : contentRect.value?.height || parseInt(props.height) || 0;
- });
- /** All static elements have been rendered and we have an assumed item height */
- const hasInitialRender = vue.computed(() => {
- return !!(containerRef.value && markerRef.value && viewportHeight.value && itemHeight.value);
- });
- let sizes = Array.from({
- length: items.value.length
- });
- let offsets = Array.from({
- length: items.value.length
- });
- const updateTime = vue.shallowRef(0);
- let targetScrollIndex = -1;
- function getSize(index) {
- return sizes[index] || itemHeight.value;
- }
- const updateOffsets = debounce(() => {
- const start = performance.now();
- offsets[0] = 0;
- const length = items.value.length;
- for (let i = 1; i <= length - 1; i++) {
- offsets[i] = (offsets[i - 1] || 0) + getSize(i - 1);
- }
- updateTime.value = Math.max(updateTime.value, performance.now() - start);
- }, updateTime);
- const unwatch = vue.watch(hasInitialRender, v => {
- if (!v) return;
- // First render is complete, update offsets and visible
- // items in case our assumed item height was incorrect
- unwatch();
- markerOffset = markerRef.value.offsetTop;
- updateOffsets.immediate();
- calculateVisibleItems();
- if (!~targetScrollIndex) return;
- vue.nextTick(() => {
- IN_BROWSER && window.requestAnimationFrame(() => {
- scrollToIndex(targetScrollIndex);
- targetScrollIndex = -1;
- });
- });
- });
- vue.onScopeDispose(() => {
- updateOffsets.clear();
- });
- function handleItemResize(index, height) {
- const prevHeight = sizes[index];
- const prevMinHeight = itemHeight.value;
- itemHeight.value = prevMinHeight ? Math.min(itemHeight.value, height) : height;
- if (prevHeight !== height || prevMinHeight !== itemHeight.value) {
- sizes[index] = height;
- updateOffsets();
- }
- }
- function calculateOffset(index) {
- index = clamp(index, 0, items.value.length - 1);
- return offsets[index] || 0;
- }
- function calculateIndex(scrollTop) {
- return binaryClosest(offsets, scrollTop);
- }
- let lastScrollTop = 0;
- let scrollVelocity = 0;
- let lastScrollTime = 0;
- vue.watch(viewportHeight, (val, oldVal) => {
- if (oldVal) {
- calculateVisibleItems();
- if (val < oldVal) {
- requestAnimationFrame(() => {
- scrollVelocity = 0;
- calculateVisibleItems();
- });
- }
- }
- });
- let scrollTimeout = -1;
- function handleScroll() {
- if (!containerRef.value || !markerRef.value) return;
- const scrollTop = containerRef.value.scrollTop;
- const scrollTime = performance.now();
- const scrollDeltaT = scrollTime - lastScrollTime;
- if (scrollDeltaT > 500) {
- scrollVelocity = Math.sign(scrollTop - lastScrollTop);
- // Not super important, only update at the
- // start of a scroll sequence to avoid reflows
- markerOffset = markerRef.value.offsetTop;
- } else {
- scrollVelocity = scrollTop - lastScrollTop;
- }
- lastScrollTop = scrollTop;
- lastScrollTime = scrollTime;
- window.clearTimeout(scrollTimeout);
- scrollTimeout = window.setTimeout(handleScrollend, 500);
- calculateVisibleItems();
- }
- function handleScrollend() {
- if (!containerRef.value || !markerRef.value) return;
- scrollVelocity = 0;
- lastScrollTime = 0;
- window.clearTimeout(scrollTimeout);
- calculateVisibleItems();
- }
- let raf = -1;
- function calculateVisibleItems() {
- cancelAnimationFrame(raf);
- raf = requestAnimationFrame(_calculateVisibleItems);
- }
- function _calculateVisibleItems() {
- if (!containerRef.value || !viewportHeight.value) return;
- const scrollTop = lastScrollTop - markerOffset;
- const direction = Math.sign(scrollVelocity);
- const startPx = Math.max(0, scrollTop - BUFFER_PX);
- const start = clamp(calculateIndex(startPx), 0, items.value.length);
- const endPx = scrollTop + viewportHeight.value + BUFFER_PX;
- const end = clamp(calculateIndex(endPx) + 1, start + 1, items.value.length);
- if (
- // Only update the side we're scrolling towards,
- // the other side will be updated incidentally
- (direction !== UP || start < first.value) && (direction !== DOWN || end > last.value)) {
- const topOverflow = calculateOffset(first.value) - calculateOffset(start);
- const bottomOverflow = calculateOffset(end) - calculateOffset(last.value);
- const bufferOverflow = Math.max(topOverflow, bottomOverflow);
- if (bufferOverflow > BUFFER_PX) {
- first.value = start;
- last.value = end;
- } else {
- // Only update the side that's reached its limit if there's still buffer left
- if (start <= 0) first.value = start;
- if (end >= items.value.length) last.value = end;
- }
- }
- paddingTop.value = calculateOffset(first.value);
- paddingBottom.value = calculateOffset(items.value.length) - calculateOffset(last.value);
- }
- function scrollToIndex(index) {
- const offset = calculateOffset(index);
- if (!containerRef.value || index && !offset) {
- targetScrollIndex = index;
- } else {
- containerRef.value.scrollTop = offset;
- }
- }
- const computedItems = vue.computed(() => {
- return items.value.slice(first.value, last.value).map((item, index) => ({
- raw: item,
- index: index + first.value,
- key: isObject(item) && 'value' in item ? item.value : index + first.value
- }));
- });
- vue.watch(items, () => {
- sizes = Array.from({
- length: items.value.length
- });
- offsets = Array.from({
- length: items.value.length
- });
- updateOffsets.immediate();
- calculateVisibleItems();
- }, {
- deep: true
- });
- return {
- calculateVisibleItems,
- containerRef,
- markerRef,
- computedItems,
- paddingTop,
- paddingBottom,
- scrollToIndex,
- handleScroll,
- handleScrollend,
- handleItemResize
- };
- }
- // https://gist.github.com/robertleeplummerjr/1cc657191d34ecd0a324
- function binaryClosest(arr, val) {
- let high = arr.length - 1;
- let low = 0;
- let mid = 0;
- let item = null;
- let target = -1;
- if (arr[high] < val) {
- return high;
- }
- while (low <= high) {
- mid = low + high >> 1;
- item = arr[mid];
- if (item > val) {
- high = mid - 1;
- } else if (item < val) {
- target = mid;
- low = mid + 1;
- } else if (item === val) {
- return mid;
- } else {
- return low;
- }
- }
- return target;
- }
- // 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 {
- calculateVisibleItems,
- containerRef,
- markerRef,
- handleScroll,
- handleScrollend,
- handleItemResize,
- scrollToIndex,
- paddingTop,
- paddingBottom,
- computedItems
- } = useVirtual(props, vue.toRef(props, 'items'));
- useToggleScope(() => props.renderless, () => {
- function handleListeners() {
- let add = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
- const method = add ? 'addEventListener' : 'removeEventListener';
- if (containerRef.value === document.documentElement) {
- document[method]('scroll', handleScroll, {
- passive: true
- });
- document[method]('scrollend', handleScrollend);
- } else {
- containerRef.value?.[method]('scroll', handleScroll, {
- passive: true
- });
- containerRef.value?.[method]('scrollend', handleScrollend);
- }
- }
- vue.onMounted(() => {
- containerRef.value = getScrollParent(vm.vnode.el, true);
- handleListeners(true);
- });
- vue.onScopeDispose(handleListeners);
- });
- useRender(() => {
- const children = computedItems.value.map(item => vue.createVNode(VVirtualScrollItem, {
- "key": item.key,
- "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", {
- "ref": markerRef,
- "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],
- "onScrollPassive": handleScroll,
- "onScrollend": handleScrollend,
- "style": [dimensionStyles.value, props.style]
- }, [vue.createVNode("div", {
- "ref": markerRef,
- "class": "v-virtual-scroll__container",
- "style": {
- paddingTop: convertToUnit(paddingTop.value),
- paddingBottom: convertToUnit(paddingBottom.value)
- }
- }, [children])]);
- });
- return {
- calculateVisibleItems,
- 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 {
- onScrollPassive: onListScroll,
- onKeydown: onListKeydown
- }; // typescript doesn't know about vue's event merging
- }
- // Types
- const makeSelectProps = propsFactory({
- chips: Boolean,
- closableChips: Boolean,
- closeText: {
- type: String,
- default: '$vuetify.close'
- },
- openText: {
- type: String,
- default: '$vuetify.open'
- },
- eager: Boolean,
- hideNoData: Boolean,
- hideSelected: Boolean,
- listProps: {
- type: Object
- },
- menu: Boolean,
- menuIcon: {
- type: IconValue,
- default: '$dropdown'
- },
- menuProps: {
- type: Object
- },
- multiple: Boolean,
- noDataText: {
- type: String,
- default: '$vuetify.noDataText'
- },
- openOnClear: Boolean,
- itemColor: String,
- ...makeItemsProps({
- itemChildren: false
- })
- }, 'Select');
- const makeVSelectProps = propsFactory({
- ...makeSelectProps(),
- ...omit(makeVTextFieldProps({
- modelValue: null,
- role: 'combobox'
- }), ['validationValue', 'dirty', 'appendInnerIcon']),
- ...makeTransitionProps({
- transition: {
- component: VDialogTransition
- }
- })
- }, 'VSelect');
- const VSelect = genericComponent()({
- name: 'VSelect',
- props: makeVSelectProps(),
- emits: {
- 'update:focused': focused => true,
- 'update:modelValue': value => true,
- 'update:menu': ue => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const vTextFieldRef = vue.ref();
- const vMenuRef = vue.ref();
- const vVirtualScrollRef = vue.ref();
- const _menu = useProxiedModel(props, 'menu');
- const menu = vue.computed({
- get: () => _menu.value,
- set: v => {
- if (_menu.value && !v && vMenuRef.value?.ΨopenChildren.size) 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 counterValue = vue.computed(() => {
- return typeof props.counterValue === 'function' ? props.counterValue(model.value) : typeof props.counterValue === 'number' ? props.counterValue : model.value.length;
- });
- const form = useForm(props);
- const selectedValues = vue.computed(() => model.value.map(selection => selection.value));
- const isFocused = vue.shallowRef(false);
- const label = vue.computed(() => menu.value ? props.closeText : props.openText);
- let keyboardLookupPrefix = '';
- let keyboardLookupLastTime;
- const displayItems = vue.computed(() => {
- if (props.hideSelected) {
- return items.value.filter(item => !model.value.some(s => props.valueComparator(s, item)));
- }
- return items.value;
- });
- const menuDisabled = vue.computed(() => props.hideNoData && !displayItems.value.length || form.isReadonly.value || form.isDisabled.value);
- const computedMenuProps = vue.computed(() => {
- return {
- ...props.menuProps,
- activatorProps: {
- ...(props.menuProps?.activatorProps || {}),
- 'aria-haspopup': 'listbox' // Set aria-haspopup to 'listbox'
- }
- };
- });
- const listRef = vue.ref();
- const listEvents = useScrolling(listRef, vTextFieldRef);
- function onClear(e) {
- if (props.openOnClear) {
- menu.value = true;
- }
- }
- function onMousedownControl() {
- if (menuDisabled.value) return;
- menu.value = !menu.value;
- }
- function onListKeydown(e) {
- if (checkPrintable(e)) {
- onKeydown(e);
- }
- }
- function onKeydown(e) {
- if (!e.key || 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
- 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];
- const index = displayItems.value.indexOf(item);
- IN_BROWSER && window.requestAnimationFrame(() => {
- index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index);
- });
- }
- }
- /** @param set - null means toggle */
- function select(item) {
- let set = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
- if (item.props.disabled) return;
- if (props.multiple) {
- const index = model.value.findIndex(selection => props.valueComparator(selection.value, item.value));
- const add = set == null ? !~index : set;
- if (~index) {
- const value = add ? [...model.value, item] : [...model.value];
- value.splice(index, 1);
- model.value = value;
- } else if (add) {
- model.value = [...model.value, item];
- }
- } else {
- const add = set !== false;
- model.value = add ? [item] : [];
- vue.nextTick(() => {
- menu.value = false;
- });
- }
- }
- function onBlur(e) {
- if (!listRef.value?.$el.contains(e.relatedTarget)) {
- menu.value = false;
- }
- }
- function onAfterEnter() {
- if (props.eager) {
- vVirtualScrollRef.value?.calculateVisibleItems();
- }
- }
- 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 = '';
- }
- }
- vue.watch(menu, () => {
- if (!props.hideSelected && menu.value && model.value.length) {
- const index = displayItems.value.findIndex(item => model.value.some(s => props.valueComparator(s.value, item.value)));
- IN_BROWSER && window.requestAnimationFrame(() => {
- index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index);
- });
- }
- });
- vue.watch(() => props.items, (newVal, oldVal) => {
- if (menu.value) return;
- if (isFocused.value && !oldVal.length && newVal.length) {
- menu.value = true;
- }
- });
- 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,
- "counterValue": counterValue.value,
- "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,
- "aria-label": t(label.value),
- "title": t(label.value)
- }), {
- ...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,
- "onAfterEnter": onAfterEnter,
- "onAfterLeave": onAfterLeave
- }, computedMenuProps.value), {
- default: () => [hasList && vue.createVNode(VList, vue.mergeProps({
- "ref": listRef,
- "selected": selectedValues.value,
- "selectStrategy": props.multiple ? 'independent' : 'single-independent',
- "onMousedown": e => e.preventDefault(),
- "onKeydown": onListKeydown,
- "onFocusin": onFocusin,
- "tabindex": "-1",
- "aria-live": "polite",
- "color": props.itemColor ?? props.color
- }, listEvents, props.listProps), {
- default: () => [slots['prepend-item']?.(), !displayItems.value.length && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
- "key": "no-data",
- "title": t(props.noDataText)
- }, null)), vue.createVNode(VVirtualScroll, {
- "ref": vVirtualScrollRef,
- "renderless": true,
- "items": displayItems.value
- }, {
- default: _ref2 => {
- let {
- item,
- index,
- itemRef
- } = _ref2;
- const itemProps = vue.mergeProps(item.props, {
- ref: itemRef,
- key: item.value,
- onClick: () => select(item, null)
- });
- return slots.item?.({
- item,
- index,
- props: itemProps
- }) ?? vue.createVNode(VListItem, vue.mergeProps(itemProps, {
- "role": "option"
- }), {
- 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.prependAvatar && vue.createVNode(VAvatar, {
- "image": item.props.prependAvatar
- }, null), item.props.prependIcon && vue.createVNode(VIcon, {
- "icon": item.props.prependIcon
- }, null)]);
- }
- });
- }
- }), slots['append-item']?.()]
- })]
- }), model.value.map((item, index) => {
- function onChipClose(e) {
- e.stopPropagation();
- e.preventDefault();
- select(item, false);
- }
- const slotProps = {
- 'onClick:close': onChipClose,
- onKeydown(e) {
- if (e.key !== 'Enter' && e.key !== ' ') return;
- e.preventDefault();
- e.stopPropagation();
- onChipClose(e);
- },
- onMousedown(e) {
- e.preventDefault();
- e.stopPropagation();
- },
- modelValue: true,
- 'onUpdate:modelValue': undefined
- };
- const hasSlot = hasChips ? !!slots.chip : !!slots.selection;
- const slotContent = hasSlot ? ensureValidVNode(hasChips ? slots.chip({
- item,
- index,
- props: slotProps
- }) : slots.selection({
- item,
- index
- })) : undefined;
- if (hasSlot && !slotContent) return 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,
- "disabled": item.props.disabled
- }, slotProps), null) : vue.createVNode(VDefaultsProvider, {
- "key": "chip-defaults",
- "defaults": {
- VChip: {
- closable: props.closableChips,
- size: 'small',
- text: item.title
- }
- }
- }, {
- default: () => [slotContent]
- }) : slotContent ?? vue.createVNode("span", {
- "class": "v-select__selection-text"
- }, [item.title, props.multiple && index < model.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
- /**
- * - match without highlight
- * - single match (index), length already known
- * - single match (start, end)
- * - multiple matches (start, end), probably shouldn't overlap
- */
- // 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, transformed = item] = wrapInArray(items[i]);
- const customMatches = {};
- const defaultMatches = {};
- let match = -1;
- if ((query || customFiltersLength > 0) && !options?.noFilter) {
- if (typeof item === 'object') {
- const filterKeys = keys || Object.keys(transformed);
- for (const key of filterKeys) {
- const value = getPropertyFromItem(transformed, key);
- 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(item => [item, options.transform(item)]) : 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,
- ...vue.unref(options?.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]
- },
- clearOnSelect: Boolean,
- search: String,
- ...makeFilterProps({
- filterKeys: ['title']
- }),
- ...makeSelectProps(),
- ...omit(makeVTextFieldProps({
- modelValue: null,
- role: 'combobox'
- }), ['validationValue', 'dirty', 'appendInnerIcon']),
- ...makeTransitionProps({
- transition: false
- })
- }, 'VAutocomplete');
- const VAutocomplete = genericComponent()({
- name: 'VAutocomplete',
- props: makeVAutocompleteProps(),
- emits: {
- 'update:focused': focused => true,
- 'update:search': value => true,
- 'update:modelValue': value => true,
- 'update:menu': value => 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 vVirtualScrollRef = vue.ref();
- const _menu = useProxiedModel(props, 'menu');
- const menu = vue.computed({
- get: () => _menu.value,
- set: v => {
- if (_menu.value && !v && vMenuRef.value?.ΨopenChildren.size) return;
- _menu.value = v;
- }
- });
- const selectionIndex = vue.shallowRef(-1);
- const color = vue.computed(() => vTextFieldRef.value?.color);
- const label = vue.computed(() => menu.value ? props.closeText : props.openText);
- 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 counterValue = vue.computed(() => {
- return typeof props.counterValue === 'function' ? props.counterValue(model.value) : typeof props.counterValue === 'number' ? props.counterValue : model.value.length;
- });
- const form = useForm(props);
- const {
- filteredItems,
- getMatches
- } = useFilter(props, items, () => isPristine.value ? '' : search.value);
- const displayItems = vue.computed(() => {
- if (props.hideSelected) {
- return filteredItems.value.filter(filteredItem => !model.value.some(s => s.value === filteredItem.value));
- }
- return filteredItems.value;
- });
- const hasChips = vue.computed(() => !!(props.chips || slots.chip));
- const hasSelectionSlot = vue.computed(() => hasChips.value || !!slots.selection);
- const selectedValues = vue.computed(() => model.value.map(selection => selection.props.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 && !displayItems.value.length || form.isReadonly.value || form.isDisabled.value);
- const listRef = vue.ref();
- const listEvents = 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 onListKeydown(e) {
- if (checkPrintable(e)) {
- vTextFieldRef.value?.focus();
- }
- }
- function onKeydown(e) {
- if (form.isReadonly.value) return;
- const selectionStart = vTextFieldRef.value.selectionStart;
- const length = model.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) && !model.value.some(_ref2 => {
- let {
- value
- } = _ref2;
- return value === displayItems.value[0].value;
- })) {
- select(displayItems.value[0]);
- }
- if (e.key === 'ArrowDown' && highlightFirst.value) {
- listRef.value?.focus('next');
- }
- if (['Backspace', 'Delete'].includes(e.key)) {
- if (!props.multiple && hasSelectionSlot.value && model.value.length > 0 && !search.value) return select(model.value[0], false);
- if (~selectionIndex.value) {
- const originalSelectionIndex = selectionIndex.value;
- select(model.value[selectionIndex.value], false);
- selectionIndex.value = originalSelectionIndex >= length - 1 ? length - 2 : originalSelectionIndex;
- } else if (e.key === 'Backspace' && !search.value) {
- selectionIndex.value = length - 1;
- }
- }
- if (!props.multiple) return;
- if (e.key === 'ArrowLeft') {
- if (selectionIndex.value < 0 && selectionStart > 0) return;
- const prev = selectionIndex.value > -1 ? selectionIndex.value - 1 : length - 1;
- if (model.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 (model.value[next]) {
- selectionIndex.value = next;
- } else {
- selectionIndex.value = -1;
- vTextFieldRef.value.setSelectionRange(0, 0);
- }
- }
- }
- 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 onAfterEnter() {
- if (props.eager) {
- vVirtualScrollRef.value?.calculateVisibleItems();
- }
- }
- 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 && !hasSelectionSlot.value) model.value = [];
- }
- const isSelecting = vue.shallowRef(false);
- /** @param set - null means toggle */
- function select(item) {
- let set = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
- if (!item || item.props.disabled) return;
- if (props.multiple) {
- const index = model.value.findIndex(selection => props.valueComparator(selection.value, item.value));
- const add = set == null ? !~index : set;
- if (~index) {
- const value = add ? [...model.value, item] : [...model.value];
- value.splice(index, 1);
- model.value = value;
- } else if (add) {
- model.value = [...model.value, item];
- }
- if (props.clearOnSelect) {
- search.value = '';
- }
- } else {
- const add = set !== false;
- model.value = add ? [item] : [];
- search.value = add && !hasSelectionSlot.value ? item.title : '';
- // watch for search watcher to trigger
- vue.nextTick(() => {
- menu.value = false;
- isPristine.value = true;
- });
- }
- }
- vue.watch(isFocused, (val, oldVal) => {
- if (val === oldVal) return;
- if (val) {
- isSelecting.value = true;
- search.value = props.multiple || hasSelectionSlot.value ? '' : String(model.value.at(-1)?.props.title ?? '');
- isPristine.value = true;
- vue.nextTick(() => isSelecting.value = false);
- } else {
- if (!props.multiple && search.value == null) model.value = [];
- menu.value = false;
- if (!model.value.some(_ref3 => {
- let {
- title
- } = _ref3;
- return title === search.value;
- })) search.value = '';
- selectionIndex.value = -1;
- }
- });
- vue.watch(search, val => {
- if (!isFocused.value || isSelecting.value) return;
- if (val) menu.value = true;
- isPristine.value = !val;
- });
- vue.watch(menu, () => {
- if (!props.hideSelected && menu.value && model.value.length) {
- const index = displayItems.value.findIndex(item => model.value.some(s => item.value === s.value));
- IN_BROWSER && window.requestAnimationFrame(() => {
- index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index);
- });
- }
- });
- vue.watch(() => props.items, (newVal, oldVal) => {
- if (menu.value) return;
- if (isFocused.value && !oldVal.length && newVal.length) {
- menu.value = true;
- }
- });
- useRender(() => {
- 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,
- "counterValue": counterValue.value,
- "dirty": isDirty,
- "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': !!hasSelectionSlot.value,
- 'v-autocomplete--selecting-index': selectionIndex.value > -1
- }, props.class],
- "style": props.style,
- "readonly": form.isReadonly.value,
- "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,
- "onAfterEnter": onAfterEnter,
- "onAfterLeave": onAfterLeave
- }, props.menuProps), {
- default: () => [hasList && vue.createVNode(VList, vue.mergeProps({
- "ref": listRef,
- "selected": selectedValues.value,
- "selectStrategy": props.multiple ? 'independent' : 'single-independent',
- "onMousedown": e => e.preventDefault(),
- "onKeydown": onListKeydown,
- "onFocusin": onFocusin,
- "onFocusout": onFocusout,
- "tabindex": "-1",
- "aria-live": "polite",
- "color": props.itemColor ?? props.color
- }, listEvents, props.listProps), {
- default: () => [slots['prepend-item']?.(), !displayItems.value.length && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
- "key": "no-data",
- "title": t(props.noDataText)
- }, null)), vue.createVNode(VVirtualScroll, {
- "ref": vVirtualScrollRef,
- "renderless": true,
- "items": displayItems.value
- }, {
- default: _ref4 => {
- let {
- item,
- index,
- itemRef
- } = _ref4;
- const itemProps = vue.mergeProps(item.props, {
- ref: itemRef,
- key: item.value,
- active: highlightFirst.value && index === 0 ? true : undefined,
- onClick: () => select(item, null)
- });
- return slots.item?.({
- item,
- index,
- props: itemProps
- }) ?? vue.createVNode(VListItem, vue.mergeProps(itemProps, {
- "role": "option"
- }), {
- prepend: _ref5 => {
- let {
- isSelected
- } = _ref5;
- 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.prependAvatar && vue.createVNode(VAvatar, {
- "image": item.props.prependAvatar
- }, null), 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']?.()]
- })]
- }), model.value.map((item, index) => {
- function onChipClose(e) {
- e.stopPropagation();
- e.preventDefault();
- select(item, false);
- }
- const slotProps = {
- 'onClick:close': onChipClose,
- onKeydown(e) {
- if (e.key !== 'Enter' && e.key !== ' ') return;
- e.preventDefault();
- e.stopPropagation();
- onChipClose(e);
- },
- onMousedown(e) {
- e.preventDefault();
- e.stopPropagation();
- },
- modelValue: true,
- 'onUpdate:modelValue': undefined
- };
- const hasSlot = hasChips.value ? !!slots.chip : !!slots.selection;
- const slotContent = hasSlot ? ensureValidVNode(hasChips.value ? slots.chip({
- item,
- index,
- props: slotProps
- }) : slots.selection({
- item,
- index
- })) : undefined;
- if (hasSlot && !slotContent) return 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.value ? !slots.chip ? vue.createVNode(VChip, vue.mergeProps({
- "key": "chip",
- "closable": props.closableChips,
- "size": "small",
- "text": item.title,
- "disabled": item.props.disabled
- }, slotProps), null) : vue.createVNode(VDefaultsProvider, {
- "key": "chip-defaults",
- "defaults": {
- VChip: {
- closable: props.closableChips,
- size: 'small',
- text: item.title
- }
- }
- }, {
- default: () => [slotContent]
- }) : slotContent ?? vue.createVNode("span", {
- "class": "v-autocomplete__selection-text"
- }, [item.title, props.multiple && index < model.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,
- "aria-label": t(label.value),
- "title": t(label.value),
- "tabindex": "-1"
- }, 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] = pickWithRest(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,
- slim: true,
- 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,
- bgColor: String,
- color: String,
- icon: IconValue,
- lines: String,
- stacked: Boolean,
- sticky: Boolean,
- text: String,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDensityProps(),
- ...makeDimensionProps(),
- ...makeDisplayProps({
- mobile: null
- }),
- ...makeElevationProps(),
- ...makeLocationProps(),
- ...makePositionProps(),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeThemeProps()
- }, 'VBanner');
- const VBanner = genericComponent()({
- name: 'VBanner',
- props: makeVBannerProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(props, 'bgColor');
- const {
- borderClasses
- } = useBorder(props);
- const {
- densityClasses
- } = useDensity(props);
- const {
- displayClasses,
- mobile
- } = useDisplay(props);
- 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
- }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, densityClasses.value, displayClasses.value, elevationClasses.value, positionClasses.value, roundedClasses.value, props.class],
- "style": [backgroundColorStyles.value, 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)]
- });
- });
- }
- });
- // Types
- const makeVBottomNavigationProps = propsFactory({
- baseColor: String,
- 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({
- selectedClass: 'v-btn--selected'
- }),
- ...makeThemeProps()
- }, 'VBottomNavigation');
- const VBottomNavigation = genericComponent()({
- name: 'VBottomNavigation',
- props: makeVBottomNavigationProps(),
- emits: {
- 'update:active': value => true,
- '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 = useProxiedModel(props, 'active', 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: {
- baseColor: vue.toRef(props, 'baseColor'),
- 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)
- }, ssrBootStyles.value, props.style]
- }, {
- default: () => [slots.default && vue.createVNode("div", {
- "class": "v-bottom-navigation__content"
- }, [slots.default()])]
- });
- });
- return {};
- }
- });
- // 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,
- afterEnter: () => true,
- afterLeave: () => true
- },
- setup(props, _ref) {
- let {
- emit,
- 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();
- }
- }
- }
- vue.onBeforeUnmount(() => {
- document.removeEventListener('focusin', onFocusin);
- });
- if (IN_BROWSER) {
- vue.watch(() => isActive.value && props.retainFocus, val => {
- val ? document.addEventListener('focusin', onFocusin) : document.removeEventListener('focusin', onFocusin);
- }, {
- immediate: true
- });
- }
- function onAfterEnter() {
- emit('afterEnter');
- if (overlay.value?.contentEl && !overlay.value.contentEl.contains(document.activeElement)) {
- overlay.value.contentEl.focus({
- preventScroll: true
- });
- }
- }
- function onAfterLeave() {
- emit('afterLeave');
- }
- vue.watch(isActive, async val => {
- if (!val) {
- await vue.nextTick();
- overlay.value.activatorEl?.focus({
- preventScroll: true
- });
- }
- });
- useRender(() => {
- const overlayProps = VOverlay.filterProps(props);
- const activatorProps = vue.mergeProps({
- 'aria-haspopup': 'dialog'
- }, props.activatorProps);
- const contentProps = vue.mergeProps({
- tabindex: -1
- }, props.contentProps);
- 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,
- "contentProps": contentProps,
- "height": !props.fullscreen ? props.height : undefined,
- "width": !props.fullscreen ? props.width : undefined,
- "maxHeight": !props.fullscreen ? props.maxHeight : undefined,
- "maxWidth": !props.fullscreen ? props.maxWidth : undefined,
- "role": "dialog",
- "onAfterEnter": onAfterEnter,
- "onAfterLeave": onAfterLeave
- }, 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 makeVBottomSheetProps = propsFactory({
- inset: Boolean,
- ...makeVDialogProps({
- transition: 'bottom-sheet-transition'
- })
- }, 'VBottomSheet');
- const VBottomSheet = genericComponent()({
- name: 'VBottomSheet',
- props: makeVBottomSheetProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const isActive = useProxiedModel(props, 'modelValue');
- useRender(() => {
- const dialogProps = VDialog.filterProps(props);
- return vue.createVNode(VDialog, vue.mergeProps(dialogProps, {
- "contentClass": ['v-bottom-sheet__content', props.contentClass],
- "modelValue": isActive.value,
- "onUpdate:modelValue": $event => isActive.value = $event,
- "class": ['v-bottom-sheet', {
- 'v-bottom-sheet--inset': props.inset
- }, props.class],
- "style": props.style
- }), slots);
- });
- 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", vue.mergeProps({
- "class": "v-breadcrumbs-item--link",
- "onClick": link.navigate
- }, link.linkProps), [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, [slots.item?.({
- item,
- index
- }) ?? vue.createVNode(VBreadcrumbsItem, vue.mergeProps({
- "key": index,
- "disabled": index >= array.length - 1
- }, typeof item === 'string' ? {
- title: item
- } : item), {
- default: slots.title ? () => slots.title?.({
- item,
- 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: {
- slim: true,
- variant: 'text'
- }
- });
- useRender(() => vue.createVNode("div", {
- "class": ['v-card-actions', props.class],
- "style": props.style
- }, [slots.default?.()]));
- return {};
- }
- });
- const makeVCardSubtitleProps = propsFactory({
- opacity: [Number, String],
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VCardSubtitle');
- const VCardSubtitle = genericComponent()({
- name: 'VCardSubtitle',
- props: makeVCardSubtitleProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-card-subtitle', props.class],
- "style": [{
- '--v-card-subtitle-opacity': props.opacity
- }, props.style]
- }, slots));
- return {};
- }
- });
- // Utilities
- const VCardTitle = createSimpleFunctional('v-card-title');
- const makeCardItemProps = propsFactory({
- appendAvatar: String,
- appendIcon: IconValue,
- prependAvatar: String,
- prependIcon: IconValue,
- subtitle: [String, Number],
- title: [String, Number],
- ...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 != null || slots.title);
- const hasSubtitle = !!(props.subtitle != null || 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 ? 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
- }
- }
- }, 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 ? 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
- }
- }
- }, slots.append)])]);
- });
- return {};
- }
- });
- const makeVCardTextProps = propsFactory({
- opacity: [Number, String],
- ...makeComponentProps(),
- ...makeTagProps()
- }, 'VCardText');
- const VCardText = genericComponent()({
- name: 'VCardText',
- props: makeVCardTextProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-card-text', props.class],
- "style": [{
- '--v-card-text-opacity': props.opacity
- }, props.style]
- }, slots));
- return {};
- }
- });
- // 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, Number],
- text: [String, Number],
- title: [String, Number],
- ...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 != null);
- const hasSubtitle = !!(slots.subtitle || props.subtitle != null);
- 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 != null);
- return vue.withDirectives(vue.createVNode(Tag, vue.mergeProps({
- "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],
- "onClick": isClickable.value && link.navigate,
- "tabindex": props.disabled ? -1 : undefined
- }, link.linkProps), {
- 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': value => 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,
- 'aria-label': 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,
- 'aria-label': 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': value => 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: ['v-carousel__controls__item', 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', props.class]
- }, windowItemProps), {
- default: () => [vue.createVNode(VImg, vue.mergeProps(attrs, imgProps), slots)]
- });
- });
- }
- });
- // Styles
- const VCode = createSimpleFunctional('v-code', '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 canvasRef = vue.ref();
- const canvasWidth = vue.shallowRef(parseFloat(props.width));
- const canvasHeight = vue.shallowRef(parseFloat(props.height));
- const _dotPosition = vue.ref({
- x: 0,
- y: 0
- });
- const dotPosition = vue.computed({
- get: () => _dotPosition.value,
- set(val) {
- if (!canvasRef.value) return;
- const {
- x,
- y
- } = val;
- _dotPosition.value = val;
- 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
- });
- }
- });
- 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 {
- resizeRef
- } = useResizeObserver(entries => {
- if (!resizeRef.el?.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 handleMouseDown(e) {
- if (e.type === 'mousedown') {
- // Prevent text selection while dragging
- e.preventDefault();
- }
- if (props.disabled) return;
- handleMouseMove(e);
- 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);
- }
- 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%, 0%, 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;
- }
- _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,
- "onMousedown": handleMouseDown,
- "onTouchstartPassive": 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: 0,
- 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 ?? mode.to(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
- }),
- ripple: {
- type: Boolean,
- default: true
- }
- }, '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 vertical = vue.computed(() => props.direction === 'vertical');
- const indexFromEnd = vue.computed(() => vertical.value !== isReversed.value);
- 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 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 ? indexFromEnd.value : indexFromEnd.value !== isRtl.value) 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,
- isReversed,
- indexFromEnd,
- 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
- },
- name: String,
- ...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 {
- isRtl,
- rtlClasses
- } = useRtl();
- if (!slider) throw new Error('[Vuetify] v-slider-thumb must be used inside v-slider or v-range-slider');
- const {
- thumbColor,
- step,
- disabled,
- thumbSize,
- thumbLabel,
- direction,
- isReversed,
- vertical,
- readonly,
- elevation,
- mousePressed,
- decimals,
- indexFromEnd
- } = slider;
- const elevationProps = vue.computed(() => !disabled.value ? elevation.value : undefined);
- const {
- elevationClasses
- } = useElevation(elevationProps);
- 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 = vertical.value ? [isRtl.value ? left : right, isReversed.value ? down : up] : indexFromEnd.value !== isRtl.value ? [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(indexFromEnd.value ? 100 - props.position : props.position, '%');
- 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-label": props.name,
- "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,
- parsedTicks,
- rounded,
- showTicks,
- tickSize,
- trackColor,
- trackFillColor,
- trackSize,
- vertical,
- min,
- max,
- indexFromEnd
- } = 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' : 'inline'}-${indexFromEnd.value ? 'end' : '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 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": {
- [startDir.value]: 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)
- }, 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,
- "ripple": props.ripple,
- "name": props.name
- }, {
- '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;
- const abortController = new AbortController();
- vue.onUnmounted(() => abortController.abort());
- async function openEyeDropper() {
- if (!SUPPORTS_EYE_DROPPER) return;
- const eyeDropper = new window.EyeDropper();
- try {
- const result = await eyeDropper.open({
- signal: abortController.signal
- });
- const colorHexValue = HexToHSV(result.sRGBHex);
- emit('update:color', {
- ...(props.color ?? nullColor),
- ...colorHexValue
- });
- } catch (e) {}
- }
- useRender(() => vue.createVNode("div", {
- "class": ['v-color-picker-preview', {
- 'v-color-picker-preview--hide-alpha': props.hideAlpha
- }, props.class],
- "style": props.style
- }, [SUPPORTS_EYE_DROPPER && vue.createVNode("div", {
- "class": "v-color-picker-preview__eye-dropper",
- "key": "eyeDropper"
- }, [vue.createVNode(VBtn, {
- "onClick": openEyeDropper,
- "icon": "$eyeDropper",
- "variant": "plain",
- "density": "comfortable"
- }, null)]), 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- 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 = {
- base: '#795548',
- lighten5: '#efebe9',
- lighten4: '#d7ccc8',
- lighten3: '#bcaaa4',
- lighten2: '#a1887f',
- lighten1: '#8d6e63',
- darken1: '#6d4c41',
- darken2: '#5d4037',
- darken3: '#4e342e',
- darken4: '#3e2723'
- };
- const blueGrey = {
- base: '#607d8b',
- lighten5: '#eceff1',
- lighten4: '#cfd8dc',
- lighten3: '#b0bec5',
- lighten2: '#90a4ae',
- lighten1: '#78909c',
- darken1: '#546e7a',
- darken2: '#455a64',
- darken3: '#37474f',
- darken4: '#263238'
- };
- const grey = {
- base: '#9e9e9e',
- lighten5: '#fafafa',
- lighten4: '#f5f5f5',
- lighten3: '#eeeeee',
- lighten2: '#e0e0e0',
- lighten1: '#bdbdbd',
- darken1: '#757575',
- darken2: '#616161',
- darken3: '#424242',
- darken4: '#212121'
- };
- const shades = {
- black: '#000000',
- white: '#ffffff',
- transparent: '#ffffff00'
- };
- var colors = {
- 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 hue = vue.ref(null);
- const model = useProxiedModel(props, 'modelValue', undefined, v => {
- if (v == null || v === '') return null;
- let c;
- try {
- c = RGBtoHSV(parseColor(v));
- } catch (err) {
- consoleWarn(err);
- return null;
- }
- return c;
- }, v => {
- if (!v) return null;
- return extractColor(v, props.modelValue);
- });
- const currentColor = vue.computed(() => {
- return model.value ? {
- ...model.value,
- h: hue.value ?? model.value.h
- } : null;
- });
- const {
- rtlClasses
- } = useRtl();
- let externalChange = true;
- vue.watch(model, v => {
- if (!externalChange) {
- // prevent hue shift from rgb conversion inaccuracy
- externalChange = true;
- return;
- }
- if (!v) return;
- hue.value = v.h;
- }, {
- immediate: true
- });
- const updateColor = hsva => {
- externalChange = false;
- hue.value = hsva.h;
- model.value = hsva;
- };
- vue.onBeforeMount(() => {
- 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]
- },
- clearOnSelect: {
- type: Boolean,
- default: true
- },
- delimiters: Array,
- ...makeFilterProps({
- filterKeys: ['title']
- }),
- ...makeSelectProps({
- hideNoData: true,
- returnObject: true
- }),
- ...omit(makeVTextFieldProps({
- modelValue: null,
- role: 'combobox'
- }), ['validationValue', 'dirty', 'appendInnerIcon']),
- ...makeTransitionProps({
- transition: false
- })
- }, 'VCombobox');
- const VCombobox = genericComponent()({
- name: 'VCombobox',
- props: makeVComboboxProps(),
- emits: {
- 'update:focused': focused => true,
- 'update:modelValue': value => true,
- 'update:search': value => true,
- 'update:menu': value => 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 vVirtualScrollRef = vue.ref();
- const _menu = useProxiedModel(props, 'menu');
- const menu = vue.computed({
- get: () => _menu.value,
- set: v => {
- if (_menu.value && !v && vMenuRef.value?.ΨopenChildren.size) return;
- _menu.value = v;
- }
- });
- const selectionIndex = vue.shallowRef(-1);
- let cleared = false;
- const color = vue.computed(() => vTextFieldRef.value?.color);
- const label = vue.computed(() => menu.value ? props.closeText : props.openText);
- 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(props);
- const hasChips = vue.computed(() => !!(props.chips || slots.chip));
- const hasSelectionSlot = vue.computed(() => hasChips.value || !!slots.selection);
- const _search = vue.shallowRef(!props.multiple && !hasSelectionSlot.value ? model.value[0]?.title ?? '' : '');
- const search = vue.computed({
- get: () => {
- return _search.value;
- },
- set: val => {
- _search.value = val ?? '';
- if (!props.multiple && !hasSelectionSlot.value) {
- model.value = [transformItem$3(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$3(props, v));
- });
- _search.value = '';
- }
- }
- if (!val) selectionIndex.value = -1;
- isPristine.value = !val;
- }
- });
- const counterValue = vue.computed(() => {
- return typeof props.counterValue === 'function' ? props.counterValue(model.value) : typeof props.counterValue === 'number' ? props.counterValue : props.multiple ? model.value.length : search.value.length;
- });
- 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 && !hasSelectionSlot.value) {
- _search.value = value[0]?.title ?? '';
- }
- });
- const {
- filteredItems,
- getMatches
- } = useFilter(props, items, () => isPristine.value ? '' : search.value);
- const displayItems = vue.computed(() => {
- if (props.hideSelected) {
- return filteredItems.value.filter(filteredItem => !model.value.some(s => s.value === filteredItem.value));
- }
- return filteredItems.value;
- });
- const selectedValues = vue.computed(() => model.value.map(selection => selection.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 && !displayItems.value.length || form.isReadonly.value || form.isDisabled.value);
- const listRef = vue.ref();
- const listEvents = 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 onListKeydown(e) {
- if (checkPrintable(e)) {
- vTextFieldRef.value?.focus();
- }
- }
- // eslint-disable-next-line complexity
- function onKeydown(e) {
- if (isComposingIgnoreKey(e) || form.isReadonly.value) return;
- const selectionStart = vTextFieldRef.value.selectionStart;
- const length = model.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) && !model.value.some(_ref2 => {
- let {
- value
- } = _ref2;
- return value === displayItems.value[0].value;
- })) {
- select(filteredItems.value[0]);
- }
- isPristine.value = true;
- }
- if (e.key === 'ArrowDown' && highlightFirst.value) {
- listRef.value?.focus('next');
- }
- if (e.key === 'Enter' && search.value) {
- select(transformItem$3(props, search.value));
- if (hasSelectionSlot.value) _search.value = '';
- }
- if (['Backspace', 'Delete'].includes(e.key)) {
- if (!props.multiple && hasSelectionSlot.value && model.value.length > 0 && !search.value) return select(model.value[0], false);
- if (~selectionIndex.value) {
- const originalSelectionIndex = selectionIndex.value;
- select(model.value[selectionIndex.value], false);
- selectionIndex.value = originalSelectionIndex >= length - 1 ? length - 2 : originalSelectionIndex;
- } else if (e.key === 'Backspace' && !search.value) {
- selectionIndex.value = length - 1;
- }
- }
- if (!props.multiple) return;
- if (e.key === 'ArrowLeft') {
- if (selectionIndex.value < 0 && selectionStart > 0) return;
- const prev = selectionIndex.value > -1 ? selectionIndex.value - 1 : length - 1;
- if (model.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 (model.value[next]) {
- selectionIndex.value = next;
- } else {
- selectionIndex.value = -1;
- vTextFieldRef.value.setSelectionRange(0, 0);
- }
- }
- }
- function onAfterEnter() {
- if (props.eager) {
- vVirtualScrollRef.value?.calculateVisibleItems();
- }
- }
- function onAfterLeave() {
- if (isFocused.value) {
- isPristine.value = true;
- vTextFieldRef.value?.focus();
- }
- }
- /** @param set - null means toggle */
- function select(item) {
- let set = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
- if (!item || item.props.disabled) return;
- if (props.multiple) {
- const index = model.value.findIndex(selection => props.valueComparator(selection.value, item.value));
- const add = set == null ? !~index : set;
- if (~index) {
- const value = add ? [...model.value, item] : [...model.value];
- value.splice(index, 1);
- model.value = value;
- } else if (add) {
- model.value = [...model.value, item];
- }
- if (props.clearOnSelect) {
- search.value = '';
- }
- } else {
- const add = set !== false;
- model.value = add ? [item] : [];
- _search.value = add && !hasSelectionSlot.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 && !hasSelectionSlot.value) model.value = [];
- }
- vue.watch(isFocused, (val, oldVal) => {
- if (val || val === oldVal) return;
- selectionIndex.value = -1;
- menu.value = false;
- if (search.value) {
- if (props.multiple) {
- select(transformItem$3(props, search.value));
- return;
- }
- if (!hasSelectionSlot.value) return;
- if (model.value.some(_ref3 => {
- let {
- title
- } = _ref3;
- return title === search.value;
- })) {
- _search.value = '';
- } else {
- select(transformItem$3(props, search.value));
- }
- }
- });
- vue.watch(menu, () => {
- if (!props.hideSelected && menu.value && model.value.length) {
- const index = displayItems.value.findIndex(item => model.value.some(s => props.valueComparator(s.value, item.value)));
- IN_BROWSER && window.requestAnimationFrame(() => {
- index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index);
- });
- }
- });
- vue.watch(() => props.items, (newVal, oldVal) => {
- if (menu.value) return;
- if (isFocused.value && !oldVal.length && newVal.length) {
- menu.value = true;
- }
- });
- useRender(() => {
- 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,
- "counterValue": counterValue.value,
- "dirty": isDirty,
- "class": ['v-combobox', {
- 'v-combobox--active-menu': menu.value,
- 'v-combobox--chips': !!props.chips,
- 'v-combobox--selection-slot': !!hasSelectionSlot.value,
- 'v-combobox--selecting-index': selectionIndex.value > -1,
- [`v-combobox--${props.multiple ? 'multiple' : 'single'}`]: true
- }, props.class],
- "style": props.style,
- "readonly": form.isReadonly.value,
- "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,
- "onAfterEnter": onAfterEnter,
- "onAfterLeave": onAfterLeave
- }, props.menuProps), {
- default: () => [hasList && vue.createVNode(VList, vue.mergeProps({
- "ref": listRef,
- "selected": selectedValues.value,
- "selectStrategy": props.multiple ? 'independent' : 'single-independent',
- "onMousedown": e => e.preventDefault(),
- "onKeydown": onListKeydown,
- "onFocusin": onFocusin,
- "onFocusout": onFocusout,
- "tabindex": "-1",
- "aria-live": "polite",
- "color": props.itemColor ?? props.color
- }, listEvents, props.listProps), {
- default: () => [slots['prepend-item']?.(), !displayItems.value.length && !props.hideNoData && (slots['no-data']?.() ?? vue.createVNode(VListItem, {
- "key": "no-data",
- "title": t(props.noDataText)
- }, null)), vue.createVNode(VVirtualScroll, {
- "ref": vVirtualScrollRef,
- "renderless": true,
- "items": displayItems.value
- }, {
- default: _ref4 => {
- let {
- item,
- index,
- itemRef
- } = _ref4;
- const itemProps = vue.mergeProps(item.props, {
- ref: itemRef,
- key: item.value,
- active: highlightFirst.value && index === 0 ? true : undefined,
- onClick: () => select(item, null)
- });
- return slots.item?.({
- item,
- index,
- props: itemProps
- }) ?? vue.createVNode(VListItem, vue.mergeProps(itemProps, {
- "role": "option"
- }), {
- prepend: _ref5 => {
- let {
- isSelected
- } = _ref5;
- 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.prependAvatar && vue.createVNode(VAvatar, {
- "image": item.props.prependAvatar
- }, null), 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']?.()]
- })]
- }), model.value.map((item, index) => {
- function onChipClose(e) {
- e.stopPropagation();
- e.preventDefault();
- select(item, false);
- }
- const slotProps = {
- 'onClick:close': onChipClose,
- onKeydown(e) {
- if (e.key !== 'Enter' && e.key !== ' ') return;
- e.preventDefault();
- e.stopPropagation();
- onChipClose(e);
- },
- onMousedown(e) {
- e.preventDefault();
- e.stopPropagation();
- },
- modelValue: true,
- 'onUpdate:modelValue': undefined
- };
- const hasSlot = hasChips.value ? !!slots.chip : !!slots.selection;
- const slotContent = hasSlot ? ensureValidVNode(hasChips.value ? slots.chip({
- item,
- index,
- props: slotProps
- }) : slots.selection({
- item,
- index
- })) : undefined;
- if (hasSlot && !slotContent) return 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.value ? !slots.chip ? vue.createVNode(VChip, vue.mergeProps({
- "key": "chip",
- "closable": props.closableChips,
- "size": "small",
- "text": item.title,
- "disabled": item.props.disabled
- }, slotProps), null) : vue.createVNode(VDefaultsProvider, {
- "key": "chip-defaults",
- "defaults": {
- VChip: {
- closable: props.closableChips,
- size: 'small',
- text: item.title
- }
- }
- }, {
- default: () => [slotContent]
- }) : slotContent ?? vue.createVNode("span", {
- "class": "v-combobox__selection-text"
- }, [item.title, props.multiple && index < model.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,
- "aria-label": t(label.value),
- "title": t(label.value),
- "tabindex": "-1"
- }, null) : undefined]);
- }
- });
- });
- return forwardRefs({
- isFocused,
- isPristine,
- menu,
- search,
- selectionIndex,
- filteredItems,
- select
- }, vTextFieldRef);
- }
- });
- // 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, firstDayOfWeek) {
- const weeks = [];
- let currentWeek = [];
- const firstDayOfMonth = startOfMonth(date);
- const lastDayOfMonth = endOfMonth(date);
- const first = firstDayOfWeek ?? firstDay[locale.slice(-2).toUpperCase()] ?? 0;
- const firstDayWeekIndex = (firstDayOfMonth.getDay() - first + 7) % 7;
- const lastDayWeekIndex = (lastDayOfMonth.getDay() - first + 7) % 7;
- 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);
- }
- if (currentWeek.length > 0) {
- weeks.push(currentWeek);
- }
- return weeks;
- }
- function startOfWeek(date, locale, firstDayOfWeek) {
- const day = firstDayOfWeek ?? firstDay[locale.slice(-2).toUpperCase()] ?? 0;
- const d = new Date(date);
- while (d.getDay() !== day) {
- d.setDate(d.getDate() - 1);
- }
- return d;
- }
- function endOfWeek(date, locale) {
- const d = new Date(date);
- const lastDay = ((firstDay[locale.slice(-2).toUpperCase()] ?? 0) + 6) % 7;
- while (d.getDay() !== lastDay) {
- d.setDate(d.getDate() + 1);
- }
- return d;
- }
- 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, firstDayOfWeek) {
- const daysFromSunday = firstDayOfWeek ?? firstDay[locale.slice(-2).toUpperCase()] ?? 0;
- return createRange(7).map(i => {
- const weekday = new Date(sundayJanuarySecond2000);
- weekday.setDate(sundayJanuarySecond2000.getDate() + daysFromSunday + i);
- return new Intl.DateTimeFormat(locale, {
- weekday: 'narrow'
- }).format(weekday);
- });
- }
- function format(value, formatString, locale, formats) {
- const newDate = date(value) ?? new Date();
- const customFormat = formats?.[formatString];
- if (typeof customFormat === 'function') {
- return customFormat(newDate, formatString, locale);
- }
- let options = {};
- switch (formatString) {
- case 'fullDate':
- options = {
- year: 'numeric',
- month: 'long',
- day: 'numeric'
- };
- break;
- case 'fullDateWithWeekday':
- options = {
- weekday: 'long',
- year: 'numeric',
- month: 'long',
- day: 'numeric'
- };
- break;
- case 'normalDate':
- const day = newDate.getDate();
- const month = new Intl.DateTimeFormat(locale, {
- month: 'long'
- }).format(newDate);
- return `${day} ${month}`;
- case 'normalDateWithWeekday':
- options = {
- weekday: 'short',
- day: 'numeric',
- month: 'short'
- };
- break;
- case 'shortDate':
- options = {
- month: 'short',
- day: 'numeric'
- };
- break;
- case 'year':
- options = {
- year: 'numeric'
- };
- break;
- case 'month':
- options = {
- month: 'long'
- };
- break;
- case 'monthShort':
- options = {
- month: 'short'
- };
- break;
- case 'monthAndYear':
- options = {
- month: 'long',
- year: 'numeric'
- };
- break;
- case 'monthAndDate':
- options = {
- month: 'long',
- day: 'numeric'
- };
- break;
- case 'weekday':
- options = {
- weekday: 'long'
- };
- break;
- case 'weekdayShort':
- options = {
- weekday: 'short'
- };
- break;
- case 'dayOfMonth':
- return new Intl.NumberFormat(locale).format(newDate.getDate());
- case 'hours12h':
- options = {
- hour: 'numeric',
- hour12: true
- };
- break;
- case 'hours24h':
- options = {
- hour: 'numeric',
- hour12: false
- };
- break;
- case 'minutes':
- options = {
- minute: 'numeric'
- };
- break;
- case 'seconds':
- options = {
- second: 'numeric'
- };
- break;
- case 'fullTime':
- options = {
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: true
- };
- break;
- case 'fullTime12h':
- options = {
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: true
- };
- break;
- case 'fullTime24h':
- options = {
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: false
- };
- break;
- case 'fullDateTime':
- options = {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: true
- };
- break;
- case 'fullDateTime12h':
- options = {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: true
- };
- break;
- case 'fullDateTime24h':
- options = {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: false
- };
- break;
- case 'keyboardDate':
- options = {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit'
- };
- break;
- case 'keyboardDateTime':
- options = {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit',
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: false
- };
- break;
- case 'keyboardDateTime12h':
- options = {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit',
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: true
- };
- break;
- case 'keyboardDateTime24h':
- options = {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit',
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: false
- };
- break;
- default:
- options = customFormat ?? {
- timeZone: 'UTC',
- timeZoneName: 'short'
- };
- }
- return new Intl.DateTimeFormat(locale, options).format(newDate);
- }
- function toISO(adapter, value) {
- const date = adapter.toJsDate(value);
- const year = date.getFullYear();
- const month = padStart(String(date.getMonth() + 1), 2, '0');
- const day = padStart(String(date.getDate()), 2, '0');
- return `${year}-${month}-${day}`;
- }
- function parseISO(value) {
- const [year, month, day] = value.split('-').map(Number);
- return new Date(year, month - 1, day);
- }
- function addMinutes(date, amount) {
- const d = new Date(date);
- d.setMinutes(d.getMinutes() + amount);
- return d;
- }
- function addHours(date, amount) {
- const d = new Date(date);
- d.setHours(d.getHours() + amount);
- return d;
- }
- function addDays(date, amount) {
- const d = new Date(date);
- d.setDate(d.getDate() + amount);
- return d;
- }
- function addWeeks(date, amount) {
- const d = new Date(date);
- d.setDate(d.getDate() + amount * 7);
- return d;
- }
- function addMonths(date, amount) {
- const d = new Date(date);
- d.setDate(1);
- d.setMonth(d.getMonth() + amount);
- return d;
- }
- function getYear(date) {
- return date.getFullYear();
- }
- function getMonth(date) {
- return date.getMonth();
- }
- function getDate(date) {
- return date.getDate();
- }
- function getNextMonth(date) {
- return new Date(date.getFullYear(), date.getMonth() + 1, 1);
- }
- function getPreviousMonth(date) {
- return new Date(date.getFullYear(), date.getMonth() - 1, 1);
- }
- function getHours(date) {
- return date.getHours();
- }
- function getMinutes(date) {
- return date.getMinutes();
- }
- 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 isAfterDay(date, comparing) {
- return isAfter(startOfDay(date), startOfDay(comparing));
- }
- 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 isSameYear(date, comparing) {
- return date.getFullYear() === comparing.getFullYear();
- }
- function getDiff(date, comparing, unit) {
- const d = new Date(date);
- const c = new Date(comparing);
- switch (unit) {
- case 'years':
- return d.getFullYear() - c.getFullYear();
- case 'quarters':
- return Math.floor((d.getMonth() - c.getMonth() + (d.getFullYear() - c.getFullYear()) * 12) / 4);
- case 'months':
- return d.getMonth() - c.getMonth() + (d.getFullYear() - c.getFullYear()) * 12;
- case 'weeks':
- return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60 * 24 * 7));
- case 'days':
- return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60 * 24));
- case 'hours':
- return Math.floor((d.getTime() - c.getTime()) / (1000 * 60 * 60));
- case 'minutes':
- return Math.floor((d.getTime() - c.getTime()) / (1000 * 60));
- case 'seconds':
- return Math.floor((d.getTime() - c.getTime()) / 1000);
- default:
- {
- return d.getTime() - c.getTime();
- }
- }
- }
- function setHours(date, count) {
- const d = new Date(date);
- d.setHours(count);
- return d;
- }
- function setMinutes(date, count) {
- const d = new Date(date);
- d.setMinutes(count);
- return d;
- }
- function setMonth(date, count) {
- const d = new Date(date);
- d.setMonth(count);
- return d;
- }
- function setDate(date, day) {
- const d = new Date(date);
- d.setDate(day);
- return d;
- }
- function setYear(date, year) {
- const d = new Date(date);
- d.setFullYear(year);
- return d;
- }
- function startOfDay(date) {
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);
- }
- function endOfDay(date) {
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);
- }
- class VuetifyDateAdapter {
- constructor(options) {
- this.locale = options.locale;
- this.formats = options.formats;
- }
- date(value) {
- return date(value);
- }
- toJsDate(date) {
- return date;
- }
- toISO(date) {
- return toISO(this, date);
- }
- parseISO(date) {
- return parseISO(date);
- }
- addMinutes(date, amount) {
- return addMinutes(date, amount);
- }
- addHours(date, amount) {
- return addHours(date, amount);
- }
- addDays(date, amount) {
- return addDays(date, amount);
- }
- addWeeks(date, amount) {
- return addWeeks(date, amount);
- }
- addMonths(date, amount) {
- return addMonths(date, amount);
- }
- getWeekArray(date, firstDayOfWeek) {
- return getWeekArray(date, this.locale, firstDayOfWeek ? Number(firstDayOfWeek) : undefined);
- }
- startOfWeek(date, firstDayOfWeek) {
- return startOfWeek(date, this.locale, firstDayOfWeek ? Number(firstDayOfWeek) : undefined);
- }
- endOfWeek(date) {
- return endOfWeek(date, this.locale);
- }
- startOfMonth(date) {
- return startOfMonth(date);
- }
- endOfMonth(date) {
- return endOfMonth(date);
- }
- format(date, formatString) {
- return format(date, formatString, this.locale, this.formats);
- }
- 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);
- }
- isAfterDay(date, comparing) {
- return isAfterDay(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);
- }
- isSameYear(date, comparing) {
- return isSameYear(date, comparing);
- }
- setMinutes(date, count) {
- return setMinutes(date, count);
- }
- setHours(date, count) {
- return setHours(date, count);
- }
- setMonth(date, count) {
- return setMonth(date, count);
- }
- setDate(date, day) {
- return setDate(date, day);
- }
- setYear(date, year) {
- return setYear(date, year);
- }
- getDiff(date, comparing, unit) {
- return getDiff(date, comparing, unit);
- }
- getWeekdays(firstDayOfWeek) {
- return getWeekdays(this.locale, firstDayOfWeek ? Number(firstDayOfWeek) : undefined);
- }
- getYear(date) {
- return getYear(date);
- }
- getMonth(date) {
- return getMonth(date);
- }
- getDate(date) {
- return getDate(date);
- }
- getNextMonth(date) {
- return getNextMonth(date);
- }
- getPreviousMonth(date) {
- return getPreviousMonth(date);
- }
- getHours(date) {
- return getHours(date);
- }
- getMinutes(date) {
- return getMinutes(date);
- }
- startOfDay(date) {
- return startOfDay(date);
- }
- endOfDay(date) {
- return endOfDay(date);
- }
- startOfYear(date) {
- return startOfYear(date);
- }
- endOfYear(date) {
- return endOfYear(date);
- }
- }
- // Composables
- const DateOptionsSymbol = Symbol.for('vuetify:date-options');
- const DateAdapterSymbol = Symbol.for('vuetify:date-adapter');
- function createDate(options, locale) {
- const _options = mergeDeep({
- adapter: VuetifyDateAdapter,
- locale: {
- af: 'af-ZA',
- // ar: '', # not the same value for all variants
- bg: 'bg-BG',
- ca: 'ca-ES',
- ckb: '',
- cs: 'cs-CZ',
- 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: 'no-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);
- return {
- options: _options,
- instance: createInstance(_options, locale)
- };
- }
- function createInstance(options, locale) {
- const instance = vue.reactive(typeof options.adapter === 'function'
- // eslint-disable-next-line new-cap
- ? new options.adapter({
- locale: options.locale[locale.current.value] ?? locale.current.value,
- formats: options.formats
- }) : options.adapter);
- vue.watch(locale.current, value => {
- instance.locale = options.locale[value] ?? value ?? instance.locale;
- });
- return instance;
- }
- function useDate() {
- const options = vue.inject(DateOptionsSymbol);
- if (!options) throw new Error('[Vuetify] Could not find injected date options');
- const locale = useLocale();
- return createInstance(options, locale);
- }
- // https://stackoverflow.com/questions/274861/how-do-i-calculate-the-week-number-given-a-date/275024#275024
- function getWeek(adapter, value) {
- const date = adapter.toJsDate(value);
- let year = date.getFullYear();
- let d1w1 = new Date(year, 0, 1);
- if (date < d1w1) {
- year = year - 1;
- d1w1 = new Date(year, 0, 1);
- } else {
- const tv = new Date(year + 1, 0, 1);
- if (date >= tv) {
- year = year + 1;
- d1w1 = tv;
- }
- }
- const diffTime = Math.abs(date.getTime() - d1w1.getTime());
- const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
- return Math.floor(diffDays / 7) + 1;
- }
- // Types
- const makeVConfirmEditProps = propsFactory({
- modelValue: null,
- color: String,
- cancelText: {
- type: String,
- default: '$vuetify.confirmEdit.cancel'
- },
- okText: {
- type: String,
- default: '$vuetify.confirmEdit.ok'
- }
- }, 'VConfirmEdit');
- const VConfirmEdit = genericComponent()({
- name: 'VConfirmEdit',
- props: makeVConfirmEditProps(),
- emits: {
- cancel: () => true,
- save: value => true,
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const internalModel = vue.ref();
- vue.watchEffect(() => {
- internalModel.value = structuredClone(vue.toRaw(model.value));
- });
- const {
- t
- } = useLocale();
- const isPristine = vue.computed(() => {
- return deepEqual(model.value, internalModel.value);
- });
- function save() {
- model.value = internalModel.value;
- emit('save', internalModel.value);
- }
- function cancel() {
- internalModel.value = structuredClone(vue.toRaw(model.value));
- emit('cancel');
- }
- function actions(actionsProps) {
- return vue.createVNode(vue.Fragment, null, [vue.createVNode(VBtn, vue.mergeProps({
- "disabled": isPristine.value,
- "variant": "text",
- "color": props.color,
- "onClick": cancel,
- "text": t(props.cancelText)
- }, actionsProps), null), vue.createVNode(VBtn, vue.mergeProps({
- "disabled": isPristine.value,
- "variant": "text",
- "color": props.color,
- "onClick": save,
- "text": t(props.okText)
- }, actionsProps), null)]);
- }
- let actionsUsed = false;
- useRender(() => {
- return vue.createVNode(vue.Fragment, null, [slots.default?.({
- model: internalModel,
- save,
- cancel,
- isPristine: isPristine.value,
- get actions() {
- actionsUsed = true;
- return actions;
- }
- }), !actionsUsed && actions()]);
- });
- return {
- save,
- cancel,
- isPristine
- };
- }
- });
- // Composables
- // Types
- const makeDataTableExpandProps = propsFactory({
- expandOnClick: Boolean,
- showExpand: Boolean,
- expanded: {
- type: Array,
- default: () => []
- }
- }, 'DataTable-expand');
- const VDataTableExpandedKey = Symbol.for('vuetify:datatable:expanded');
- function provideExpanded(props) {
- const expandOnClick = vue.toRef(props, 'expandOnClick');
- const expanded = useProxiedModel(props, 'expanded', props.expanded, v => {
- return new Set(v);
- }, v => {
- return [...v.values()];
- });
- function expand(item, value) {
- const newExpanded = new Set(expanded.value);
- if (!value) {
- newExpanded.delete(item.value);
- } else {
- newExpanded.add(item.value);
- }
- expanded.value = newExpanded;
- }
- function isExpanded(item) {
- return expanded.value.has(item.value);
- }
- function toggleExpand(item) {
- expand(item, !isExpanded(item));
- }
- const data = {
- expand,
- expanded,
- expandOnClick,
- isExpanded,
- toggleExpand
- };
- vue.provide(VDataTableExpandedKey, data);
- return data;
- }
- function useExpanded() {
- const data = vue.inject(VDataTableExpandedKey);
- if (!data) throw new Error('foo');
- return data;
- }
- // Composables
- // Types
- const makeDataTableGroupProps = propsFactory({
- groupBy: {
- type: Array,
- default: () => []
- }
- }, 'DataTable-group');
- const VDataTableGroupSymbol = Symbol.for('vuetify:data-table-group');
- function createGroupBy(props) {
- const groupBy = useProxiedModel(props, 'groupBy');
- return {
- groupBy
- };
- }
- function provideGroupBy(options) {
- const {
- disableSort,
- groupBy,
- sortBy
- } = options;
- const opened = vue.ref(new Set());
- const sortByWithGroups = vue.computed(() => {
- return groupBy.value.map(val => ({
- ...val,
- order: val.order ?? false
- })).concat(disableSort?.value ? [] : sortBy.value);
- });
- function isGroupOpen(group) {
- return opened.value.has(group.id);
- }
- function toggleGroup(group) {
- const newOpened = new Set(opened.value);
- if (!isGroupOpen(group)) newOpened.add(group.id);else newOpened.delete(group.id);
- opened.value = newOpened;
- }
- function extractRows(items) {
- function dive(group) {
- const arr = [];
- for (const item of group.items) {
- if ('type' in item && item.type === 'group') {
- arr.push(...dive(item));
- } else {
- arr.push(item);
- }
- }
- return arr;
- }
- return dive({
- type: 'group',
- items,
- id: 'dummy',
- key: 'dummy',
- value: 'dummy',
- depth: 0
- });
- }
- // onBeforeMount(() => {
- // for (const key of groupedItems.value.keys()) {
- // opened.value.add(key)
- // }
- // })
- const data = {
- sortByWithGroups,
- toggleGroup,
- opened,
- groupBy,
- extractRows,
- isGroupOpen
- };
- vue.provide(VDataTableGroupSymbol, data);
- return data;
- }
- function useGroupBy() {
- const data = vue.inject(VDataTableGroupSymbol);
- if (!data) throw new Error('Missing group!');
- return data;
- }
- function groupItemsByProperty(items, groupBy) {
- if (!items.length) return [];
- const groups = new Map();
- for (const item of items) {
- const value = getObjectValueByPath(item.raw, groupBy);
- if (!groups.has(value)) {
- groups.set(value, []);
- }
- groups.get(value).push(item);
- }
- return groups;
- }
- function groupItems(items, groupBy) {
- let depth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
- let prefix = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'root';
- if (!groupBy.length) return [];
- const groupedItems = groupItemsByProperty(items, groupBy[0]);
- const groups = [];
- const rest = groupBy.slice(1);
- groupedItems.forEach((items, value) => {
- const key = groupBy[0];
- const id = `${prefix}_${key}_${value}`;
- groups.push({
- depth,
- id,
- key,
- value,
- items: rest.length ? groupItems(items, rest, depth + 1, id) : items,
- type: 'group'
- });
- });
- return groups;
- }
- function flattenItems(items, opened) {
- const flatItems = [];
- for (const item of items) {
- // TODO: make this better
- if ('type' in item && item.type === 'group') {
- if (item.value != null) {
- flatItems.push(item);
- }
- if (opened.has(item.id) || item.value == null) {
- flatItems.push(...flattenItems(item.items, opened));
- }
- } else {
- flatItems.push(item);
- }
- }
- return flatItems;
- }
- function useGroupedItems(items, groupBy, opened) {
- const flatItems = vue.computed(() => {
- if (!groupBy.value.length) return items.value;
- const groupedItems = groupItems(items.value, groupBy.value.map(item => item.key));
- return flattenItems(groupedItems, opened.value);
- });
- return {
- flatItems
- };
- }
- // Utilities
- // Types
- function useOptions(_ref) {
- let {
- page,
- itemsPerPage,
- sortBy,
- groupBy,
- search
- } = _ref;
- const vm = getCurrentInstance('VDataTable');
- const options = vue.computed(() => ({
- page: page.value,
- itemsPerPage: itemsPerPage.value,
- sortBy: sortBy.value,
- groupBy: groupBy.value,
- search: search.value
- }));
- let oldOptions = null;
- vue.watch(options, () => {
- if (deepEqual(oldOptions, options.value)) return;
- // Reset page when searching
- if (oldOptions && oldOptions.search !== options.value.search) {
- page.value = 1;
- }
- vm.emit('update:options', options.value);
- oldOptions = options.value;
- }, {
- deep: true,
- immediate: true
- });
- }
- // Composables
- // Types
- const makeDataTablePaginateProps = propsFactory({
- page: {
- type: [Number, String],
- default: 1
- },
- itemsPerPage: {
- type: [Number, String],
- default: 10
- }
- }, 'DataTable-paginate');
- const VDataTablePaginationSymbol = Symbol.for('vuetify:data-table-pagination');
- function createPagination(props) {
- const page = useProxiedModel(props, 'page', undefined, value => +(value ?? 1));
- const itemsPerPage = useProxiedModel(props, 'itemsPerPage', undefined, value => +(value ?? 10));
- return {
- page,
- itemsPerPage
- };
- }
- function providePagination(options) {
- const {
- page,
- itemsPerPage,
- itemsLength
- } = options;
- const startIndex = vue.computed(() => {
- if (itemsPerPage.value === -1) return 0;
- return itemsPerPage.value * (page.value - 1);
- });
- const stopIndex = vue.computed(() => {
- if (itemsPerPage.value === -1) return itemsLength.value;
- return Math.min(itemsLength.value, startIndex.value + itemsPerPage.value);
- });
- const pageCount = vue.computed(() => {
- if (itemsPerPage.value === -1 || itemsLength.value === 0) return 1;
- return Math.ceil(itemsLength.value / itemsPerPage.value);
- });
- // Don't run immediately, items may not have been loaded yet: #17966
- vue.watch([page, pageCount], () => {
- if (page.value > pageCount.value) {
- page.value = pageCount.value;
- }
- });
- function setItemsPerPage(value) {
- itemsPerPage.value = value;
- page.value = 1;
- }
- function nextPage() {
- page.value = clamp(page.value + 1, 1, pageCount.value);
- }
- function prevPage() {
- page.value = clamp(page.value - 1, 1, pageCount.value);
- }
- function setPage(value) {
- page.value = clamp(value, 1, pageCount.value);
- }
- const data = {
- page,
- itemsPerPage,
- startIndex,
- stopIndex,
- pageCount,
- itemsLength,
- nextPage,
- prevPage,
- setPage,
- setItemsPerPage
- };
- vue.provide(VDataTablePaginationSymbol, data);
- return data;
- }
- function usePagination() {
- const data = vue.inject(VDataTablePaginationSymbol);
- if (!data) throw new Error('Missing pagination!');
- return data;
- }
- function usePaginatedItems(options) {
- const vm = getCurrentInstance('usePaginatedItems');
- const {
- items,
- startIndex,
- stopIndex,
- itemsPerPage
- } = options;
- const paginatedItems = vue.computed(() => {
- if (itemsPerPage.value <= 0) return items.value;
- return items.value.slice(startIndex.value, stopIndex.value);
- });
- vue.watch(paginatedItems, val => {
- vm.emit('update:currentItems', val);
- });
- return {
- paginatedItems
- };
- }
- // Composables
- // Types
- const singleSelectStrategy = {
- showSelectAll: false,
- allSelected: () => [],
- select: _ref => {
- let {
- items,
- value
- } = _ref;
- return new Set(value ? [items[0]?.value] : []);
- },
- selectAll: _ref2 => {
- let {
- selected
- } = _ref2;
- return selected;
- }
- };
- const pageSelectStrategy = {
- showSelectAll: true,
- allSelected: _ref3 => {
- let {
- currentPage
- } = _ref3;
- return currentPage;
- },
- select: _ref4 => {
- let {
- items,
- value,
- selected
- } = _ref4;
- for (const item of items) {
- if (value) selected.add(item.value);else selected.delete(item.value);
- }
- return selected;
- },
- selectAll: _ref5 => {
- let {
- value,
- currentPage,
- selected
- } = _ref5;
- return pageSelectStrategy.select({
- items: currentPage,
- value,
- selected
- });
- }
- };
- const allSelectStrategy = {
- showSelectAll: true,
- allSelected: _ref6 => {
- let {
- allItems
- } = _ref6;
- return allItems;
- },
- select: _ref7 => {
- let {
- items,
- value,
- selected
- } = _ref7;
- for (const item of items) {
- if (value) selected.add(item.value);else selected.delete(item.value);
- }
- return selected;
- },
- selectAll: _ref8 => {
- let {
- value,
- allItems,
- selected
- } = _ref8;
- return allSelectStrategy.select({
- items: allItems,
- value,
- selected
- });
- }
- };
- const makeDataTableSelectProps = propsFactory({
- showSelect: Boolean,
- selectStrategy: {
- type: [String, Object],
- default: 'page'
- },
- modelValue: {
- type: Array,
- default: () => []
- },
- valueComparator: {
- type: Function,
- default: deepEqual
- }
- }, 'DataTable-select');
- const VDataTableSelectionSymbol = Symbol.for('vuetify:data-table-selection');
- function provideSelection(props, _ref9) {
- let {
- allItems,
- currentPage
- } = _ref9;
- const selected = useProxiedModel(props, 'modelValue', props.modelValue, v => {
- return new Set(wrapInArray(v).map(v => {
- return allItems.value.find(item => props.valueComparator(v, item.value))?.value ?? v;
- }));
- }, v => {
- return [...v.values()];
- });
- const allSelectable = vue.computed(() => allItems.value.filter(item => item.selectable));
- const currentPageSelectable = vue.computed(() => currentPage.value.filter(item => item.selectable));
- const selectStrategy = vue.computed(() => {
- if (typeof props.selectStrategy === 'object') return props.selectStrategy;
- switch (props.selectStrategy) {
- case 'single':
- return singleSelectStrategy;
- case 'all':
- return allSelectStrategy;
- case 'page':
- default:
- return pageSelectStrategy;
- }
- });
- function isSelected(items) {
- return wrapInArray(items).every(item => selected.value.has(item.value));
- }
- function isSomeSelected(items) {
- return wrapInArray(items).some(item => selected.value.has(item.value));
- }
- function select(items, value) {
- const newSelected = selectStrategy.value.select({
- items,
- value,
- selected: new Set(selected.value)
- });
- selected.value = newSelected;
- }
- function toggleSelect(item) {
- select([item], !isSelected([item]));
- }
- function selectAll(value) {
- const newSelected = selectStrategy.value.selectAll({
- value,
- allItems: allSelectable.value,
- currentPage: currentPageSelectable.value,
- selected: new Set(selected.value)
- });
- selected.value = newSelected;
- }
- const someSelected = vue.computed(() => selected.value.size > 0);
- const allSelected = vue.computed(() => {
- const items = selectStrategy.value.allSelected({
- allItems: allSelectable.value,
- currentPage: currentPageSelectable.value
- });
- return !!items.length && isSelected(items);
- });
- const showSelectAll = vue.computed(() => selectStrategy.value.showSelectAll);
- const data = {
- toggleSelect,
- select,
- selectAll,
- isSelected,
- isSomeSelected,
- someSelected,
- allSelected,
- showSelectAll
- };
- vue.provide(VDataTableSelectionSymbol, data);
- return data;
- }
- function useSelection() {
- const data = vue.inject(VDataTableSelectionSymbol);
- if (!data) throw new Error('Missing selection!');
- return data;
- }
- // Composables
- // Types
- const makeDataTableSortProps = propsFactory({
- sortBy: {
- type: Array,
- default: () => []
- },
- customKeySort: Object,
- multiSort: Boolean,
- mustSort: Boolean
- }, 'DataTable-sort');
- const VDataTableSortSymbol = Symbol.for('vuetify:data-table-sort');
- function createSort(props) {
- const sortBy = useProxiedModel(props, 'sortBy');
- const mustSort = vue.toRef(props, 'mustSort');
- const multiSort = vue.toRef(props, 'multiSort');
- return {
- sortBy,
- mustSort,
- multiSort
- };
- }
- function provideSort(options) {
- const {
- sortBy,
- mustSort,
- multiSort,
- page
- } = options;
- const toggleSort = column => {
- if (column.key == null) return;
- let newSortBy = sortBy.value.map(x => ({
- ...x
- })) ?? [];
- const item = newSortBy.find(x => x.key === column.key);
- if (!item) {
- if (multiSort.value) newSortBy = [...newSortBy, {
- key: column.key,
- order: 'asc'
- }];else newSortBy = [{
- key: column.key,
- order: 'asc'
- }];
- } else if (item.order === 'desc') {
- if (mustSort.value) {
- item.order = 'asc';
- } else {
- newSortBy = newSortBy.filter(x => x.key !== column.key);
- }
- } else {
- item.order = 'desc';
- }
- sortBy.value = newSortBy;
- if (page) page.value = 1;
- };
- function isSorted(column) {
- return !!sortBy.value.find(item => item.key === column.key);
- }
- const data = {
- sortBy,
- toggleSort,
- isSorted
- };
- vue.provide(VDataTableSortSymbol, data);
- return data;
- }
- function useSort() {
- const data = vue.inject(VDataTableSortSymbol);
- if (!data) throw new Error('Missing sort!');
- return data;
- }
- // TODO: abstract into project composable
- function useSortedItems(props, items, sortBy, options) {
- const locale = useLocale();
- const sortedItems = vue.computed(() => {
- if (!sortBy.value.length) return items.value;
- return sortItems(items.value, sortBy.value, locale.current.value, {
- transform: options?.transform,
- sortFunctions: {
- ...props.customKeySort,
- ...options?.sortFunctions?.value
- },
- sortRawFunctions: options?.sortRawFunctions?.value
- });
- });
- return {
- sortedItems
- };
- }
- function sortItems(items, sortByItems, locale, options) {
- const stringCollator = new Intl.Collator(locale, {
- sensitivity: 'accent',
- usage: 'sort'
- });
- const transformedItems = items.map(item => [item, options?.transform ? options.transform(item) : item]);
- return transformedItems.sort((a, b) => {
- for (let i = 0; i < sortByItems.length; i++) {
- let hasCustomResult = false;
- const sortKey = sortByItems[i].key;
- const sortOrder = sortByItems[i].order ?? 'asc';
- if (sortOrder === false) continue;
- let sortA = getObjectValueByPath(a[1], sortKey);
- let sortB = getObjectValueByPath(b[1], sortKey);
- let sortARaw = a[0].raw;
- let sortBRaw = b[0].raw;
- if (sortOrder === 'desc') {
- [sortA, sortB] = [sortB, sortA];
- [sortARaw, sortBRaw] = [sortBRaw, sortARaw];
- }
- if (options?.sortRawFunctions?.[sortKey]) {
- const customResult = options.sortRawFunctions[sortKey](sortARaw, sortBRaw);
- if (customResult == null) continue;
- hasCustomResult = true;
- if (customResult) return customResult;
- }
- if (options?.sortFunctions?.[sortKey]) {
- const customResult = options.sortFunctions[sortKey](sortA, sortB);
- if (customResult == null) continue;
- hasCustomResult = true;
- if (customResult) return customResult;
- }
- if (hasCustomResult) continue;
- // Dates should be compared numerically
- if (sortA instanceof Date && sortB instanceof Date) {
- return sortA.getTime() - sortB.getTime();
- }
- [sortA, sortB] = [sortA, sortB].map(s => s != null ? s.toString().toLocaleLowerCase() : s);
- if (sortA !== sortB) {
- if (isEmpty(sortA) && isEmpty(sortB)) return 0;
- if (isEmpty(sortA)) return -1;
- if (isEmpty(sortB)) return 1;
- if (!isNaN(sortA) && !isNaN(sortB)) return Number(sortA) - Number(sortB);
- return stringCollator.compare(sortA, sortB);
- }
- }
- return 0;
- }).map(_ref => {
- let [item] = _ref;
- return item;
- });
- }
- // Utilities
- // Types
- // Composables
- const makeDataIteratorItemsProps = propsFactory({
- items: {
- type: Array,
- default: () => []
- },
- itemValue: {
- type: [String, Array, Function],
- default: 'id'
- },
- itemSelectable: {
- type: [String, Array, Function],
- default: null
- },
- returnObject: Boolean
- }, 'DataIterator-items');
- function transformItem$1(props, item) {
- const value = props.returnObject ? item : getPropertyFromItem(item, props.itemValue);
- const selectable = getPropertyFromItem(item, props.itemSelectable, true);
- return {
- type: 'item',
- value,
- selectable,
- raw: item
- };
- }
- function transformItems$1(props, items) {
- const array = [];
- for (const item of items) {
- array.push(transformItem$1(props, item));
- }
- return array;
- }
- function useDataIteratorItems(props) {
- const items = vue.computed(() => transformItems$1(props, props.items));
- return {
- items
- };
- }
- // Types
- const makeVDataIteratorProps = propsFactory({
- search: String,
- loading: Boolean,
- ...makeComponentProps(),
- ...makeDataIteratorItemsProps(),
- ...makeDataTableSelectProps(),
- ...makeDataTableSortProps(),
- ...makeDataTablePaginateProps({
- itemsPerPage: 5
- }),
- ...makeDataTableExpandProps(),
- ...makeDataTableGroupProps(),
- ...makeFilterProps(),
- ...makeTagProps(),
- ...makeTransitionProps({
- transition: {
- component: VFadeTransition,
- hideOnLeave: true
- }
- })
- }, 'VDataIterator');
- const VDataIterator = genericComponent()({
- name: 'VDataIterator',
- props: makeVDataIteratorProps(),
- emits: {
- 'update:modelValue': value => true,
- 'update:groupBy': value => true,
- 'update:page': value => true,
- 'update:itemsPerPage': value => true,
- 'update:sortBy': value => true,
- 'update:options': value => true,
- 'update:expanded': value => true,
- 'update:currentItems': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const groupBy = useProxiedModel(props, 'groupBy');
- const search = vue.toRef(props, 'search');
- const {
- items
- } = useDataIteratorItems(props);
- const {
- filteredItems
- } = useFilter(props, items, search, {
- transform: item => item.raw
- });
- const {
- sortBy,
- multiSort,
- mustSort
- } = createSort(props);
- const {
- page,
- itemsPerPage
- } = createPagination(props);
- const {
- toggleSort
- } = provideSort({
- sortBy,
- multiSort,
- mustSort,
- page
- });
- const {
- sortByWithGroups,
- opened,
- extractRows,
- isGroupOpen,
- toggleGroup
- } = provideGroupBy({
- groupBy,
- sortBy
- });
- const {
- sortedItems
- } = useSortedItems(props, filteredItems, sortByWithGroups, {
- transform: item => item.raw
- });
- const {
- flatItems
- } = useGroupedItems(sortedItems, groupBy, opened);
- const itemsLength = vue.computed(() => flatItems.value.length);
- const {
- startIndex,
- stopIndex,
- pageCount,
- prevPage,
- nextPage,
- setItemsPerPage,
- setPage
- } = providePagination({
- page,
- itemsPerPage,
- itemsLength
- });
- const {
- paginatedItems
- } = usePaginatedItems({
- items: flatItems,
- startIndex,
- stopIndex,
- itemsPerPage
- });
- const paginatedItemsWithoutGroups = vue.computed(() => extractRows(paginatedItems.value));
- const {
- isSelected,
- select,
- selectAll,
- toggleSelect
- } = provideSelection(props, {
- allItems: items,
- currentPage: paginatedItemsWithoutGroups
- });
- const {
- isExpanded,
- toggleExpand
- } = provideExpanded(props);
- useOptions({
- page,
- itemsPerPage,
- sortBy,
- groupBy,
- search
- });
- const slotProps = vue.computed(() => ({
- page: page.value,
- itemsPerPage: itemsPerPage.value,
- sortBy: sortBy.value,
- pageCount: pageCount.value,
- toggleSort,
- prevPage,
- nextPage,
- setPage,
- setItemsPerPage,
- isSelected,
- select,
- selectAll,
- toggleSelect,
- isExpanded,
- toggleExpand,
- isGroupOpen,
- toggleGroup,
- items: paginatedItemsWithoutGroups.value,
- groupedItems: paginatedItems.value
- }));
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-data-iterator', {
- 'v-data-iterator--loading': props.loading
- }, props.class],
- "style": props.style
- }, {
- default: () => [slots.header?.(slotProps.value), vue.createVNode(MaybeTransition, {
- "transition": props.transition
- }, {
- default: () => [props.loading ? vue.createVNode(LoaderSlot, {
- "key": "loader",
- "name": "v-data-iterator",
- "active": true
- }, {
- default: slotProps => slots.loader?.(slotProps)
- }) : vue.createVNode("div", {
- "key": "items"
- }, [!paginatedItems.value.length ? slots['no-data']?.() : slots.default?.(slotProps.value)])]
- }), slots.footer?.(slotProps.value)]
- }));
- return {};
- }
- });
- // 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 != null) 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 <= 0) return [];else 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,
- 'aria-current': isActive,
- 'aria-label': 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,
- 'aria-label': t(props.firstAriaLabel),
- 'aria-disabled': prevDisabled
- } : undefined,
- prev: {
- icon: isRtl.value ? props.nextIcon : props.prevIcon,
- onClick: e => setValue(e, page.value - 1, 'prev'),
- disabled: prevDisabled,
- 'aria-label': t(props.previousAriaLabel),
- 'aria-disabled': prevDisabled
- },
- next: {
- icon: isRtl.value ? props.prevIcon : props.nextIcon,
- onClick: e => setValue(e, page.value + 1, 'next'),
- disabled: nextDisabled,
- 'aria-label': t(props.nextAriaLabel),
- 'aria-disabled': nextDisabled
- },
- last: props.showFirstLastPage ? {
- icon: isRtl.value ? props.firstIcon : props.lastIcon,
- onClick: e => setValue(e, start.value + length.value - 1, 'last'),
- disabled: nextDisabled,
- 'aria-label': t(props.lastAriaLabel),
- 'aria-disabled': 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
- const makeVDataTableFooterProps = propsFactory({
- prevIcon: {
- type: IconValue,
- default: '$prev'
- },
- nextIcon: {
- type: IconValue,
- default: '$next'
- },
- firstIcon: {
- type: IconValue,
- default: '$first'
- },
- lastIcon: {
- type: IconValue,
- default: '$last'
- },
- itemsPerPageText: {
- type: String,
- default: '$vuetify.dataFooter.itemsPerPageText'
- },
- pageText: {
- type: String,
- default: '$vuetify.dataFooter.pageText'
- },
- firstPageLabel: {
- type: String,
- default: '$vuetify.dataFooter.firstPage'
- },
- prevPageLabel: {
- type: String,
- default: '$vuetify.dataFooter.prevPage'
- },
- nextPageLabel: {
- type: String,
- default: '$vuetify.dataFooter.nextPage'
- },
- lastPageLabel: {
- type: String,
- default: '$vuetify.dataFooter.lastPage'
- },
- itemsPerPageOptions: {
- type: Array,
- default: () => [{
- value: 10,
- title: '10'
- }, {
- value: 25,
- title: '25'
- }, {
- value: 50,
- title: '50'
- }, {
- value: 100,
- title: '100'
- }, {
- value: -1,
- title: '$vuetify.dataFooter.itemsPerPageAll'
- }]
- },
- showCurrentPage: Boolean
- }, 'VDataTableFooter');
- const VDataTableFooter = genericComponent()({
- name: 'VDataTableFooter',
- props: makeVDataTableFooterProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const {
- page,
- pageCount,
- startIndex,
- stopIndex,
- itemsLength,
- itemsPerPage,
- setItemsPerPage
- } = usePagination();
- const itemsPerPageOptions = vue.computed(() => props.itemsPerPageOptions.map(option => {
- if (typeof option === 'number') {
- return {
- value: option,
- title: option === -1 ? t('$vuetify.dataFooter.itemsPerPageAll') : String(option)
- };
- }
- return {
- ...option,
- title: !isNaN(Number(option.title)) ? option.title : t(option.title)
- };
- }));
- useRender(() => {
- const paginationProps = VPagination.filterProps(props);
- return vue.createVNode("div", {
- "class": "v-data-table-footer"
- }, [slots.prepend?.(), vue.createVNode("div", {
- "class": "v-data-table-footer__items-per-page"
- }, [vue.createVNode("span", null, [t(props.itemsPerPageText)]), vue.createVNode(VSelect, {
- "items": itemsPerPageOptions.value,
- "modelValue": itemsPerPage.value,
- "onUpdate:modelValue": v => setItemsPerPage(Number(v)),
- "density": "compact",
- "variant": "outlined",
- "hide-details": true
- }, null)]), vue.createVNode("div", {
- "class": "v-data-table-footer__info"
- }, [vue.createVNode("div", null, [t(props.pageText, !itemsLength.value ? 0 : startIndex.value + 1, stopIndex.value, itemsLength.value)])]), vue.createVNode("div", {
- "class": "v-data-table-footer__pagination"
- }, [vue.createVNode(VPagination, vue.mergeProps({
- "modelValue": page.value,
- "onUpdate:modelValue": $event => page.value = $event,
- "density": "comfortable",
- "first-aria-label": props.firstPageLabel,
- "last-aria-label": props.lastPageLabel,
- "length": pageCount.value,
- "next-aria-label": props.nextPageLabel,
- "previous-aria-label": props.prevPageLabel,
- "rounded": true,
- "show-first-last-page": true,
- "total-visible": props.showCurrentPage ? 1 : 0,
- "variant": "plain"
- }, paginationProps), null)])]);
- });
- return {};
- }
- });
- // Types
- const VDataTableColumn = defineFunctionalComponent({
- align: {
- type: String,
- default: 'start'
- },
- fixed: Boolean,
- fixedOffset: [Number, String],
- height: [Number, String],
- lastFixed: Boolean,
- noPadding: Boolean,
- tag: String,
- width: [Number, String],
- maxWidth: [Number, String],
- nowrap: Boolean
- }, (props, _ref) => {
- let {
- slots
- } = _ref;
- const Tag = props.tag ?? 'td';
- return vue.createVNode(Tag, {
- "class": ['v-data-table__td', {
- 'v-data-table-column--fixed': props.fixed,
- 'v-data-table-column--last-fixed': props.lastFixed,
- 'v-data-table-column--no-padding': props.noPadding,
- 'v-data-table-column--nowrap': props.nowrap
- }, `v-data-table-column--align-${props.align}`],
- "style": {
- height: convertToUnit(props.height),
- width: convertToUnit(props.width),
- maxWidth: convertToUnit(props.maxWidth),
- left: convertToUnit(props.fixedOffset || null)
- }
- }, {
- default: () => [slots.default?.()]
- });
- });
- // Utilities
- // Types
- const makeDataTableHeaderProps = propsFactory({
- headers: Array
- }, 'DataTable-header');
- const VDataTableHeadersSymbol = Symbol.for('vuetify:data-table-headers');
- const defaultHeader = {
- title: '',
- sortable: false
- };
- const defaultActionHeader = {
- ...defaultHeader,
- width: 48
- };
- function priorityQueue() {
- let arr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
- const queue = arr.map(element => ({
- element,
- priority: 0
- }));
- return {
- enqueue: (element, priority) => {
- let added = false;
- for (let i = 0; i < queue.length; i++) {
- const item = queue[i];
- if (item.priority > priority) {
- queue.splice(i, 0, {
- element,
- priority
- });
- added = true;
- break;
- }
- }
- if (!added) queue.push({
- element,
- priority
- });
- },
- size: () => queue.length,
- count: () => {
- let count = 0;
- if (!queue.length) return 0;
- const whole = Math.floor(queue[0].priority);
- for (let i = 0; i < queue.length; i++) {
- if (Math.floor(queue[i].priority) === whole) count += 1;
- }
- return count;
- },
- dequeue: () => {
- return queue.shift();
- }
- };
- }
- function extractLeaves(item) {
- let columns = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
- if (!item.children) {
- columns.push(item);
- } else {
- for (const child of item.children) {
- extractLeaves(child, columns);
- }
- }
- return columns;
- }
- function extractKeys(headers) {
- let keys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Set();
- for (const item of headers) {
- if (item.key) keys.add(item.key);
- if (item.children) {
- extractKeys(item.children, keys);
- }
- }
- return keys;
- }
- function getDefaultItem(item) {
- if (!item.key) return undefined;
- if (item.key === 'data-table-group') return defaultHeader;
- if (['data-table-expand', 'data-table-select'].includes(item.key)) return defaultActionHeader;
- return undefined;
- }
- function getDepth(item) {
- let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
- if (!item.children) return depth;
- return Math.max(depth, ...item.children.map(child => getDepth(child, depth + 1)));
- }
- function parseFixedColumns(items) {
- let seenFixed = false;
- function setFixed(item) {
- let parentFixed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
- if (!item) return;
- if (parentFixed) {
- item.fixed = true;
- }
- if (item.fixed) {
- if (item.children) {
- for (let i = item.children.length - 1; i >= 0; i--) {
- setFixed(item.children[i], true);
- }
- } else {
- if (!seenFixed) {
- item.lastFixed = true;
- } else if (isNaN(+item.width)) {
- consoleError(`Multiple fixed columns should have a static width (key: ${item.key})`);
- }
- seenFixed = true;
- }
- } else {
- if (item.children) {
- for (let i = item.children.length - 1; i >= 0; i--) {
- setFixed(item.children[i]);
- }
- } else {
- seenFixed = false;
- }
- }
- }
- for (let i = items.length - 1; i >= 0; i--) {
- setFixed(items[i]);
- }
- function setFixedOffset(item) {
- let fixedOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
- if (!item) return fixedOffset;
- if (item.children) {
- item.fixedOffset = fixedOffset;
- for (const child of item.children) {
- fixedOffset = setFixedOffset(child, fixedOffset);
- }
- } else if (item.fixed) {
- item.fixedOffset = fixedOffset;
- fixedOffset += parseFloat(item.width || '0') || 0;
- }
- return fixedOffset;
- }
- let fixedOffset = 0;
- for (const item of items) {
- fixedOffset = setFixedOffset(item, fixedOffset);
- }
- }
- function parse(items, maxDepth) {
- const headers = [];
- let currentDepth = 0;
- const queue = priorityQueue(items);
- while (queue.size() > 0) {
- let rowSize = queue.count();
- const row = [];
- let fraction = 1;
- while (rowSize > 0) {
- const {
- element: item,
- priority
- } = queue.dequeue();
- const diff = maxDepth - currentDepth - getDepth(item);
- row.push({
- ...item,
- rowspan: diff ?? 1,
- colspan: item.children ? extractLeaves(item).length : 1
- });
- if (item.children) {
- for (const child of item.children) {
- // This internally sorts items that are on the same priority "row"
- const sort = priority % 1 + fraction / Math.pow(10, currentDepth + 2);
- queue.enqueue(child, currentDepth + diff + sort);
- }
- }
- fraction += 1;
- rowSize -= 1;
- }
- currentDepth += 1;
- headers.push(row);
- }
- const columns = items.map(item => extractLeaves(item)).flat();
- return {
- columns,
- headers
- };
- }
- function convertToInternalHeaders(items) {
- const internalHeaders = [];
- for (const item of items) {
- const defaultItem = {
- ...getDefaultItem(item),
- ...item
- };
- const key = defaultItem.key ?? (typeof defaultItem.value === 'string' ? defaultItem.value : null);
- const value = defaultItem.value ?? key ?? null;
- const internalItem = {
- ...defaultItem,
- key,
- value,
- sortable: defaultItem.sortable ?? (defaultItem.key != null || !!defaultItem.sort),
- children: defaultItem.children ? convertToInternalHeaders(defaultItem.children) : undefined
- };
- internalHeaders.push(internalItem);
- }
- return internalHeaders;
- }
- function createHeaders(props, options) {
- const headers = vue.ref([]);
- const columns = vue.ref([]);
- const sortFunctions = vue.ref({});
- const sortRawFunctions = vue.ref({});
- const filterFunctions = vue.ref({});
- vue.watchEffect(() => {
- const _headers = props.headers || Object.keys(props.items[0] ?? {}).map(key => ({
- key,
- title: vue.capitalize(key)
- }));
- const items = _headers.slice();
- const keys = extractKeys(items);
- if (options?.groupBy?.value.length && !keys.has('data-table-group')) {
- items.unshift({
- key: 'data-table-group',
- title: 'Group'
- });
- }
- if (options?.showSelect?.value && !keys.has('data-table-select')) {
- items.unshift({
- key: 'data-table-select'
- });
- }
- if (options?.showExpand?.value && !keys.has('data-table-expand')) {
- items.push({
- key: 'data-table-expand'
- });
- }
- const internalHeaders = convertToInternalHeaders(items);
- parseFixedColumns(internalHeaders);
- const maxDepth = Math.max(...internalHeaders.map(item => getDepth(item))) + 1;
- const parsed = parse(internalHeaders, maxDepth);
- headers.value = parsed.headers;
- columns.value = parsed.columns;
- const flatHeaders = parsed.headers.flat(1);
- for (const header of flatHeaders) {
- if (!header.key) continue;
- if (header.sortable) {
- if (header.sort) {
- sortFunctions.value[header.key] = header.sort;
- }
- if (header.sortRaw) {
- sortRawFunctions.value[header.key] = header.sortRaw;
- }
- }
- if (header.filter) {
- filterFunctions.value[header.key] = header.filter;
- }
- }
- });
- const data = {
- headers,
- columns,
- sortFunctions,
- sortRawFunctions,
- filterFunctions
- };
- vue.provide(VDataTableHeadersSymbol, data);
- return data;
- }
- function useHeaders() {
- const data = vue.inject(VDataTableHeadersSymbol);
- if (!data) throw new Error('Missing headers!');
- return data;
- }
- // Types
- const makeVDataTableHeadersProps = propsFactory({
- color: String,
- sticky: Boolean,
- disableSort: Boolean,
- multiSort: Boolean,
- sortAscIcon: {
- type: IconValue,
- default: '$sortAsc'
- },
- sortDescIcon: {
- type: IconValue,
- default: '$sortDesc'
- },
- headerProps: {
- type: Object
- },
- ...makeDisplayProps(),
- ...makeLoaderProps()
- }, 'VDataTableHeaders');
- const VDataTableHeaders = genericComponent()({
- name: 'VDataTableHeaders',
- props: makeVDataTableHeadersProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const {
- toggleSort,
- sortBy,
- isSorted
- } = useSort();
- const {
- someSelected,
- allSelected,
- selectAll,
- showSelectAll
- } = useSelection();
- const {
- columns,
- headers
- } = useHeaders();
- const {
- loaderClasses
- } = useLoader(props);
- function getFixedStyles(column, y) {
- if (!props.sticky && !column.fixed) return undefined;
- return {
- position: 'sticky',
- left: column.fixed ? convertToUnit(column.fixedOffset) : undefined,
- top: props.sticky ? `calc(var(--v-table-header-height) * ${y})` : undefined
- };
- }
- function getSortIcon(column) {
- const item = sortBy.value.find(item => item.key === column.key);
- if (!item) return props.sortAscIcon;
- return item.order === 'asc' ? props.sortAscIcon : props.sortDescIcon;
- }
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(props, 'color');
- const {
- displayClasses,
- mobile
- } = useDisplay(props);
- const slotProps = vue.computed(() => ({
- headers: headers.value,
- columns: columns.value,
- toggleSort,
- isSorted,
- sortBy: sortBy.value,
- someSelected: someSelected.value,
- allSelected: allSelected.value,
- selectAll,
- getSortIcon
- }));
- const headerCellClasses = vue.computed(() => ['v-data-table__th', {
- 'v-data-table__th--sticky': props.sticky
- }, displayClasses.value, loaderClasses.value]);
- const VDataTableHeaderCell = _ref2 => {
- let {
- column,
- x,
- y
- } = _ref2;
- const noPadding = column.key === 'data-table-select' || column.key === 'data-table-expand';
- const headerProps = vue.mergeProps(props.headerProps ?? {}, column.headerProps ?? {});
- return vue.createVNode(VDataTableColumn, vue.mergeProps({
- "tag": "th",
- "align": column.align,
- "class": [{
- 'v-data-table__th--sortable': column.sortable && !props.disableSort,
- 'v-data-table__th--sorted': isSorted(column),
- 'v-data-table__th--fixed': column.fixed
- }, ...headerCellClasses.value],
- "style": {
- width: convertToUnit(column.width),
- minWidth: convertToUnit(column.minWidth),
- maxWidth: convertToUnit(column.maxWidth),
- ...getFixedStyles(column, y)
- },
- "colspan": column.colspan,
- "rowspan": column.rowspan,
- "onClick": column.sortable ? () => toggleSort(column) : undefined,
- "fixed": column.fixed,
- "nowrap": column.nowrap,
- "lastFixed": column.lastFixed,
- "noPadding": noPadding
- }, headerProps), {
- default: () => {
- const columnSlotName = `header.${column.key}`;
- const columnSlotProps = {
- column,
- selectAll,
- isSorted,
- toggleSort,
- sortBy: sortBy.value,
- someSelected: someSelected.value,
- allSelected: allSelected.value,
- getSortIcon
- };
- if (slots[columnSlotName]) return slots[columnSlotName](columnSlotProps);
- if (column.key === 'data-table-select') {
- return slots['header.data-table-select']?.(columnSlotProps) ?? (showSelectAll.value && vue.createVNode(VCheckboxBtn, {
- "modelValue": allSelected.value,
- "indeterminate": someSelected.value && !allSelected.value,
- "onUpdate:modelValue": selectAll
- }, null));
- }
- return vue.createVNode("div", {
- "class": "v-data-table-header__content"
- }, [vue.createVNode("span", null, [column.title]), column.sortable && !props.disableSort && vue.createVNode(VIcon, {
- "key": "icon",
- "class": "v-data-table-header__sort-icon",
- "icon": getSortIcon(column)
- }, null), props.multiSort && isSorted(column) && vue.createVNode("div", {
- "key": "badge",
- "class": ['v-data-table-header__sort-badge', ...backgroundColorClasses.value],
- "style": backgroundColorStyles.value
- }, [sortBy.value.findIndex(x => x.key === column.key) + 1])]);
- }
- });
- };
- const VDataTableMobileHeaderCell = () => {
- const headerProps = vue.mergeProps(props.headerProps ?? {} ?? {});
- const displayItems = vue.computed(() => {
- return columns.value.filter(column => column?.sortable && !props.disableSort);
- });
- const appendIcon = vue.computed(() => {
- const showSelectColumn = columns.value.find(column => column.key === 'data-table-select');
- if (showSelectColumn == null) return;
- return allSelected.value ? '$checkboxOn' : someSelected.value ? '$checkboxIndeterminate' : '$checkboxOff';
- });
- return vue.createVNode(VDataTableColumn, vue.mergeProps({
- "tag": "th",
- "class": [...headerCellClasses.value],
- "colspan": headers.value.length + 1
- }, headerProps), {
- default: () => [vue.createVNode("div", {
- "class": "v-data-table-header__content"
- }, [vue.createVNode(VSelect, {
- "chips": true,
- "class": "v-data-table__td-sort-select",
- "clearable": true,
- "density": "default",
- "items": displayItems.value,
- "label": t('$vuetify.dataTable.sortBy'),
- "multiple": props.multiSort,
- "variant": "underlined",
- "onClick:clear": () => sortBy.value = [],
- "appendIcon": appendIcon.value,
- "onClick:append": () => selectAll(!allSelected.value)
- }, {
- ...slots,
- chip: props => vue.createVNode(VChip, {
- "onClick": props.item.raw?.sortable ? () => toggleSort(props.item.raw) : undefined,
- "onMousedown": e => {
- e.preventDefault();
- e.stopPropagation();
- }
- }, {
- default: () => [props.item.title, vue.createVNode(VIcon, {
- "class": ['v-data-table__td-sort-icon', isSorted(props.item.raw) && 'v-data-table__td-sort-icon-active'],
- "icon": getSortIcon(props.item.raw),
- "size": "small"
- }, null)]
- })
- })])]
- });
- };
- useRender(() => {
- return mobile.value ? vue.createVNode("tr", null, [vue.createVNode(VDataTableMobileHeaderCell, null, null)]) : vue.createVNode(vue.Fragment, null, [slots.headers ? slots.headers(slotProps.value) : headers.value.map((row, y) => vue.createVNode("tr", null, [row.map((column, x) => vue.createVNode(VDataTableHeaderCell, {
- "column": column,
- "x": x,
- "y": y
- }, null))])), props.loading && vue.createVNode("tr", {
- "class": "v-data-table-progress"
- }, [vue.createVNode("th", {
- "colspan": columns.value.length
- }, [vue.createVNode(LoaderSlot, {
- "name": "v-data-table-progress",
- "absolute": true,
- "active": true,
- "color": typeof props.loading === 'boolean' ? undefined : props.loading,
- "indeterminate": true
- }, {
- default: slots.loader
- })])])]);
- });
- }
- });
- // Types
- const makeVDataTableGroupHeaderRowProps = propsFactory({
- item: {
- type: Object,
- required: true
- }
- }, 'VDataTableGroupHeaderRow');
- const VDataTableGroupHeaderRow = genericComponent()({
- name: 'VDataTableGroupHeaderRow',
- props: makeVDataTableGroupHeaderRowProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- isGroupOpen,
- toggleGroup,
- extractRows
- } = useGroupBy();
- const {
- isSelected,
- isSomeSelected,
- select
- } = useSelection();
- const {
- columns
- } = useHeaders();
- const rows = vue.computed(() => {
- return extractRows([props.item]);
- });
- return () => vue.createVNode("tr", {
- "class": "v-data-table-group-header-row",
- "style": {
- '--v-data-table-group-header-row-depth': props.item.depth
- }
- }, [columns.value.map(column => {
- if (column.key === 'data-table-group') {
- const icon = isGroupOpen(props.item) ? '$expand' : '$next';
- const onClick = () => toggleGroup(props.item);
- return slots['data-table-group']?.({
- item: props.item,
- count: rows.value.length,
- props: {
- icon,
- onClick
- }
- }) ?? vue.createVNode(VDataTableColumn, {
- "class": "v-data-table-group-header-row__column"
- }, {
- default: () => [vue.createVNode(VBtn, {
- "size": "small",
- "variant": "text",
- "icon": icon,
- "onClick": onClick
- }, null), vue.createVNode("span", null, [props.item.value]), vue.createVNode("span", null, [vue.createTextVNode("("), rows.value.length, vue.createTextVNode(")")])]
- });
- }
- if (column.key === 'data-table-select') {
- const modelValue = isSelected(rows.value);
- const indeterminate = isSomeSelected(rows.value) && !modelValue;
- const selectGroup = v => select(rows.value, v);
- return slots['data-table-select']?.({
- props: {
- modelValue,
- indeterminate,
- 'onUpdate:modelValue': selectGroup
- }
- }) ?? vue.createVNode("td", null, [vue.createVNode(VCheckboxBtn, {
- "modelValue": modelValue,
- "indeterminate": indeterminate,
- "onUpdate:modelValue": selectGroup
- }, null)]);
- }
- return vue.createVNode("td", null, null);
- })]);
- }
- });
- // Types
- const makeVDataTableRowProps = propsFactory({
- index: Number,
- item: Object,
- cellProps: [Object, Function],
- onClick: EventProp(),
- onContextmenu: EventProp(),
- onDblclick: EventProp(),
- ...makeDisplayProps()
- }, 'VDataTableRow');
- const VDataTableRow = genericComponent()({
- name: 'VDataTableRow',
- props: makeVDataTableRowProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- displayClasses,
- mobile
- } = useDisplay(props, 'v-data-table__tr');
- const {
- isSelected,
- toggleSelect,
- someSelected,
- allSelected,
- selectAll
- } = useSelection();
- const {
- isExpanded,
- toggleExpand
- } = useExpanded();
- const {
- toggleSort,
- sortBy,
- isSorted
- } = useSort();
- const {
- columns
- } = useHeaders();
- useRender(() => vue.createVNode("tr", {
- "class": ['v-data-table__tr', {
- 'v-data-table__tr--clickable': !!(props.onClick || props.onContextmenu || props.onDblclick)
- }, displayClasses.value],
- "onClick": props.onClick,
- "onContextmenu": props.onContextmenu,
- "onDblclick": props.onDblclick
- }, [props.item && columns.value.map((column, i) => {
- const item = props.item;
- const slotName = `item.${column.key}`;
- const headerSlotName = `header.${column.key}`;
- const slotProps = {
- index: props.index,
- item: item.raw,
- internalItem: item,
- value: getObjectValueByPath(item.columns, column.key),
- column,
- isSelected,
- toggleSelect,
- isExpanded,
- toggleExpand
- };
- const columnSlotProps = {
- column,
- selectAll,
- isSorted,
- toggleSort,
- sortBy: sortBy.value,
- someSelected: someSelected.value,
- allSelected: allSelected.value,
- getSortIcon: () => ''
- };
- const cellProps = typeof props.cellProps === 'function' ? props.cellProps({
- index: slotProps.index,
- item: slotProps.item,
- internalItem: slotProps.internalItem,
- value: slotProps.value,
- column
- }) : props.cellProps;
- const columnCellProps = typeof column.cellProps === 'function' ? column.cellProps({
- index: slotProps.index,
- item: slotProps.item,
- internalItem: slotProps.internalItem,
- value: slotProps.value
- }) : column.cellProps;
- return vue.createVNode(VDataTableColumn, vue.mergeProps({
- "align": column.align,
- "class": {
- 'v-data-table__td--expanded-row': column.key === 'data-table-expand',
- 'v-data-table__td--select-row': column.key === 'data-table-select'
- },
- "fixed": column.fixed,
- "fixedOffset": column.fixedOffset,
- "lastFixed": column.lastFixed,
- "maxWidth": !mobile.value ? column.maxWidth : undefined,
- "noPadding": column.key === 'data-table-select' || column.key === 'data-table-expand',
- "nowrap": column.nowrap,
- "width": !mobile.value ? column.width : undefined
- }, cellProps, columnCellProps), {
- default: () => {
- if (slots[slotName] && !mobile.value) return slots[slotName]?.(slotProps);
- if (column.key === 'data-table-select') {
- return slots['item.data-table-select']?.(slotProps) ?? vue.createVNode(VCheckboxBtn, {
- "disabled": !item.selectable,
- "modelValue": isSelected([item]),
- "onClick": vue.withModifiers(() => toggleSelect(item), ['stop'])
- }, null);
- }
- if (column.key === 'data-table-expand') {
- return slots['item.data-table-expand']?.(slotProps) ?? vue.createVNode(VBtn, {
- "icon": isExpanded(item) ? '$collapse' : '$expand',
- "size": "small",
- "variant": "text",
- "onClick": vue.withModifiers(() => toggleExpand(item), ['stop'])
- }, null);
- }
- const displayValue = vue.toDisplayString(slotProps.value);
- return !mobile.value ? displayValue : vue.createVNode(vue.Fragment, null, [vue.createVNode("div", {
- "class": "v-data-table__td-title"
- }, [slots[headerSlotName]?.(columnSlotProps) ?? column.title]), vue.createVNode("div", {
- "class": "v-data-table__td-value"
- }, [slots[slotName]?.(slotProps) ?? displayValue])]);
- }
- });
- })]));
- }
- });
- // Types
- const makeVDataTableRowsProps = propsFactory({
- loading: [Boolean, String],
- loadingText: {
- type: String,
- default: '$vuetify.dataIterator.loadingText'
- },
- hideNoData: Boolean,
- items: {
- type: Array,
- default: () => []
- },
- noDataText: {
- type: String,
- default: '$vuetify.noDataText'
- },
- rowProps: [Object, Function],
- cellProps: [Object, Function],
- ...makeDisplayProps()
- }, 'VDataTableRows');
- const VDataTableRows = genericComponent()({
- name: 'VDataTableRows',
- inheritAttrs: false,
- props: makeVDataTableRowsProps(),
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- columns
- } = useHeaders();
- const {
- expandOnClick,
- toggleExpand,
- isExpanded
- } = useExpanded();
- const {
- isSelected,
- toggleSelect
- } = useSelection();
- const {
- toggleGroup,
- isGroupOpen
- } = useGroupBy();
- const {
- t
- } = useLocale();
- const {
- mobile
- } = useDisplay(props);
- useRender(() => {
- if (props.loading && (!props.items.length || slots.loading)) {
- return vue.createVNode("tr", {
- "class": "v-data-table-rows-loading",
- "key": "loading"
- }, [vue.createVNode("td", {
- "colspan": columns.value.length
- }, [slots.loading?.() ?? t(props.loadingText)])]);
- }
- if (!props.loading && !props.items.length && !props.hideNoData) {
- return vue.createVNode("tr", {
- "class": "v-data-table-rows-no-data",
- "key": "no-data"
- }, [vue.createVNode("td", {
- "colspan": columns.value.length
- }, [slots['no-data']?.() ?? t(props.noDataText)])]);
- }
- return vue.createVNode(vue.Fragment, null, [props.items.map((item, index) => {
- if (item.type === 'group') {
- const slotProps = {
- index,
- item,
- columns: columns.value,
- isExpanded,
- toggleExpand,
- isSelected,
- toggleSelect,
- toggleGroup,
- isGroupOpen
- };
- return slots['group-header'] ? slots['group-header'](slotProps) : vue.createVNode(VDataTableGroupHeaderRow, vue.mergeProps({
- "key": `group-header_${item.id}`,
- "item": item
- }, getPrefixedEventHandlers(attrs, ':group-header', () => slotProps)), slots);
- }
- const slotProps = {
- index,
- item: item.raw,
- internalItem: item,
- columns: columns.value,
- isExpanded,
- toggleExpand,
- isSelected,
- toggleSelect
- };
- const itemSlotProps = {
- ...slotProps,
- props: vue.mergeProps({
- key: `item_${item.key ?? item.index}`,
- onClick: expandOnClick.value ? () => {
- toggleExpand(item);
- } : undefined,
- index,
- item,
- cellProps: props.cellProps,
- mobile: mobile.value
- }, getPrefixedEventHandlers(attrs, ':row', () => slotProps), typeof props.rowProps === 'function' ? props.rowProps({
- item: slotProps.item,
- index: slotProps.index,
- internalItem: slotProps.internalItem
- }) : props.rowProps)
- };
- return vue.createVNode(vue.Fragment, {
- "key": itemSlotProps.props.key
- }, [slots.item ? slots.item(itemSlotProps) : vue.createVNode(VDataTableRow, itemSlotProps.props, slots), isExpanded(item) && slots['expanded-row']?.(slotProps)]);
- })]);
- });
- 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,
- emit
- } = _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 {};
- }
- });
- // Utilities
- // Types
- // Composables
- const makeDataTableItemsProps = propsFactory({
- items: {
- type: Array,
- default: () => []
- },
- itemValue: {
- type: [String, Array, Function],
- default: 'id'
- },
- itemSelectable: {
- type: [String, Array, Function],
- default: null
- },
- rowProps: [Object, Function],
- cellProps: [Object, Function],
- returnObject: Boolean
- }, 'DataTable-items');
- function transformItem(props, item, index, columns) {
- const value = props.returnObject ? item : getPropertyFromItem(item, props.itemValue);
- const selectable = getPropertyFromItem(item, props.itemSelectable, true);
- const itemColumns = columns.reduce((obj, column) => {
- if (column.key != null) obj[column.key] = getPropertyFromItem(item, column.value);
- return obj;
- }, {});
- return {
- type: 'item',
- key: props.returnObject ? getPropertyFromItem(item, props.itemValue) : value,
- index,
- value,
- selectable,
- columns: itemColumns,
- raw: item
- };
- }
- function transformItems(props, items, columns) {
- return items.map((item, index) => transformItem(props, item, index, columns));
- }
- function useDataTableItems(props, columns) {
- const items = vue.computed(() => transformItems(props, props.items, columns.value));
- return {
- items
- };
- }
- // Types
- const makeDataTableProps = propsFactory({
- ...makeVDataTableRowsProps(),
- hideDefaultBody: Boolean,
- hideDefaultFooter: Boolean,
- hideDefaultHeader: Boolean,
- width: [String, Number],
- search: String,
- ...makeDataTableExpandProps(),
- ...makeDataTableGroupProps(),
- ...makeDataTableHeaderProps(),
- ...makeDataTableItemsProps(),
- ...makeDataTableSelectProps(),
- ...makeDataTableSortProps(),
- ...makeVDataTableHeadersProps(),
- ...makeVTableProps()
- }, 'DataTable');
- const makeVDataTableProps = propsFactory({
- ...makeDataTablePaginateProps(),
- ...makeDataTableProps(),
- ...makeFilterProps(),
- ...makeVDataTableFooterProps()
- }, 'VDataTable');
- const VDataTable = genericComponent()({
- name: 'VDataTable',
- props: makeVDataTableProps(),
- emits: {
- 'update:modelValue': value => true,
- 'update:page': value => true,
- 'update:itemsPerPage': value => true,
- 'update:sortBy': value => true,
- 'update:options': value => true,
- 'update:groupBy': value => true,
- 'update:expanded': value => true,
- 'update:currentItems': value => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- groupBy
- } = createGroupBy(props);
- const {
- sortBy,
- multiSort,
- mustSort
- } = createSort(props);
- const {
- page,
- itemsPerPage
- } = createPagination(props);
- const {
- disableSort
- } = vue.toRefs(props);
- const {
- columns,
- headers,
- sortFunctions,
- sortRawFunctions,
- filterFunctions
- } = createHeaders(props, {
- groupBy,
- showSelect: vue.toRef(props, 'showSelect'),
- showExpand: vue.toRef(props, 'showExpand')
- });
- const {
- items
- } = useDataTableItems(props, columns);
- const search = vue.toRef(props, 'search');
- const {
- filteredItems
- } = useFilter(props, items, search, {
- transform: item => item.columns,
- customKeyFilter: filterFunctions
- });
- const {
- toggleSort
- } = provideSort({
- sortBy,
- multiSort,
- mustSort,
- page
- });
- const {
- sortByWithGroups,
- opened,
- extractRows,
- isGroupOpen,
- toggleGroup
- } = provideGroupBy({
- groupBy,
- sortBy,
- disableSort
- });
- const {
- sortedItems
- } = useSortedItems(props, filteredItems, sortByWithGroups, {
- transform: item => ({
- ...item.raw,
- ...item.columns
- }),
- sortFunctions,
- sortRawFunctions
- });
- const {
- flatItems
- } = useGroupedItems(sortedItems, groupBy, opened);
- const itemsLength = vue.computed(() => flatItems.value.length);
- const {
- startIndex,
- stopIndex,
- pageCount,
- setItemsPerPage
- } = providePagination({
- page,
- itemsPerPage,
- itemsLength
- });
- const {
- paginatedItems
- } = usePaginatedItems({
- items: flatItems,
- startIndex,
- stopIndex,
- itemsPerPage
- });
- const paginatedItemsWithoutGroups = vue.computed(() => extractRows(paginatedItems.value));
- const {
- isSelected,
- select,
- selectAll,
- toggleSelect,
- someSelected,
- allSelected
- } = provideSelection(props, {
- allItems: items,
- currentPage: paginatedItemsWithoutGroups
- });
- const {
- isExpanded,
- toggleExpand
- } = provideExpanded(props);
- useOptions({
- page,
- itemsPerPage,
- sortBy,
- groupBy,
- search
- });
- provideDefaults({
- VDataTableRows: {
- hideNoData: vue.toRef(props, 'hideNoData'),
- noDataText: vue.toRef(props, 'noDataText'),
- loading: vue.toRef(props, 'loading'),
- loadingText: vue.toRef(props, 'loadingText')
- }
- });
- const slotProps = vue.computed(() => ({
- page: page.value,
- itemsPerPage: itemsPerPage.value,
- sortBy: sortBy.value,
- pageCount: pageCount.value,
- toggleSort,
- setItemsPerPage,
- someSelected: someSelected.value,
- allSelected: allSelected.value,
- isSelected,
- select,
- selectAll,
- toggleSelect,
- isExpanded,
- toggleExpand,
- isGroupOpen,
- toggleGroup,
- items: paginatedItemsWithoutGroups.value.map(item => item.raw),
- internalItems: paginatedItemsWithoutGroups.value,
- groupedItems: paginatedItems.value,
- columns: columns.value,
- headers: headers.value
- }));
- useRender(() => {
- const dataTableFooterProps = VDataTableFooter.filterProps(props);
- const dataTableHeadersProps = VDataTableHeaders.filterProps(props);
- const dataTableRowsProps = VDataTableRows.filterProps(props);
- const tableProps = VTable.filterProps(props);
- return vue.createVNode(VTable, vue.mergeProps({
- "class": ['v-data-table', {
- 'v-data-table--show-select': props.showSelect,
- 'v-data-table--loading': props.loading
- }, props.class],
- "style": props.style
- }, tableProps), {
- top: () => slots.top?.(slotProps.value),
- default: () => slots.default ? slots.default(slotProps.value) : vue.createVNode(vue.Fragment, null, [slots.colgroup?.(slotProps.value), !props.hideDefaultHeader && vue.createVNode("thead", {
- "key": "thead"
- }, [vue.createVNode(VDataTableHeaders, dataTableHeadersProps, slots)]), slots.thead?.(slotProps.value), !props.hideDefaultBody && vue.createVNode("tbody", null, [slots['body.prepend']?.(slotProps.value), slots.body ? slots.body(slotProps.value) : vue.createVNode(VDataTableRows, vue.mergeProps(attrs, dataTableRowsProps, {
- "items": paginatedItems.value
- }), slots), slots['body.append']?.(slotProps.value)]), slots.tbody?.(slotProps.value), slots.tfoot?.(slotProps.value)]),
- bottom: () => slots.bottom ? slots.bottom(slotProps.value) : !props.hideDefaultFooter && vue.createVNode(vue.Fragment, null, [vue.createVNode(VDivider, null, null), vue.createVNode(VDataTableFooter, dataTableFooterProps, {
- prepend: slots['footer.prepend']
- })])
- });
- });
- return {};
- }
- });
- // Types
- const makeVDataTableVirtualProps = propsFactory({
- ...makeDataTableProps(),
- ...makeDataTableGroupProps(),
- ...makeVirtualProps(),
- ...makeFilterProps()
- }, 'VDataTableVirtual');
- const VDataTableVirtual = genericComponent()({
- name: 'VDataTableVirtual',
- props: makeVDataTableVirtualProps(),
- emits: {
- 'update:modelValue': value => true,
- 'update:sortBy': value => true,
- 'update:options': value => true,
- 'update:groupBy': value => true,
- 'update:expanded': value => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- groupBy
- } = createGroupBy(props);
- const {
- sortBy,
- multiSort,
- mustSort
- } = createSort(props);
- const {
- disableSort
- } = vue.toRefs(props);
- const {
- columns,
- headers,
- filterFunctions,
- sortFunctions,
- sortRawFunctions
- } = createHeaders(props, {
- groupBy,
- showSelect: vue.toRef(props, 'showSelect'),
- showExpand: vue.toRef(props, 'showExpand')
- });
- const {
- items
- } = useDataTableItems(props, columns);
- const search = vue.toRef(props, 'search');
- const {
- filteredItems
- } = useFilter(props, items, search, {
- transform: item => item.columns,
- customKeyFilter: filterFunctions
- });
- const {
- toggleSort
- } = provideSort({
- sortBy,
- multiSort,
- mustSort
- });
- const {
- sortByWithGroups,
- opened,
- extractRows,
- isGroupOpen,
- toggleGroup
- } = provideGroupBy({
- groupBy,
- sortBy,
- disableSort
- });
- const {
- sortedItems
- } = useSortedItems(props, filteredItems, sortByWithGroups, {
- transform: item => ({
- ...item.raw,
- ...item.columns
- }),
- sortFunctions,
- sortRawFunctions
- });
- const {
- flatItems
- } = useGroupedItems(sortedItems, groupBy, opened);
- const allItems = vue.computed(() => extractRows(flatItems.value));
- const {
- isSelected,
- select,
- selectAll,
- toggleSelect,
- someSelected,
- allSelected
- } = provideSelection(props, {
- allItems,
- currentPage: allItems
- });
- const {
- isExpanded,
- toggleExpand
- } = provideExpanded(props);
- const {
- containerRef,
- markerRef,
- paddingTop,
- paddingBottom,
- computedItems,
- handleItemResize,
- handleScroll,
- handleScrollend
- } = useVirtual(props, flatItems);
- const displayItems = vue.computed(() => computedItems.value.map(item => item.raw));
- useOptions({
- sortBy,
- page: vue.shallowRef(1),
- itemsPerPage: vue.shallowRef(-1),
- groupBy,
- search
- });
- provideDefaults({
- VDataTableRows: {
- hideNoData: vue.toRef(props, 'hideNoData'),
- noDataText: vue.toRef(props, 'noDataText'),
- loading: vue.toRef(props, 'loading'),
- loadingText: vue.toRef(props, 'loadingText')
- }
- });
- const slotProps = vue.computed(() => ({
- sortBy: sortBy.value,
- toggleSort,
- someSelected: someSelected.value,
- allSelected: allSelected.value,
- isSelected,
- select,
- selectAll,
- toggleSelect,
- isExpanded,
- toggleExpand,
- isGroupOpen,
- toggleGroup,
- items: allItems.value.map(item => item.raw),
- internalItems: allItems.value,
- groupedItems: flatItems.value,
- columns: columns.value,
- headers: headers.value
- }));
- useRender(() => {
- const dataTableHeadersProps = VDataTableHeaders.filterProps(props);
- const dataTableRowsProps = VDataTableRows.filterProps(props);
- const tableProps = VTable.filterProps(props);
- return vue.createVNode(VTable, vue.mergeProps({
- "class": ['v-data-table', {
- 'v-data-table--loading': props.loading
- }, props.class],
- "style": props.style
- }, tableProps), {
- top: () => slots.top?.(slotProps.value),
- wrapper: () => vue.createVNode("div", {
- "ref": containerRef,
- "onScrollPassive": handleScroll,
- "onScrollend": handleScrollend,
- "class": "v-table__wrapper",
- "style": {
- height: convertToUnit(props.height)
- }
- }, [vue.createVNode("table", null, [slots.colgroup?.(slotProps.value), !props.hideDefaultHeader && vue.createVNode("thead", {
- "key": "thead"
- }, [vue.createVNode(VDataTableHeaders, vue.mergeProps(dataTableHeadersProps, {
- "sticky": props.fixedHeader
- }), slots)]), !props.hideDefaultBody && vue.createVNode("tbody", null, [vue.createVNode("tr", {
- "ref": markerRef,
- "style": {
- height: convertToUnit(paddingTop.value),
- border: 0
- }
- }, [vue.createVNode("td", {
- "colspan": columns.value.length,
- "style": {
- height: 0,
- border: 0
- }
- }, null)]), slots['body.prepend']?.(slotProps.value), vue.createVNode(VDataTableRows, vue.mergeProps(attrs, dataTableRowsProps, {
- "items": displayItems.value
- }), {
- ...slots,
- item: itemSlotProps => vue.createVNode(VVirtualScrollItem, {
- "key": itemSlotProps.internalItem.index,
- "renderless": true,
- "onUpdate:height": height => handleItemResize(itemSlotProps.internalItem.index, height)
- }, {
- default: _ref2 => {
- let {
- itemRef
- } = _ref2;
- return slots.item?.({
- ...itemSlotProps,
- itemRef
- }) ?? vue.createVNode(VDataTableRow, vue.mergeProps(itemSlotProps.props, {
- "ref": itemRef,
- "key": itemSlotProps.internalItem.index,
- "index": itemSlotProps.internalItem.index
- }), slots);
- }
- })
- }), slots['body.append']?.(slotProps.value), vue.createVNode("tr", {
- "style": {
- height: convertToUnit(paddingBottom.value),
- border: 0
- }
- }, [vue.createVNode("td", {
- "colspan": columns.value.length,
- "style": {
- height: 0,
- border: 0
- }
- }, null)])])])]),
- bottom: () => slots.bottom?.(slotProps.value)
- });
- });
- }
- });
- // Types
- const makeVDataTableServerProps = propsFactory({
- itemsLength: {
- type: [Number, String],
- required: true
- },
- ...makeDataTablePaginateProps(),
- ...makeDataTableProps(),
- ...makeVDataTableFooterProps()
- }, 'VDataTableServer');
- const VDataTableServer = genericComponent()({
- name: 'VDataTableServer',
- props: makeVDataTableServerProps(),
- emits: {
- 'update:modelValue': value => true,
- 'update:page': page => true,
- 'update:itemsPerPage': page => true,
- 'update:sortBy': sortBy => true,
- 'update:options': options => true,
- 'update:expanded': options => true,
- 'update:groupBy': value => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- groupBy
- } = createGroupBy(props);
- const {
- sortBy,
- multiSort,
- mustSort
- } = createSort(props);
- const {
- page,
- itemsPerPage
- } = createPagination(props);
- const {
- disableSort
- } = vue.toRefs(props);
- const itemsLength = vue.computed(() => parseInt(props.itemsLength, 10));
- const {
- columns,
- headers
- } = createHeaders(props, {
- groupBy,
- showSelect: vue.toRef(props, 'showSelect'),
- showExpand: vue.toRef(props, 'showExpand')
- });
- const {
- items
- } = useDataTableItems(props, columns);
- const {
- toggleSort
- } = provideSort({
- sortBy,
- multiSort,
- mustSort,
- page
- });
- const {
- opened,
- isGroupOpen,
- toggleGroup,
- extractRows
- } = provideGroupBy({
- groupBy,
- sortBy,
- disableSort
- });
- const {
- pageCount,
- setItemsPerPage
- } = providePagination({
- page,
- itemsPerPage,
- itemsLength
- });
- const {
- flatItems
- } = useGroupedItems(items, groupBy, opened);
- const {
- isSelected,
- select,
- selectAll,
- toggleSelect,
- someSelected,
- allSelected
- } = provideSelection(props, {
- allItems: items,
- currentPage: items
- });
- const {
- isExpanded,
- toggleExpand
- } = provideExpanded(props);
- const itemsWithoutGroups = vue.computed(() => extractRows(items.value));
- useOptions({
- page,
- itemsPerPage,
- sortBy,
- groupBy,
- search: vue.toRef(props, 'search')
- });
- vue.provide('v-data-table', {
- toggleSort,
- sortBy
- });
- provideDefaults({
- VDataTableRows: {
- hideNoData: vue.toRef(props, 'hideNoData'),
- noDataText: vue.toRef(props, 'noDataText'),
- loading: vue.toRef(props, 'loading'),
- loadingText: vue.toRef(props, 'loadingText')
- }
- });
- const slotProps = vue.computed(() => ({
- page: page.value,
- itemsPerPage: itemsPerPage.value,
- sortBy: sortBy.value,
- pageCount: pageCount.value,
- toggleSort,
- setItemsPerPage,
- someSelected: someSelected.value,
- allSelected: allSelected.value,
- isSelected,
- select,
- selectAll,
- toggleSelect,
- isExpanded,
- toggleExpand,
- isGroupOpen,
- toggleGroup,
- items: itemsWithoutGroups.value.map(item => item.raw),
- internalItems: itemsWithoutGroups.value,
- groupedItems: flatItems.value,
- columns: columns.value,
- headers: headers.value
- }));
- useRender(() => {
- const dataTableFooterProps = VDataTableFooter.filterProps(props);
- const dataTableHeadersProps = VDataTableHeaders.filterProps(props);
- const dataTableRowsProps = VDataTableRows.filterProps(props);
- const tableProps = VTable.filterProps(props);
- return vue.createVNode(VTable, vue.mergeProps({
- "class": ['v-data-table', {
- 'v-data-table--loading': props.loading
- }, props.class],
- "style": props.style
- }, tableProps), {
- top: () => slots.top?.(slotProps.value),
- default: () => slots.default ? slots.default(slotProps.value) : vue.createVNode(vue.Fragment, null, [slots.colgroup?.(slotProps.value), !props.hideDefaultHeader && vue.createVNode("thead", {
- "key": "thead",
- "class": "v-data-table__thead",
- "role": "rowgroup"
- }, [vue.createVNode(VDataTableHeaders, vue.mergeProps(dataTableHeadersProps, {
- "sticky": props.fixedHeader
- }), slots)]), slots.thead?.(slotProps.value), !props.hideDefaultBody && vue.createVNode("tbody", {
- "class": "v-data-table__tbody",
- "role": "rowgroup"
- }, [slots['body.prepend']?.(slotProps.value), slots.body ? slots.body(slotProps.value) : vue.createVNode(VDataTableRows, vue.mergeProps(attrs, dataTableRowsProps, {
- "items": flatItems.value
- }), slots), slots['body.append']?.(slotProps.value)]), slots.tbody?.(slotProps.value), slots.tfoot?.(slotProps.value)]),
- bottom: () => slots.bottom ? slots.bottom(slotProps.value) : !props.hideDefaultFooter && vue.createVNode(vue.Fragment, null, [vue.createVNode(VDivider, null, null), vue.createVNode(VDataTableFooter, dataTableFooterProps, {
- prepend: slots['footer.prepend']
- })])
- });
- });
- }
- });
- const makeVContainerProps = propsFactory({
- fluid: {
- type: Boolean,
- default: false
- },
- ...makeComponentProps(),
- ...makeDimensionProps(),
- ...makeTagProps()
- }, 'VContainer');
- const VContainer = genericComponent()({
- name: 'VContainer',
- props: makeVContainerProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- rtlClasses
- } = useRtl();
- const {
- dimensionStyles
- } = useDimension(props);
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-container', {
- 'v-container--fluid': props.fluid
- }, rtlClasses.value, props.class],
- "style": [dimensionStyles.value, 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?.());
- }
- });
- // Styles
- const VSpacer = createSimpleFunctional('v-spacer', 'div', 'VSpacer');
- // Types
- const makeVDatePickerControlsProps = propsFactory({
- active: {
- type: [String, Array],
- default: undefined
- },
- disabled: {
- type: [Boolean, String, Array],
- default: false
- },
- nextIcon: {
- type: IconValue,
- default: '$next'
- },
- prevIcon: {
- type: IconValue,
- default: '$prev'
- },
- modeIcon: {
- type: IconValue,
- default: '$subgroup'
- },
- text: String,
- viewMode: {
- type: String,
- default: 'month'
- }
- }, 'VDatePickerControls');
- const VDatePickerControls = genericComponent()({
- name: 'VDatePickerControls',
- props: makeVDatePickerControlsProps(),
- emits: {
- 'click:year': () => true,
- 'click:month': () => true,
- 'click:prev': () => true,
- 'click:next': () => true,
- 'click:text': () => true
- },
- setup(props, _ref) {
- let {
- emit
- } = _ref;
- const disableMonth = vue.computed(() => {
- return Array.isArray(props.disabled) ? props.disabled.includes('text') : !!props.disabled;
- });
- const disableYear = vue.computed(() => {
- return Array.isArray(props.disabled) ? props.disabled.includes('mode') : !!props.disabled;
- });
- const disablePrev = vue.computed(() => {
- return Array.isArray(props.disabled) ? props.disabled.includes('prev') : !!props.disabled;
- });
- const disableNext = vue.computed(() => {
- return Array.isArray(props.disabled) ? props.disabled.includes('next') : !!props.disabled;
- });
- function onClickPrev() {
- emit('click:prev');
- }
- function onClickNext() {
- emit('click:next');
- }
- function onClickYear() {
- emit('click:year');
- }
- function onClickMonth() {
- emit('click:month');
- }
- useRender(() => {
- // TODO: add slot support and scope defaults
- return vue.createVNode("div", {
- "class": ['v-date-picker-controls']
- }, [vue.createVNode(VBtn, {
- "class": "v-date-picker-controls__month-btn",
- "disabled": disableMonth.value,
- "text": props.text,
- "variant": "text",
- "rounded": true,
- "onClick": onClickMonth
- }, null), vue.createVNode(VBtn, {
- "key": "mode-btn",
- "class": "v-date-picker-controls__mode-btn",
- "disabled": disableYear.value,
- "density": "comfortable",
- "icon": props.modeIcon,
- "variant": "text",
- "onClick": onClickYear
- }, null), vue.createVNode(VSpacer, {
- "key": "mode-spacer"
- }, null), vue.createVNode("div", {
- "key": "month-buttons",
- "class": "v-date-picker-controls__month"
- }, [vue.createVNode(VBtn, {
- "disabled": disablePrev.value,
- "icon": props.prevIcon,
- "variant": "text",
- "onClick": onClickPrev
- }, null), vue.createVNode(VBtn, {
- "disabled": disableNext.value,
- "icon": props.nextIcon,
- "variant": "text",
- "onClick": onClickNext
- }, null)])]);
- });
- return {};
- }
- });
- // Types
- const makeVDatePickerHeaderProps = propsFactory({
- appendIcon: IconValue,
- color: String,
- header: String,
- transition: String,
- onClick: EventProp()
- }, 'VDatePickerHeader');
- const VDatePickerHeader = genericComponent()({
- name: 'VDatePickerHeader',
- props: makeVDatePickerHeaderProps(),
- emits: {
- click: () => true,
- 'click:append': () => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(props, 'color');
- function onClick() {
- emit('click');
- }
- function onClickAppend() {
- emit('click:append');
- }
- useRender(() => {
- const hasContent = !!(slots.default || props.header);
- const hasAppend = !!(slots.append || props.appendIcon);
- return vue.createVNode("div", {
- "class": ['v-date-picker-header', {
- 'v-date-picker-header--clickable': !!props.onClick
- }, backgroundColorClasses.value],
- "style": backgroundColorStyles.value,
- "onClick": onClick
- }, [slots.prepend && vue.createVNode("div", {
- "key": "prepend",
- "class": "v-date-picker-header__prepend"
- }, [slots.prepend()]), hasContent && vue.createVNode(MaybeTransition, {
- "key": "content",
- "name": props.transition
- }, {
- default: () => [vue.createVNode("div", {
- "key": props.header,
- "class": "v-date-picker-header__content"
- }, [slots.default?.() ?? props.header])]
- }), hasAppend && vue.createVNode("div", {
- "class": "v-date-picker-header__append"
- }, [!slots.append ? vue.createVNode(VBtn, {
- "key": "append-btn",
- "icon": props.appendIcon,
- "variant": "text",
- "onClick": onClickAppend
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "append-defaults",
- "disabled": !props.appendIcon,
- "defaults": {
- VBtn: {
- icon: props.appendIcon,
- variant: 'text'
- }
- }
- }, {
- default: () => [slots.append?.()]
- })])]);
- });
- return {};
- }
- });
- // Composables
- // Types
- // Types
- // Composables
- const makeCalendarProps = propsFactory({
- allowedDates: [Array, Function],
- disabled: Boolean,
- displayValue: null,
- modelValue: Array,
- month: [Number, String],
- max: null,
- min: null,
- showAdjacentMonths: Boolean,
- year: [Number, String],
- weekdays: {
- type: Array,
- default: () => [0, 1, 2, 3, 4, 5, 6]
- },
- weeksInMonth: {
- type: String,
- default: 'dynamic'
- },
- firstDayOfWeek: [Number, String]
- }, 'calendar');
- function useCalendar(props) {
- const adapter = useDate();
- const model = useProxiedModel(props, 'modelValue', [], v => wrapInArray(v));
- const displayValue = vue.computed(() => {
- if (props.displayValue) return adapter.date(props.displayValue);
- if (model.value.length > 0) return adapter.date(model.value[0]);
- if (props.min) return adapter.date(props.min);
- if (Array.isArray(props.allowedDates)) return adapter.date(props.allowedDates[0]);
- return adapter.date();
- });
- const year = useProxiedModel(props, 'year', undefined, v => {
- const value = v != null ? Number(v) : adapter.getYear(displayValue.value);
- return adapter.startOfYear(adapter.setYear(adapter.date(), value));
- }, v => adapter.getYear(v));
- const month = useProxiedModel(props, 'month', undefined, v => {
- const value = v != null ? Number(v) : adapter.getMonth(displayValue.value);
- const date = adapter.setYear(adapter.startOfMonth(adapter.date()), adapter.getYear(year.value));
- return adapter.setMonth(date, value);
- }, v => adapter.getMonth(v));
- const weekDays = vue.computed(() => {
- const firstDayOfWeek = Number(props.firstDayOfWeek ?? 0);
- return props.weekdays.map(day => (day + firstDayOfWeek) % 7);
- });
- const weeksInMonth = vue.computed(() => {
- const weeks = adapter.getWeekArray(month.value, props.firstDayOfWeek);
- const days = weeks.flat();
- // Make sure there's always 6 weeks in month (6 * 7 days)
- // if weeksInMonth is 'static'
- const daysInMonth = 6 * 7;
- if (props.weeksInMonth === 'static' && days.length < daysInMonth) {
- const lastDay = days[days.length - 1];
- let week = [];
- for (let day = 1; day <= daysInMonth - days.length; day++) {
- week.push(adapter.addDays(lastDay, day));
- if (day % 7 === 0) {
- weeks.push(week);
- week = [];
- }
- }
- }
- return weeks;
- });
- function genDays(days, today) {
- return days.filter(date => {
- return weekDays.value.includes(adapter.toJsDate(date).getDay());
- }).map((date, index) => {
- const isoDate = adapter.toISO(date);
- const isAdjacent = !adapter.isSameMonth(date, month.value);
- const isStart = adapter.isSameDay(date, adapter.startOfMonth(month.value));
- const isEnd = adapter.isSameDay(date, adapter.endOfMonth(month.value));
- const isSame = adapter.isSameDay(date, month.value);
- return {
- date,
- isoDate,
- formatted: adapter.format(date, 'keyboardDate'),
- year: adapter.getYear(date),
- month: adapter.getMonth(date),
- isDisabled: isDisabled(date),
- isWeekStart: index % 7 === 0,
- isWeekEnd: index % 7 === 6,
- isToday: adapter.isSameDay(date, today),
- isAdjacent,
- isHidden: isAdjacent && !props.showAdjacentMonths,
- isStart,
- isSelected: model.value.some(value => adapter.isSameDay(date, value)),
- isEnd,
- isSame,
- localized: adapter.format(date, 'dayOfMonth')
- };
- });
- }
- const daysInWeek = vue.computed(() => {
- const lastDay = adapter.startOfWeek(displayValue.value, props.firstDayOfWeek);
- const week = [];
- for (let day = 0; day <= 6; day++) {
- week.push(adapter.addDays(lastDay, day));
- }
- const today = adapter.date();
- return genDays(week, today);
- });
- const daysInMonth = vue.computed(() => {
- const days = weeksInMonth.value.flat();
- const today = adapter.date();
- return genDays(days, today);
- });
- const weekNumbers = vue.computed(() => {
- return weeksInMonth.value.map(week => {
- return week.length ? getWeek(adapter, week[0]) : null;
- });
- });
- function isDisabled(value) {
- if (props.disabled) return true;
- const date = adapter.date(value);
- if (props.min && adapter.isAfter(adapter.date(props.min), date)) return true;
- if (props.max && adapter.isAfter(date, adapter.date(props.max))) return true;
- if (Array.isArray(props.allowedDates) && props.allowedDates.length > 0) {
- return !props.allowedDates.some(d => adapter.isSameDay(adapter.date(d), date));
- }
- if (typeof props.allowedDates === 'function') {
- return !props.allowedDates(date);
- }
- return false;
- }
- return {
- displayValue,
- daysInMonth,
- daysInWeek,
- genDays,
- model,
- weeksInMonth,
- weekDays,
- weekNumbers
- };
- }
- // Types
- const makeVDatePickerMonthProps = propsFactory({
- color: String,
- hideWeekdays: Boolean,
- multiple: [Boolean, Number, String],
- showWeek: Boolean,
- transition: {
- type: String,
- default: 'picker-transition'
- },
- reverseTransition: {
- type: String,
- default: 'picker-reverse-transition'
- },
- ...makeCalendarProps()
- }, 'VDatePickerMonth');
- const VDatePickerMonth = genericComponent()({
- name: 'VDatePickerMonth',
- props: makeVDatePickerMonthProps(),
- emits: {
- 'update:modelValue': date => true,
- 'update:month': date => true,
- 'update:year': date => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const daysRef = vue.ref();
- const {
- daysInMonth,
- model,
- weekNumbers
- } = useCalendar(props);
- const adapter = useDate();
- const rangeStart = vue.shallowRef();
- const rangeStop = vue.shallowRef();
- const isReverse = vue.shallowRef(false);
- const transition = vue.computed(() => {
- return !isReverse.value ? props.transition : props.reverseTransition;
- });
- if (props.multiple === 'range' && model.value.length > 0) {
- rangeStart.value = model.value[0];
- if (model.value.length > 1) {
- rangeStop.value = model.value[model.value.length - 1];
- }
- }
- const atMax = vue.computed(() => {
- const max = ['number', 'string'].includes(typeof props.multiple) ? Number(props.multiple) : Infinity;
- return model.value.length >= max;
- });
- vue.watch(daysInMonth, (val, oldVal) => {
- if (!oldVal) return;
- isReverse.value = adapter.isBefore(val[0].date, oldVal[0].date);
- });
- function onRangeClick(value) {
- const _value = adapter.startOfDay(value);
- if (model.value.length === 0) {
- rangeStart.value = undefined;
- } else if (model.value.length === 1) {
- rangeStart.value = model.value[0];
- rangeStop.value = undefined;
- }
- if (!rangeStart.value) {
- rangeStart.value = _value;
- model.value = [rangeStart.value];
- } else if (!rangeStop.value) {
- if (adapter.isSameDay(_value, rangeStart.value)) {
- rangeStart.value = undefined;
- model.value = [];
- return;
- } else if (adapter.isBefore(_value, rangeStart.value)) {
- rangeStop.value = adapter.endOfDay(rangeStart.value);
- rangeStart.value = _value;
- } else {
- rangeStop.value = adapter.endOfDay(_value);
- }
- const diff = adapter.getDiff(rangeStop.value, rangeStart.value, 'days');
- const datesInRange = [rangeStart.value];
- for (let i = 1; i < diff; i++) {
- const nextDate = adapter.addDays(rangeStart.value, i);
- datesInRange.push(nextDate);
- }
- datesInRange.push(rangeStop.value);
- model.value = datesInRange;
- } else {
- rangeStart.value = value;
- rangeStop.value = undefined;
- model.value = [rangeStart.value];
- }
- }
- function onMultipleClick(value) {
- const index = model.value.findIndex(selection => adapter.isSameDay(selection, value));
- if (index === -1) {
- model.value = [...model.value, value];
- } else {
- const value = [...model.value];
- value.splice(index, 1);
- model.value = value;
- }
- }
- function onClick(value) {
- if (props.multiple === 'range') {
- onRangeClick(value);
- } else if (props.multiple) {
- onMultipleClick(value);
- } else {
- model.value = [value];
- }
- }
- return () => vue.createVNode("div", {
- "class": "v-date-picker-month"
- }, [props.showWeek && vue.createVNode("div", {
- "key": "weeks",
- "class": "v-date-picker-month__weeks"
- }, [!props.hideWeekdays && vue.createVNode("div", {
- "key": "hide-week-days",
- "class": "v-date-picker-month__day"
- }, [vue.createTextVNode("\xA0")]), weekNumbers.value.map(week => vue.createVNode("div", {
- "class": ['v-date-picker-month__day', 'v-date-picker-month__day--adjacent']
- }, [week]))]), vue.createVNode(MaybeTransition, {
- "name": transition.value
- }, {
- default: () => [vue.createVNode("div", {
- "ref": daysRef,
- "key": daysInMonth.value[0].date?.toString(),
- "class": "v-date-picker-month__days"
- }, [!props.hideWeekdays && adapter.getWeekdays(props.firstDayOfWeek).map(weekDay => vue.createVNode("div", {
- "class": ['v-date-picker-month__day', 'v-date-picker-month__weekday']
- }, [weekDay])), daysInMonth.value.map((item, i) => {
- const slotProps = {
- props: {
- onClick: () => onClick(item.date)
- },
- item,
- i
- };
- if (atMax.value && !item.isSelected) {
- item.isDisabled = true;
- }
- return vue.createVNode("div", {
- "class": ['v-date-picker-month__day', {
- 'v-date-picker-month__day--adjacent': item.isAdjacent,
- 'v-date-picker-month__day--hide-adjacent': item.isHidden,
- 'v-date-picker-month__day--selected': item.isSelected,
- 'v-date-picker-month__day--week-end': item.isWeekEnd,
- 'v-date-picker-month__day--week-start': item.isWeekStart
- }],
- "data-v-date": !item.isDisabled ? item.isoDate : undefined
- }, [(props.showAdjacentMonths || !item.isAdjacent) && vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- class: 'v-date-picker-month__day-btn',
- color: (item.isSelected || item.isToday) && !item.isDisabled ? props.color : undefined,
- disabled: item.isDisabled,
- icon: true,
- ripple: false,
- text: item.localized,
- variant: item.isDisabled ? item.isToday ? 'outlined' : 'text' : item.isToday && !item.isSelected ? 'outlined' : 'flat',
- onClick: () => onClick(item.date)
- }
- }
- }, {
- default: () => [slots.day?.(slotProps) ?? vue.createVNode(VBtn, slotProps.props, null)]
- })]);
- })])]
- })]);
- }
- });
- // Types
- const makeVDatePickerMonthsProps = propsFactory({
- color: String,
- height: [String, Number],
- min: null,
- max: null,
- modelValue: Number,
- year: Number
- }, 'VDatePickerMonths');
- const VDatePickerMonths = genericComponent()({
- name: 'VDatePickerMonths',
- props: makeVDatePickerMonthsProps(),
- emits: {
- 'update:modelValue': date => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const adapter = useDate();
- const model = useProxiedModel(props, 'modelValue');
- const months = vue.computed(() => {
- let date = adapter.startOfYear(adapter.date());
- if (props.year) {
- date = adapter.setYear(date, props.year);
- }
- return createRange(12).map(i => {
- const text = adapter.format(date, 'monthShort');
- const isDisabled = !!(props.min && adapter.isAfter(adapter.startOfMonth(adapter.date(props.min)), date) || props.max && adapter.isAfter(date, adapter.startOfMonth(adapter.date(props.max))));
- date = adapter.getNextMonth(date);
- return {
- isDisabled,
- text,
- value: i
- };
- });
- });
- vue.watchEffect(() => {
- model.value = model.value ?? adapter.getMonth(adapter.date());
- });
- useRender(() => vue.createVNode("div", {
- "class": "v-date-picker-months",
- "style": {
- height: convertToUnit(props.height)
- }
- }, [vue.createVNode("div", {
- "class": "v-date-picker-months__content"
- }, [months.value.map((month, i) => {
- const btnProps = {
- active: model.value === i,
- color: model.value === i ? props.color : undefined,
- disabled: month.isDisabled,
- rounded: true,
- text: month.text,
- variant: model.value === month.value ? 'flat' : 'text',
- onClick: () => onClick(i)
- };
- function onClick(i) {
- if (model.value === i) {
- emit('update:modelValue', model.value);
- return;
- }
- model.value = i;
- }
- return slots.month?.({
- month,
- i,
- props: btnProps
- }) ?? vue.createVNode(VBtn, vue.mergeProps({
- "key": "month"
- }, btnProps), null);
- })])]));
- return {};
- }
- });
- // Types
- // Types
- const makeVDatePickerYearsProps = propsFactory({
- color: String,
- height: [String, Number],
- min: null,
- max: null,
- modelValue: Number
- }, 'VDatePickerYears');
- const VDatePickerYears = genericComponent()({
- name: 'VDatePickerYears',
- props: makeVDatePickerYearsProps(),
- emits: {
- 'update:modelValue': year => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const adapter = useDate();
- const model = useProxiedModel(props, 'modelValue');
- const years = vue.computed(() => {
- const year = adapter.getYear(adapter.date());
- let min = year - 100;
- let max = year + 52;
- if (props.min) {
- min = adapter.getYear(adapter.date(props.min));
- }
- if (props.max) {
- max = adapter.getYear(adapter.date(props.max));
- }
- let date = adapter.startOfYear(adapter.date());
- date = adapter.setYear(date, min);
- return createRange(max - min + 1, min).map(i => {
- const text = adapter.format(date, 'year');
- date = adapter.setYear(date, adapter.getYear(date) + 1);
- return {
- text,
- value: i
- };
- });
- });
- vue.watchEffect(() => {
- model.value = model.value ?? adapter.getYear(adapter.date());
- });
- const yearRef = templateRef();
- vue.onMounted(async () => {
- await vue.nextTick();
- yearRef.el?.scrollIntoView({
- block: 'center'
- });
- });
- useRender(() => vue.createVNode("div", {
- "class": "v-date-picker-years",
- "style": {
- height: convertToUnit(props.height)
- }
- }, [vue.createVNode("div", {
- "class": "v-date-picker-years__content"
- }, [years.value.map((year, i) => {
- const btnProps = {
- ref: model.value === year.value ? yearRef : undefined,
- active: model.value === year.value,
- color: model.value === year.value ? props.color : undefined,
- rounded: true,
- text: year.text,
- variant: model.value === year.value ? 'flat' : 'text',
- onClick: () => {
- if (model.value === year.value) {
- emit('update:modelValue', model.value);
- return;
- }
- model.value = year.value;
- }
- };
- return slots.year?.({
- year,
- i,
- props: btnProps
- }) ?? vue.createVNode(VBtn, vue.mergeProps({
- "key": "month"
- }, btnProps), null);
- })])]));
- return {};
- }
- });
- // Utilities
- const VPickerTitle = createSimpleFunctional('v-picker-title');
- // Types
- const makeVPickerProps = propsFactory({
- bgColor: String,
- landscape: Boolean,
- title: String,
- hideHeader: Boolean,
- ...makeVSheetProps()
- }, 'VPicker');
- const VPicker = genericComponent()({
- name: 'VPicker',
- props: makeVPickerProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- useRender(() => {
- const sheetProps = VSheet.filterProps(props);
- const hasTitle = !!(props.title || slots.title);
- return vue.createVNode(VSheet, vue.mergeProps(sheetProps, {
- "color": props.bgColor,
- "class": ['v-picker', {
- 'v-picker--landscape': props.landscape,
- 'v-picker--with-actions': !!slots.actions
- }, props.class],
- "style": props.style
- }), {
- default: () => [!props.hideHeader && vue.createVNode("div", {
- "key": "header",
- "class": [backgroundColorClasses.value],
- "style": [backgroundColorStyles.value]
- }, [hasTitle && vue.createVNode(VPickerTitle, {
- "key": "picker-title"
- }, {
- default: () => [slots.title?.() ?? props.title]
- }), slots.header && vue.createVNode("div", {
- "class": "v-picker__header"
- }, [slots.header()])]), vue.createVNode("div", {
- "class": "v-picker__body"
- }, [slots.default?.()]), slots.actions && vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- slim: true,
- variant: 'text'
- }
- }
- }, {
- default: () => [vue.createVNode("div", {
- "class": "v-picker__actions"
- }, [slots.actions()])]
- })]
- });
- });
- return {};
- }
- });
- // Types
- // Types
- const makeVDatePickerProps = propsFactory({
- // TODO: implement in v3.5
- // calendarIcon: {
- // type: String,
- // default: '$calendar',
- // },
- // keyboardIcon: {
- // type: String,
- // default: '$edit',
- // },
- // inputMode: {
- // type: String as PropType<'calendar' | 'keyboard'>,
- // default: 'calendar',
- // },
- // inputText: {
- // type: String,
- // default: '$vuetify.datePicker.input.placeholder',
- // },
- // inputPlaceholder: {
- // type: String,
- // default: 'dd/mm/yyyy',
- // },
- header: {
- type: String,
- default: '$vuetify.datePicker.header'
- },
- ...makeVDatePickerControlsProps(),
- ...makeVDatePickerMonthProps({
- weeksInMonth: 'static'
- }),
- ...omit(makeVDatePickerMonthsProps(), ['modelValue']),
- ...omit(makeVDatePickerYearsProps(), ['modelValue']),
- ...makeVPickerProps({
- title: '$vuetify.datePicker.title'
- }),
- modelValue: null
- }, 'VDatePicker');
- const VDatePicker = genericComponent()({
- name: 'VDatePicker',
- props: makeVDatePickerProps(),
- emits: {
- 'update:modelValue': date => true,
- 'update:month': date => true,
- 'update:year': date => true,
- // 'update:inputMode': (date: any) => true,
- 'update:viewMode': date => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const adapter = useDate();
- const {
- t
- } = useLocale();
- const model = useProxiedModel(props, 'modelValue', undefined, v => wrapInArray(v), v => props.multiple ? v : v[0]);
- const viewMode = useProxiedModel(props, 'viewMode');
- // const inputMode = useProxiedModel(props, 'inputMode')
- const internal = vue.computed(() => {
- const value = adapter.date(model.value?.[0]);
- return value && adapter.isValid(value) ? value : adapter.date();
- });
- const month = vue.ref(Number(props.month ?? adapter.getMonth(adapter.startOfMonth(internal.value))));
- const year = vue.ref(Number(props.year ?? adapter.getYear(adapter.startOfYear(adapter.setMonth(internal.value, month.value)))));
- const isReversing = vue.shallowRef(false);
- const header = vue.computed(() => {
- if (props.multiple && model.value.length > 1) {
- return t('$vuetify.datePicker.itemsSelected', model.value.length);
- }
- return model.value[0] && adapter.isValid(model.value[0]) ? adapter.format(adapter.date(model.value[0]), 'normalDateWithWeekday') : t(props.header);
- });
- const text = vue.computed(() => {
- let date = adapter.date();
- date = adapter.setDate(date, 1);
- date = adapter.setMonth(date, month.value);
- date = adapter.setYear(date, year.value);
- return adapter.format(date, 'monthAndYear');
- });
- // const headerIcon = computed(() => props.inputMode === 'calendar' ? props.keyboardIcon : props.calendarIcon)
- const headerTransition = vue.computed(() => `date-picker-header${isReversing.value ? '-reverse' : ''}-transition`);
- const minDate = vue.computed(() => {
- const date = adapter.date(props.min);
- return props.min && adapter.isValid(date) ? date : null;
- });
- const maxDate = vue.computed(() => {
- const date = adapter.date(props.max);
- return props.max && adapter.isValid(date) ? date : null;
- });
- const disabled = vue.computed(() => {
- if (props.disabled) return true;
- const targets = [];
- if (viewMode.value !== 'month') {
- targets.push(...['prev', 'next']);
- } else {
- let _date = adapter.date();
- _date = adapter.setYear(_date, year.value);
- _date = adapter.setMonth(_date, month.value);
- if (minDate.value) {
- const date = adapter.addDays(adapter.startOfMonth(_date), -1);
- adapter.isAfter(minDate.value, date) && targets.push('prev');
- }
- if (maxDate.value) {
- const date = adapter.addDays(adapter.endOfMonth(_date), 1);
- adapter.isAfter(date, maxDate.value) && targets.push('next');
- }
- }
- return targets;
- });
- // function onClickAppend () {
- // inputMode.value = inputMode.value === 'calendar' ? 'keyboard' : 'calendar'
- // }
- function onClickNext() {
- if (month.value < 11) {
- month.value++;
- } else {
- year.value++;
- month.value = 0;
- onUpdateYear(year.value);
- }
- onUpdateMonth(month.value);
- }
- function onClickPrev() {
- if (month.value > 0) {
- month.value--;
- } else {
- year.value--;
- month.value = 11;
- onUpdateYear(year.value);
- }
- onUpdateMonth(month.value);
- }
- function onClickDate() {
- viewMode.value = 'month';
- }
- function onClickMonth() {
- viewMode.value = viewMode.value === 'months' ? 'month' : 'months';
- }
- function onClickYear() {
- viewMode.value = viewMode.value === 'year' ? 'month' : 'year';
- }
- function onUpdateMonth(value) {
- if (viewMode.value === 'months') onClickMonth();
- emit('update:month', value);
- }
- function onUpdateYear(value) {
- if (viewMode.value === 'year') onClickYear();
- emit('update:year', value);
- }
- vue.watch(model, (val, oldVal) => {
- const arrBefore = wrapInArray(oldVal);
- const arrAfter = wrapInArray(val);
- if (!arrAfter.length) return;
- const before = adapter.date(arrBefore[arrBefore.length - 1]);
- const after = adapter.date(arrAfter[arrAfter.length - 1]);
- const newMonth = adapter.getMonth(after);
- const newYear = adapter.getYear(after);
- if (newMonth !== month.value) {
- month.value = newMonth;
- onUpdateMonth(month.value);
- }
- if (newYear !== year.value) {
- year.value = newYear;
- onUpdateYear(year.value);
- }
- isReversing.value = adapter.isBefore(before, after);
- });
- useRender(() => {
- const pickerProps = VPicker.filterProps(props);
- const datePickerControlsProps = VDatePickerControls.filterProps(props);
- const datePickerHeaderProps = VDatePickerHeader.filterProps(props);
- const datePickerMonthProps = VDatePickerMonth.filterProps(props);
- const datePickerMonthsProps = omit(VDatePickerMonths.filterProps(props), ['modelValue']);
- const datePickerYearsProps = omit(VDatePickerYears.filterProps(props), ['modelValue']);
- const headerProps = {
- header: header.value,
- transition: headerTransition.value
- };
- return vue.createVNode(VPicker, vue.mergeProps(pickerProps, {
- "class": ['v-date-picker', `v-date-picker--${viewMode.value}`, {
- 'v-date-picker--show-week': props.showWeek
- }, props.class],
- "style": props.style
- }), {
- title: () => slots.title?.() ?? vue.createVNode("div", {
- "class": "v-date-picker__title"
- }, [t(props.title)]),
- header: () => slots.header ? vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VDatePickerHeader: {
- ...headerProps
- }
- }
- }, {
- default: () => [slots.header?.(headerProps)]
- }) : vue.createVNode(VDatePickerHeader, vue.mergeProps({
- "key": "header"
- }, datePickerHeaderProps, headerProps, {
- "onClick": viewMode.value !== 'month' ? onClickDate : undefined
- }), {
- ...slots,
- default: undefined
- }),
- default: () => vue.createVNode(vue.Fragment, null, [vue.createVNode(VDatePickerControls, vue.mergeProps(datePickerControlsProps, {
- "disabled": disabled.value,
- "text": text.value,
- "onClick:next": onClickNext,
- "onClick:prev": onClickPrev,
- "onClick:month": onClickMonth,
- "onClick:year": onClickYear
- }), null), vue.createVNode(VFadeTransition, {
- "hideOnLeave": true
- }, {
- default: () => [viewMode.value === 'months' ? vue.createVNode(VDatePickerMonths, vue.mergeProps({
- "key": "date-picker-months"
- }, datePickerMonthsProps, {
- "modelValue": month.value,
- "onUpdate:modelValue": [$event => month.value = $event, onUpdateMonth],
- "min": minDate.value,
- "max": maxDate.value,
- "year": year.value
- }), null) : viewMode.value === 'year' ? vue.createVNode(VDatePickerYears, vue.mergeProps({
- "key": "date-picker-years"
- }, datePickerYearsProps, {
- "modelValue": year.value,
- "onUpdate:modelValue": [$event => year.value = $event, onUpdateYear],
- "min": minDate.value,
- "max": maxDate.value
- }), null) : vue.createVNode(VDatePickerMonth, vue.mergeProps({
- "key": "date-picker-month"
- }, datePickerMonthProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "month": month.value,
- "onUpdate:month": [$event => month.value = $event, onUpdateMonth],
- "year": year.value,
- "onUpdate:year": [$event => year.value = $event, onUpdateYear],
- "min": minDate.value,
- "max": maxDate.value
- }), null)]
- })]),
- actions: slots.actions
- });
- });
- return {};
- }
- });
- // Types
- // Types
- const makeVEmptyStateProps = propsFactory({
- actionText: String,
- bgColor: String,
- color: String,
- icon: IconValue,
- image: String,
- justify: {
- type: String,
- default: 'center'
- },
- headline: String,
- title: String,
- text: String,
- textWidth: {
- type: [Number, String],
- default: 500
- },
- href: String,
- to: String,
- ...makeComponentProps(),
- ...makeDimensionProps(),
- ...makeSizeProps({
- size: undefined
- }),
- ...makeThemeProps()
- }, 'VEmptyState');
- const VEmptyState = genericComponent()({
- name: 'VEmptyState',
- props: makeVEmptyStateProps(),
- emits: {
- 'click:action': e => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const {
- themeClasses
- } = provideTheme(props);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'bgColor'));
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- displayClasses
- } = useDisplay();
- function onClickAction(e) {
- emit('click:action', e);
- }
- useRender(() => {
- const hasActions = !!(slots.actions || props.actionText);
- const hasHeadline = !!(slots.headline || props.headline);
- const hasTitle = !!(slots.title || props.title);
- const hasText = !!(slots.text || props.text);
- const hasMedia = !!(slots.media || props.image || props.icon);
- const size = props.size || (props.image ? 200 : 96);
- return vue.createVNode("div", {
- "class": ['v-empty-state', {
- [`v-empty-state--${props.justify}`]: true
- }, themeClasses.value, backgroundColorClasses.value, displayClasses.value, props.class],
- "style": [backgroundColorStyles.value, dimensionStyles.value, props.style]
- }, [hasMedia && vue.createVNode("div", {
- "key": "media",
- "class": "v-empty-state__media"
- }, [!slots.media ? vue.createVNode(vue.Fragment, null, [props.image ? vue.createVNode(VImg, {
- "key": "image",
- "src": props.image,
- "height": size
- }, null) : props.icon ? vue.createVNode(VIcon, {
- "key": "icon",
- "color": props.color,
- "size": size,
- "icon": props.icon
- }, null) : undefined]) : vue.createVNode(VDefaultsProvider, {
- "key": "media-defaults",
- "defaults": {
- VImg: {
- src: props.image,
- height: size
- },
- VIcon: {
- size,
- icon: props.icon
- }
- }
- }, {
- default: () => [slots.media()]
- })]), hasHeadline && vue.createVNode("div", {
- "key": "headline",
- "class": "v-empty-state__headline"
- }, [slots.headline?.() ?? props.headline]), hasTitle && vue.createVNode("div", {
- "key": "title",
- "class": "v-empty-state__title"
- }, [slots.title?.() ?? props.title]), hasText && vue.createVNode("div", {
- "key": "text",
- "class": "v-empty-state__text",
- "style": {
- maxWidth: convertToUnit(props.textWidth)
- }
- }, [slots.text?.() ?? props.text]), slots.default && vue.createVNode("div", {
- "key": "content",
- "class": "v-empty-state__content"
- }, [slots.default()]), hasActions && vue.createVNode("div", {
- "key": "actions",
- "class": "v-empty-state__actions"
- }, [vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- class: 'v-empty-state__action-btn',
- color: props.color ?? 'surface-variant',
- text: props.actionText
- }
- }
- }, {
- default: () => [slots.actions?.({
- props: {
- onClick: onClickAction
- }
- }) ?? vue.createVNode(VBtn, {
- "onClick": onClickAction
- }, null)]
- })])]);
- });
- return {};
- }
- });
- // Types
- const VExpansionPanelSymbol = Symbol.for('vuetify:v-expansion-panel');
- 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,
- focusable: Boolean,
- static: Boolean,
- ripple: {
- type: [Boolean, Object],
- default: false
- },
- readonly: Boolean,
- ...makeComponentProps(),
- ...makeDimensionProps()
- }, '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 {
- dimensionStyles
- } = useDimension(props);
- const slotProps = vue.computed(() => ({
- collapseIcon: props.collapseIcon,
- disabled: expansionPanel.disabled.value,
- expanded: expansionPanel.isSelected.value,
- expandIcon: props.expandIcon,
- readonly: props.readonly
- }));
- const icon = vue.computed(() => expansionPanel.isSelected.value ? props.collapseIcon : props.expandIcon);
- useRender(() => vue.withDirectives(vue.createVNode("button", {
- "class": ['v-expansion-panel-title', {
- 'v-expansion-panel-title--active': expansionPanel.isSelected.value,
- 'v-expansion-panel-title--focusable': props.focusable,
- 'v-expansion-panel-title--static': props.static
- }, backgroundColorClasses.value, props.class],
- "style": [backgroundColorStyles.value, dimensionStyles.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(VDefaultsProvider, {
- "defaults": {
- VIcon: {
- icon: icon.value
- }
- }
- }, {
- default: () => [vue.createVNode("span", {
- "class": "v-expansion-panel-title__icon"
- }, [slots.actions?.(slotProps.value) ?? vue.createVNode(VIcon, null, null)])]
- })]), [[vue.resolveDirective("ripple"), props.ripple]]));
- return {};
- }
- });
- const makeVExpansionPanelProps = propsFactory({
- title: String,
- text: String,
- bgColor: String,
- ...makeElevationProps(),
- ...makeGroupItemProps(),
- ...makeRoundedProps(),
- ...makeTagProps(),
- ...makeVExpansionPanelTitleProps(),
- ...makeVExpansionPanelTextProps()
- }, '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);
- useRender(() => {
- const hasText = !!(slots.text || props.text);
- const hasTitle = !!(slots.title || props.title);
- const expansionPanelTitleProps = VExpansionPanelTitle.filterProps(props);
- const expansionPanelTextProps = VExpansionPanelText.filterProps(props);
- 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), vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VExpansionPanelTitle: {
- ...expansionPanelTitleProps
- },
- VExpansionPanelText: {
- ...expansionPanelTextProps
- }
- }
- }, {
- default: () => [hasTitle && vue.createVNode(VExpansionPanelTitle, {
- "key": "title"
- }, {
- default: () => [slots.title ? slots.title() : props.title]
- }), hasText && vue.createVNode(VExpansionPanelText, {
- "key": "text"
- }, {
- default: () => [slots.text ? slots.text() : props.text]
- }), slots.default?.()]
- })]
- });
- });
- return {
- groupItem
- };
- }
- });
- // Types
- const allowedVariants = ['default', 'accordion', 'inset', 'popout'];
- const makeVExpansionPanelsProps = propsFactory({
- flat: Boolean,
- ...makeGroupProps(),
- ...pick(makeVExpansionPanelProps(), ['bgColor', 'collapseIcon', 'color', 'eager', 'elevation', 'expandIcon', 'focusable', 'hideActions', 'readonly', 'ripple', 'rounded', 'tile', 'static']),
- ...makeThemeProps(),
- ...makeComponentProps(),
- ...makeTagProps(),
- variant: {
- type: String,
- default: 'default',
- validator: v => allowedVariants.includes(v)
- }
- }, 'VExpansionPanels');
- const VExpansionPanels = genericComponent()({
- name: 'VExpansionPanels',
- props: makeVExpansionPanelsProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- next,
- prev
- } = useGroup(props, VExpansionPanelSymbol);
- const {
- themeClasses
- } = provideTheme(props);
- const variantClass = vue.computed(() => props.variant && `v-expansion-panels--variant-${props.variant}`);
- provideDefaults({
- VExpansionPanel: {
- bgColor: vue.toRef(props, 'bgColor'),
- collapseIcon: vue.toRef(props, 'collapseIcon'),
- color: vue.toRef(props, 'color'),
- eager: vue.toRef(props, 'eager'),
- elevation: vue.toRef(props, 'elevation'),
- expandIcon: vue.toRef(props, 'expandIcon'),
- focusable: vue.toRef(props, 'focusable'),
- hideActions: vue.toRef(props, 'hideActions'),
- readonly: vue.toRef(props, 'readonly'),
- ripple: vue.toRef(props, 'ripple'),
- rounded: vue.toRef(props, 'rounded'),
- static: vue.toRef(props, 'static')
- }
- });
- useRender(() => vue.createVNode(props.tag, {
- "class": ['v-expansion-panels', {
- 'v-expansion-panels--flat': props.flat,
- 'v-expansion-panels--tile': props.tile
- }, themeClasses.value, variantClass.value, props.class],
- "style": props.style
- }, {
- default: () => [slots.default?.({
- prev,
- next
- })]
- }));
- return {
- next,
- prev
- };
- }
- });
- // Types
- const makeVFabProps = propsFactory({
- app: Boolean,
- appear: Boolean,
- extended: Boolean,
- layout: Boolean,
- offset: Boolean,
- modelValue: {
- type: Boolean,
- default: true
- },
- ...omit(makeVBtnProps({
- active: true
- }), ['location']),
- ...makeLayoutItemProps(),
- ...makeLocationProps(),
- ...makeTransitionProps({
- transition: 'fab-transition'
- })
- }, 'VFab');
- const VFab = genericComponent()({
- name: 'VFab',
- props: makeVFabProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const height = vue.shallowRef(56);
- const layoutItemStyles = vue.ref();
- const {
- resizeRef
- } = useResizeObserver(entries => {
- if (!entries.length) return;
- height.value = entries[0].target.clientHeight;
- });
- const hasPosition = vue.computed(() => props.app || props.absolute);
- const position = vue.computed(() => {
- if (!hasPosition.value) return false;
- return props.location?.split(' ').shift() ?? 'bottom';
- });
- const orientation = vue.computed(() => {
- if (!hasPosition.value) return false;
- return props.location?.split(' ')[1] ?? 'end';
- });
- useToggleScope(() => props.app, () => {
- const layout = useLayoutItem({
- id: props.name,
- order: vue.computed(() => parseInt(props.order, 10)),
- position,
- layoutSize: vue.computed(() => props.layout ? height.value + 24 : 0),
- elementSize: vue.computed(() => height.value + 24),
- active: vue.computed(() => props.app && model.value),
- absolute: vue.toRef(props, 'absolute')
- });
- vue.watchEffect(() => {
- layoutItemStyles.value = layout.layoutItemStyles.value;
- });
- });
- const vFabRef = vue.ref();
- useRender(() => {
- const btnProps = VBtn.filterProps(props);
- return vue.createVNode("div", {
- "ref": vFabRef,
- "class": ['v-fab', {
- 'v-fab--absolute': props.absolute,
- 'v-fab--app': !!props.app,
- 'v-fab--extended': props.extended,
- 'v-fab--offset': props.offset,
- [`v-fab--${position.value}`]: hasPosition.value,
- [`v-fab--${orientation.value}`]: hasPosition.value
- }, props.class],
- "style": [props.app ? {
- ...layoutItemStyles.value
- } : {
- height: 'inherit',
- width: undefined
- }, props.style]
- }, [vue.createVNode("div", {
- "class": "v-fab__container"
- }, [vue.createVNode(MaybeTransition, {
- "appear": props.appear,
- "transition": props.transition
- }, {
- default: () => [vue.withDirectives(vue.createVNode(VBtn, vue.mergeProps({
- "ref": resizeRef
- }, btnProps, {
- "active": undefined,
- "location": undefined
- }), slots), [[vue.vShow, props.active]])]
- })])]);
- });
- return {};
- }
- });
- // Types
- const makeVFileInputProps = propsFactory({
- chips: Boolean,
- counter: Boolean,
- counterSizeString: {
- type: String,
- default: '$vuetify.fileInput.counterSize'
- },
- counterString: {
- type: String,
- default: '$vuetify.fileInput.counter'
- },
- hideInput: Boolean,
- multiple: Boolean,
- showSize: {
- type: [Boolean, Number, String],
- default: false,
- validator: v => {
- return typeof v === 'boolean' || [1000, 1024].includes(Number(v));
- }
- },
- ...makeVInputProps({
- prependIcon: '$file'
- }),
- modelValue: {
- type: [Array, Object],
- default: props => props.multiple ? [] : null,
- 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', props.modelValue, val => wrapInArray(val), val => !props.multiple && Array.isArray(val) ? val[0] : val);
- 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) {
- inputRef.value?.click();
- }
- 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-file-input--chips': !!props.chips,
- 'v-file-input--hide': props.hideInput,
- 'v-input--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 || props.dirty,
- "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 && !props.hideInput && (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",
- "text": text
- }, null)) : 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,
- "disabled": props.disabled
- }, 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 layoutItemStyles = vue.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));
- useToggleScope(() => props.app, () => {
- const layout = 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')
- });
- vue.watchEffect(() => {
- layoutItemStyles.value = layout.layoutItemStyles.value;
- });
- });
- 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);
- }
- });
- // Composables
- const makeVHoverProps = propsFactory({
- disabled: Boolean,
- modelValue: {
- type: Boolean,
- default: null
- },
- ...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
- }
- });
- }
- });
- // Types
- const makeVInfiniteScrollProps = propsFactory({
- color: String,
- direction: {
- type: String,
- default: 'vertical',
- validator: v => ['vertical', 'horizontal'].includes(v)
- },
- side: {
- type: String,
- default: 'end',
- validator: v => ['start', 'end', 'both'].includes(v)
- },
- mode: {
- type: String,
- default: 'intersect',
- validator: v => ['intersect', 'manual'].includes(v)
- },
- margin: [Number, String],
- loadMoreText: {
- type: String,
- default: '$vuetify.infiniteScroll.loadMore'
- },
- emptyText: {
- type: String,
- default: '$vuetify.infiniteScroll.empty'
- },
- ...makeDimensionProps(),
- ...makeTagProps()
- }, 'VInfiniteScroll');
- const VInfiniteScrollIntersect = defineComponent({
- name: 'VInfiniteScrollIntersect',
- props: {
- side: {
- type: String,
- required: true
- },
- rootMargin: String
- },
- emits: {
- intersect: (side, isIntersecting) => true
- },
- setup(props, _ref) {
- let {
- emit
- } = _ref;
- const {
- intersectionRef,
- isIntersecting
- } = useIntersectionObserver();
- vue.watch(isIntersecting, async val => {
- emit('intersect', props.side, val);
- });
- useRender(() => vue.createVNode("div", {
- "class": "v-infinite-scroll-intersect",
- "style": {
- '--v-infinite-margin-size': props.rootMargin
- },
- "ref": intersectionRef
- }, [vue.createTextVNode("\xA0")]));
- return {};
- }
- });
- const VInfiniteScroll = genericComponent()({
- name: 'VInfiniteScroll',
- props: makeVInfiniteScrollProps(),
- emits: {
- load: options => true
- },
- setup(props, _ref2) {
- let {
- slots,
- emit
- } = _ref2;
- const rootEl = vue.ref();
- const startStatus = vue.shallowRef('ok');
- const endStatus = vue.shallowRef('ok');
- const margin = vue.computed(() => convertToUnit(props.margin));
- const isIntersecting = vue.shallowRef(false);
- function setScrollAmount(amount) {
- if (!rootEl.value) return;
- const property = props.direction === 'vertical' ? 'scrollTop' : 'scrollLeft';
- rootEl.value[property] = amount;
- }
- function getScrollAmount() {
- if (!rootEl.value) return 0;
- const property = props.direction === 'vertical' ? 'scrollTop' : 'scrollLeft';
- return rootEl.value[property];
- }
- function getScrollSize() {
- if (!rootEl.value) return 0;
- const property = props.direction === 'vertical' ? 'scrollHeight' : 'scrollWidth';
- return rootEl.value[property];
- }
- function getContainerSize() {
- if (!rootEl.value) return 0;
- const property = props.direction === 'vertical' ? 'clientHeight' : 'clientWidth';
- return rootEl.value[property];
- }
- vue.onMounted(() => {
- if (!rootEl.value) return;
- if (props.side === 'start') {
- setScrollAmount(getScrollSize());
- } else if (props.side === 'both') {
- setScrollAmount(getScrollSize() / 2 - getContainerSize() / 2);
- }
- });
- function setStatus(side, status) {
- if (side === 'start') {
- startStatus.value = status;
- } else if (side === 'end') {
- endStatus.value = status;
- }
- }
- function getStatus(side) {
- return side === 'start' ? startStatus.value : endStatus.value;
- }
- let previousScrollSize = 0;
- function handleIntersect(side, _isIntersecting) {
- isIntersecting.value = _isIntersecting;
- if (isIntersecting.value) {
- intersecting(side);
- }
- }
- function intersecting(side) {
- if (props.mode !== 'manual' && !isIntersecting.value) return;
- const status = getStatus(side);
- if (!rootEl.value || ['empty', 'loading'].includes(status)) return;
- previousScrollSize = getScrollSize();
- setStatus(side, 'loading');
- function done(status) {
- setStatus(side, status);
- vue.nextTick(() => {
- if (status === 'empty' || status === 'error') return;
- if (status === 'ok' && side === 'start') {
- setScrollAmount(getScrollSize() - previousScrollSize + getScrollAmount());
- }
- if (props.mode !== 'manual') {
- vue.nextTick(() => {
- window.requestAnimationFrame(() => {
- window.requestAnimationFrame(() => {
- window.requestAnimationFrame(() => {
- intersecting(side);
- });
- });
- });
- });
- }
- });
- }
- emit('load', {
- side,
- done
- });
- }
- const {
- t
- } = useLocale();
- function renderSide(side, status) {
- if (props.side !== side && props.side !== 'both') return;
- const onClick = () => intersecting(side);
- const slotProps = {
- side,
- props: {
- onClick,
- color: props.color
- }
- };
- if (status === 'error') return slots.error?.(slotProps);
- if (status === 'empty') return slots.empty?.(slotProps) ?? vue.createVNode("div", null, [t(props.emptyText)]);
- if (props.mode === 'manual') {
- if (status === 'loading') {
- return slots.loading?.(slotProps) ?? vue.createVNode(VProgressCircular, {
- "indeterminate": true,
- "color": props.color
- }, null);
- }
- return slots['load-more']?.(slotProps) ?? vue.createVNode(VBtn, {
- "variant": "outlined",
- "color": props.color,
- "onClick": onClick
- }, {
- default: () => [t(props.loadMoreText)]
- });
- }
- return slots.loading?.(slotProps) ?? vue.createVNode(VProgressCircular, {
- "indeterminate": true,
- "color": props.color
- }, null);
- }
- const {
- dimensionStyles
- } = useDimension(props);
- useRender(() => {
- const Tag = props.tag;
- const hasStartIntersect = props.side === 'start' || props.side === 'both';
- const hasEndIntersect = props.side === 'end' || props.side === 'both';
- const intersectMode = props.mode === 'intersect';
- return vue.createVNode(Tag, {
- "ref": rootEl,
- "class": ['v-infinite-scroll', `v-infinite-scroll--${props.direction}`, {
- 'v-infinite-scroll--start': hasStartIntersect,
- 'v-infinite-scroll--end': hasEndIntersect
- }],
- "style": dimensionStyles.value
- }, {
- default: () => [vue.createVNode("div", {
- "class": "v-infinite-scroll__side"
- }, [renderSide('start', startStatus.value)]), hasStartIntersect && intersectMode && vue.createVNode(VInfiniteScrollIntersect, {
- "key": "start",
- "side": "start",
- "onIntersect": handleIntersect,
- "rootMargin": margin.value
- }, null), slots.default?.(), hasEndIntersect && intersectMode && vue.createVNode(VInfiniteScrollIntersect, {
- "key": "end",
- "side": "end",
- "onIntersect": handleIntersect,
- "rootMargin": margin.value
- }, null), vue.createVNode("div", {
- "class": "v-infinite-scroll__side"
- }, [renderSide('end', endStatus.value)])]
- });
- });
- }
- });
- // Types
- 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', 'kbd');
- const makeVLayoutProps = propsFactory({
- ...makeComponentProps(),
- ...makeDimensionProps(),
- ...makeLayoutProps()
- }, 'VLayout');
- const VLayout = genericComponent()({
- name: 'VLayout',
- props: makeVLayoutProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- layoutClasses,
- layoutStyles,
- getLayoutItem,
- items,
- layoutRef
- } = createLayout(props);
- const {
- dimensionStyles
- } = useDimension(props);
- useRender(() => vue.createVNode("div", {
- "ref": layoutRef,
- "class": [layoutClasses.value, props.class],
- "style": [dimensionStyles.value, 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(),
- ...makeDimensionProps(),
- ...makeTagProps({
- tag: 'main'
- })
- }, 'VMain');
- const VMain = genericComponent()({
- name: 'VMain',
- props: makeVMainProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- dimensionStyles
- } = useDimension(props);
- 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, dimensionStyles.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 {
- el,
- 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) {
- start = [touchX, touchY];
- offset.value = getOffset(isHorizontal.value ? touchX : touchY, isActive.value);
- dragProgress.value = getProgress(isHorizontal.value ? touchX : touchY);
- maybeDragging = offset.value > -20 && offset.value < 80;
- 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;
- });
- useToggleScope(isDragging, () => {
- const transform = el.value?.style.transform ?? null;
- const transition = el.value?.style.transition ?? null;
- vue.watchEffect(() => {
- el.value?.style.setProperty('transform', dragStyles.value?.transform || 'none');
- el.value?.style.setProperty('transition', dragStyles.value?.transition || null);
- });
- vue.onScopeDispose(() => {
- el.value?.style.setProperty('transform', transform);
- el.value?.style.setProperty('transition', transition);
- });
- });
- 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,
- persistent: Boolean,
- touchless: Boolean,
- width: {
- type: [Number, String],
- default: 256
- },
- location: {
- type: String,
- default: 'start',
- validator: value => locations.includes(value)
- },
- sticky: Boolean,
- ...makeBorderProps(),
- ...makeComponentProps(),
- ...makeDelayProps(),
- ...makeDisplayProps({
- mobile: null
- }),
- ...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 {
- displayClasses,
- mobile
- } = useDisplay(props);
- 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 {
- runOpenDelay,
- runCloseDelay
- } = useDelay(props, value => {
- isHovering.value = value;
- });
- 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 isPersistent = vue.computed(() => props.persistent);
- const isTemporary = vue.computed(() => !props.permanent && (mobile.value || props.temporary));
- const isSticky = vue.computed(() => props.sticky && !isTemporary.value && location.value !== 'bottom');
- useToggleScope(() => props.expandOnHover && props.rail != null, () => {
- vue.watch(isHovering, val => emit('update:rail', !val));
- });
- useToggleScope(() => !props.disableResizeWatcher, () => {
- vue.watch(isTemporary, val => !props.permanent && vue.nextTick(() => isActive.value = !val));
- });
- useToggleScope(() => !props.disableRouteWatcher && !!router, () => {
- vue.watch(router.currentRoute, () => isTemporary.value && (isActive.value = false));
- });
- vue.watch(() => props.permanent, val => {
- if (val) isActive.value = true;
- });
- if (props.modelValue == null && !isTemporary.value) {
- isActive.value = props.permanent || !mobile.value;
- }
- const {
- isDragging,
- dragProgress
- } = useTouch({
- el: rootEl,
- 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 elementSize = vue.computed(() => ['top', 'bottom'].includes(props.location) ? 0 : width.value);
- const {
- layoutItemStyles,
- layoutItemScrimStyles
- } = useLayoutItem({
- id: props.name,
- order: vue.computed(() => parseInt(props.order, 10)),
- position: location,
- layoutSize,
- elementSize,
- 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'
- }
- });
- useRender(() => {
- const hasImage = slots.image || props.image;
- return vue.createVNode(vue.Fragment, null, [vue.createVNode(props.tag, vue.mergeProps({
- "ref": rootEl,
- "onMouseenter": runOpenDelay,
- "onMouseleave": runCloseDelay,
- "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--persistent': isPersistent.value,
- 'v-navigation-drawer--active': isActive.value,
- 'v-navigation-drawer--sticky': isSticky.value
- }, themeClasses.value, backgroundColorClasses.value, borderClasses.value, displayClasses.value, elevationClasses.value, roundedClasses.value, props.class],
- "style": [backgroundColorStyles.value, layoutItemStyles.value, ssrBootStyles.value, stickyStyles.value, props.style, ['top', 'bottom'].includes(location.value) ? {
- height: 'auto'
- } : {}]
- }, scopeId, attrs), {
- default: () => [hasImage && vue.createVNode("div", {
- "key": "image",
- "class": "v-navigation-drawer__img"
- }, [!slots.image ? vue.createVNode(VImg, {
- "key": "image-img",
- "alt": "",
- "cover": true,
- "height": "inherit",
- "src": props.image
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "image-defaults",
- "disabled": !props.image,
- "defaults": {
- VImg: {
- alt: '',
- cover: true,
- height: 'inherit',
- src: props.image
- }
- }
- }, slots.image)]), 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": () => {
- if (isPersistent.value) return;
- 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?.();
- }
- });
- // Types
- // Types
- const makeVOtpInputProps = propsFactory({
- autofocus: Boolean,
- divider: String,
- focusAll: Boolean,
- label: {
- type: String,
- default: '$vuetify.input.otp'
- },
- length: {
- type: [Number, String],
- default: 6
- },
- modelValue: {
- type: [Number, String],
- default: undefined
- },
- placeholder: String,
- type: {
- type: String,
- default: 'number'
- },
- ...makeDimensionProps(),
- ...makeFocusProps(),
- ...only(makeVFieldProps({
- variant: 'outlined'
- }), ['baseColor', 'bgColor', 'class', 'color', 'disabled', 'error', 'loading', 'rounded', 'style', 'theme', 'variant'])
- }, 'VOtpInput');
- const VOtpInput = genericComponent()({
- name: 'VOtpInput',
- props: makeVOtpInputProps(),
- emits: {
- finish: val => true,
- 'update:focused': val => true,
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- attrs,
- emit,
- slots
- } = _ref;
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const model = useProxiedModel(props, 'modelValue', '', val => val == null ? [] : String(val).split(''), val => val.join(''));
- const {
- t
- } = useLocale();
- const length = vue.computed(() => Number(props.length));
- const fields = vue.computed(() => Array(length.value).fill(0));
- const focusIndex = vue.ref(-1);
- const contentRef = vue.ref();
- const inputRef = vue.ref([]);
- const current = vue.computed(() => inputRef.value[focusIndex.value]);
- function onInput() {
- // The maxlength attribute doesn't work for the number type input, so the text type is used.
- // The following logic simulates the behavior of a number input.
- if (isValidNumber(current.value.value)) {
- current.value.value = '';
- return;
- }
- const array = model.value.slice();
- const value = current.value.value;
- array[focusIndex.value] = value;
- let target = null;
- if (focusIndex.value > model.value.length) {
- target = model.value.length + 1;
- } else if (focusIndex.value + 1 !== length.value) {
- target = 'next';
- }
- model.value = array;
- if (target) focusChild(contentRef.value, target);
- }
- function onKeydown(e) {
- const array = model.value.slice();
- const index = focusIndex.value;
- let target = null;
- if (!['ArrowLeft', 'ArrowRight', 'Backspace', 'Delete'].includes(e.key)) return;
- e.preventDefault();
- if (e.key === 'ArrowLeft') {
- target = 'prev';
- } else if (e.key === 'ArrowRight') {
- target = 'next';
- } else if (['Backspace', 'Delete'].includes(e.key)) {
- array[focusIndex.value] = '';
- model.value = array;
- if (focusIndex.value > 0 && e.key === 'Backspace') {
- target = 'prev';
- } else {
- requestAnimationFrame(() => {
- inputRef.value[index]?.select();
- });
- }
- }
- requestAnimationFrame(() => {
- if (target != null) {
- focusChild(contentRef.value, target);
- }
- });
- }
- function onPaste(index, e) {
- e.preventDefault();
- e.stopPropagation();
- const clipboardText = e?.clipboardData?.getData('Text').slice(0, length.value) ?? '';
- if (isValidNumber(clipboardText)) return;
- model.value = clipboardText.split('');
- inputRef.value?.[index].blur();
- }
- function reset() {
- model.value = [];
- }
- function onFocus(e, index) {
- focus();
- focusIndex.value = index;
- }
- function onBlur() {
- blur();
- focusIndex.value = -1;
- }
- function isValidNumber(value) {
- return props.type === 'number' && /[^0-9]/g.test(value);
- }
- provideDefaults({
- VField: {
- color: vue.computed(() => props.color),
- bgColor: vue.computed(() => props.color),
- baseColor: vue.computed(() => props.baseColor),
- disabled: vue.computed(() => props.disabled),
- error: vue.computed(() => props.error),
- variant: vue.computed(() => props.variant)
- }
- }, {
- scoped: true
- });
- vue.watch(model, val => {
- if (val.length === length.value) emit('finish', val.join(''));
- }, {
- deep: true
- });
- vue.watch(focusIndex, val => {
- if (val < 0) return;
- vue.nextTick(() => {
- inputRef.value[val]?.select();
- });
- });
- useRender(() => {
- const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
- return vue.createVNode("div", vue.mergeProps({
- "class": ['v-otp-input', {
- 'v-otp-input--divided': !!props.divider
- }, props.class],
- "style": [props.style]
- }, rootAttrs), [vue.createVNode("div", {
- "ref": contentRef,
- "class": "v-otp-input__content",
- "style": [dimensionStyles.value]
- }, [fields.value.map((_, i) => vue.createVNode(vue.Fragment, null, [props.divider && i !== 0 && vue.createVNode("span", {
- "class": "v-otp-input__divider"
- }, [props.divider]), vue.createVNode(VField, {
- "focused": isFocused.value && props.focusAll || focusIndex.value === i,
- "key": i
- }, {
- ...slots,
- loader: undefined,
- default: () => {
- return vue.createVNode("input", {
- "ref": val => inputRef.value[i] = val,
- "aria-label": t(props.label, i + 1),
- "autofocus": i === 0 && props.autofocus,
- "autocomplete": "one-time-code",
- "class": ['v-otp-input__field'],
- "disabled": props.disabled,
- "inputmode": props.type === 'number' ? 'numeric' : 'text',
- "min": props.type === 'number' ? 0 : undefined,
- "maxlength": "1",
- "placeholder": props.placeholder,
- "type": props.type === 'number' ? 'text' : props.type,
- "value": model.value[i],
- "onInput": onInput,
- "onFocus": e => onFocus(e, i),
- "onBlur": onBlur,
- "onKeydown": onKeydown,
- "onPaste": event => onPaste(i, event)
- }, null);
- }
- })])), vue.createVNode("input", vue.mergeProps({
- "class": "v-otp-input-input",
- "type": "hidden"
- }, inputAttrs, {
- "value": model.value.join('')
- }), null), vue.createVNode(VOverlay, {
- "contained": true,
- "content-class": "v-otp-input__loader",
- "model-value": !!props.loading,
- "persistent": true
- }, {
- default: () => [slots.loader?.() ?? vue.createVNode(VProgressCircular, {
- "color": typeof props.loading === 'boolean' ? undefined : props.loading,
- "indeterminate": true,
- "size": "24",
- "width": "2"
- }, null)]
- }), slots.default?.()])]);
- });
- return {
- blur: () => {
- inputRef.value?.some(input => input.blur());
- },
- focus: () => {
- inputRef.value?.[0].focus();
- },
- reset,
- isFocused
- };
- }
- });
- // 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(() => {
- const controlProps = VSelectionControl.filterProps(props);
- return vue.createVNode(VSelectionControl, vue.mergeProps(controlProps, {
- "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': value => 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 [rootAttrs, controlAttrs] = filterInputAttrs(attrs);
- const inputProps = VInput.filterProps(props);
- const controlProps = 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
- }, rootAttrs, 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,
- readonly
- } = 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": !readonly.value ? onSliderMousedown : undefined,
- "onTouchstartPassive": !readonly.value ? onSliderTouchstart : undefined
- }, [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 (max.value !== min.value && 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,
- "ripple": props.ripple
- }, {
- '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 (max.value !== min.value && 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,
- "ripple": props.ripple
- }, {
- '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 {};
- }
- });
- // Types
- const rootTypes = {
- actions: 'button@2',
- article: 'heading, paragraph',
- avatar: 'avatar',
- button: 'button',
- card: 'image, heading',
- 'card-avatar': 'image, list-item-avatar',
- chip: 'chip',
- 'date-picker': 'list-item, heading, divider, date-picker-options, date-picker-days, actions',
- 'date-picker-options': 'text, avatar@2',
- 'date-picker-days': 'avatar@28',
- divider: 'divider',
- heading: 'heading',
- image: 'image',
- 'list-item': 'text',
- 'list-item-avatar': 'avatar, text',
- 'list-item-two-line': 'sentences',
- 'list-item-avatar-two-line': 'avatar, sentences',
- 'list-item-three-line': 'paragraph',
- 'list-item-avatar-three-line': 'avatar, paragraph',
- ossein: 'ossein',
- paragraph: 'text@3',
- sentences: 'text@2',
- subtitle: 'text',
- table: 'table-heading, table-thead, table-tbody, table-tfoot',
- 'table-heading': 'chip, text',
- 'table-thead': 'heading@6',
- 'table-tbody': 'table-row-divider@6',
- 'table-row-divider': 'table-row, divider',
- 'table-row': 'text@6',
- 'table-tfoot': 'text@2, avatar@2',
- text: 'text'
- };
- function genBone(type) {
- let children = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
- return vue.createVNode("div", {
- "class": ['v-skeleton-loader__bone', `v-skeleton-loader__${type}`]
- }, [children]);
- }
- function genBones(bone) {
- // e.g. 'text@3'
- const [type, length] = bone.split('@');
- // Generate a length array based upon
- // value after @ in the bone string
- return Array.from({
- length
- }).map(() => genStructure(type));
- }
- function genStructure(type) {
- let children = [];
- if (!type) return children;
- // TODO: figure out a better way to type this
- const bone = rootTypes[type];
- // End of recursion, do nothing
- /* eslint-disable-next-line no-empty, brace-style */
- if (type === bone) ;
- // Array of values - e.g. 'heading, paragraph, text@2'
- else if (type.includes(',')) return mapBones(type);
- // Array of values - e.g. 'paragraph@4'
- else if (type.includes('@')) return genBones(type);
- // Array of values - e.g. 'card@2'
- else if (bone.includes(',')) children = mapBones(bone);
- // Array of values - e.g. 'list-item@2'
- else if (bone.includes('@')) children = genBones(bone);
- // Single value - e.g. 'card-heading'
- else if (bone) children.push(genStructure(bone));
- return [genBone(type, children)];
- }
- function mapBones(bones) {
- // Remove spaces and return array of structures
- return bones.replace(/\s/g, '').split(',').map(genStructure);
- }
- const makeVSkeletonLoaderProps = propsFactory({
- boilerplate: Boolean,
- color: String,
- loading: Boolean,
- loadingText: {
- type: String,
- default: '$vuetify.loading'
- },
- type: {
- type: [String, Array],
- default: 'ossein'
- },
- ...makeDimensionProps(),
- ...makeElevationProps(),
- ...makeThemeProps()
- }, 'VSkeletonLoader');
- const VSkeletonLoader = genericComponent()({
- name: 'VSkeletonLoader',
- props: makeVSkeletonLoaderProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- const {
- dimensionStyles
- } = useDimension(props);
- const {
- elevationClasses
- } = useElevation(props);
- const {
- themeClasses
- } = provideTheme(props);
- const {
- t
- } = useLocale();
- const items = vue.computed(() => genStructure(wrapInArray(props.type).join(',')));
- useRender(() => {
- const isLoading = !slots.default || props.loading;
- const loadingProps = props.boilerplate || !isLoading ? {} : {
- ariaLive: 'polite',
- ariaLabel: t(props.loadingText),
- role: 'alert'
- };
- return vue.createVNode("div", vue.mergeProps({
- "class": ['v-skeleton-loader', {
- 'v-skeleton-loader--boilerplate': props.boilerplate
- }, themeClasses.value, backgroundColorClasses.value, elevationClasses.value],
- "style": [backgroundColorStyles.value, isLoading ? dimensionStyles.value : {}]
- }, loadingProps), [isLoading ? items.value : slots.default?.()]);
- });
- return {};
- }
- });
- // 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
- });
- }
- });
- // Types
- function useCountdown(milliseconds) {
- const time = vue.shallowRef(milliseconds());
- let timer = -1;
- function clear() {
- clearInterval(timer);
- }
- function reset() {
- clear();
- vue.nextTick(() => time.value = milliseconds());
- }
- function start(el) {
- const style = el ? getComputedStyle(el) : {
- transitionDuration: 0.2
- };
- const interval = parseFloat(style.transitionDuration) * 1000 || 200;
- clear();
- if (time.value <= 0) return;
- const startTime = performance.now();
- timer = window.setInterval(() => {
- const elapsed = performance.now() - startTime + interval;
- time.value = Math.max(milliseconds() - elapsed, 0);
- if (time.value <= 0) clear();
- }, interval);
- }
- vue.onScopeDispose(clear);
- return {
- clear,
- time,
- start,
- reset
- };
- }
- const makeVSnackbarProps = propsFactory({
- multiLine: Boolean,
- text: String,
- timer: [Boolean, String],
- 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 {
- positionClasses
- } = usePosition(props);
- const {
- scopeId
- } = useScopeId();
- const {
- themeClasses
- } = provideTheme(props);
- const {
- colorClasses,
- colorStyles,
- variantClasses
- } = useVariant(props);
- const {
- roundedClasses
- } = useRounded(props);
- const countdown = useCountdown(() => Number(props.timeout));
- const overlay = vue.ref();
- const timerRef = vue.ref();
- const isHovering = vue.shallowRef(false);
- const startY = vue.shallowRef(0);
- const mainStyles = vue.ref();
- const hasLayout = vue.inject(VuetifyLayoutKey, undefined);
- useToggleScope(() => !!hasLayout, () => {
- const layout = useLayout();
- vue.watchEffect(() => {
- mainStyles.value = layout.mainStyles.value;
- });
- });
- vue.watch(isActive, startTimeout);
- vue.watch(() => props.timeout, startTimeout);
- vue.onMounted(() => {
- if (isActive.value) startTimeout();
- });
- let activeTimeout = -1;
- function startTimeout() {
- countdown.reset();
- window.clearTimeout(activeTimeout);
- const timeout = Number(props.timeout);
- if (!isActive.value || timeout === -1) return;
- const element = refElement(timerRef.value);
- countdown.start(element);
- activeTimeout = window.setTimeout(() => {
- isActive.value = false;
- }, timeout);
- }
- function clearTimeout() {
- countdown.reset();
- window.clearTimeout(activeTimeout);
- }
- function onPointerenter() {
- isHovering.value = true;
- clearTimeout();
- }
- function onPointerleave() {
- isHovering.value = false;
- startTimeout();
- }
- function onTouchstart(event) {
- startY.value = event.touches[0].clientY;
- }
- function onTouchend(event) {
- if (Math.abs(startY.value - event.changedTouches[0].clientY) > 50) {
- isActive.value = false;
- }
- }
- function onAfterLeave() {
- if (isHovering.value) onPointerleave();
- }
- const locationClasses = vue.computed(() => {
- return props.location.split(' ').reduce((acc, loc) => {
- acc[`v-snackbar--${loc}`] = true;
- return acc;
- }, {});
- });
- useRender(() => {
- const overlayProps = VOverlay.filterProps(props);
- const hasContent = !!(slots.default || slots.text || props.text);
- 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--timer': !!props.timer,
- 'v-snackbar--vertical': props.vertical
- }, locationClasses.value, positionClasses.value, props.class],
- "style": [mainStyles.value, 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: [colorStyles.value],
- onPointerenter,
- onPointerleave
- }, overlayProps.contentProps),
- "persistent": true,
- "noClickAnimation": true,
- "scrim": false,
- "scrollStrategy": "none",
- "_disableGlobalStack": true,
- "onTouchstartPassive": onTouchstart,
- "onTouchend": onTouchend,
- "onAfterLeave": onAfterLeave
- }, scopeId), {
- default: () => [genOverlays(false, 'v-snackbar'), props.timer && !isHovering.value && vue.createVNode("div", {
- "key": "timer",
- "class": "v-snackbar__timer"
- }, [vue.createVNode(VProgressLinear, {
- "ref": timerRef,
- "color": typeof props.timer === 'string' ? props.timer : 'info',
- "max": props.timeout,
- "model-value": countdown.time.value
- }, null)]), hasContent && vue.createVNode("div", {
- "key": "content",
- "class": "v-snackbar__content",
- "role": "status",
- "aria-live": "polite"
- }, [slots.text?.() ?? props.text, slots.default?.()]), slots.actions && vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- variant: 'text',
- ripple: false,
- slim: true
- }
- }
- }, {
- default: () => [vue.createVNode("div", {
- "class": "v-snackbar__actions"
- }, [slots.actions({
- isActive
- })])]
- })],
- activator: slots.activator
- });
- });
- return forwardRefs({}, overlay);
- }
- });
- // Utilities
- // Types
- const makeLineProps = propsFactory({
- autoDraw: Boolean,
- autoDrawDuration: [Number, String],
- autoDrawEasing: {
- type: String,
- default: 'ease'
- },
- color: String,
- gradient: {
- type: Array,
- default: () => []
- },
- gradientDirection: {
- type: String,
- validator: val => ['top', 'bottom', 'left', 'right'].includes(val),
- default: 'top'
- },
- height: {
- type: [String, Number],
- default: 75
- },
- labels: {
- type: Array,
- default: () => []
- },
- labelSize: {
- type: [Number, String],
- default: 7
- },
- lineWidth: {
- type: [String, Number],
- default: 4
- },
- id: String,
- itemValue: {
- type: String,
- default: 'value'
- },
- modelValue: {
- type: Array,
- default: () => []
- },
- min: [String, Number],
- max: [String, Number],
- padding: {
- type: [String, Number],
- default: 8
- },
- showLabels: Boolean,
- smooth: Boolean,
- width: {
- type: [Number, String],
- default: 300
- }
- }, 'Line');
- // Types
- const makeVBarlineProps = propsFactory({
- autoLineWidth: Boolean,
- ...makeLineProps()
- }, 'VBarline');
- const VBarline = genericComponent()({
- name: 'VBarline',
- props: makeVBarlineProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const uid = getUid();
- const id = vue.computed(() => props.id || `barline-${uid}`);
- const autoDrawDuration = vue.computed(() => Number(props.autoDrawDuration) || 500);
- const hasLabels = vue.computed(() => {
- return Boolean(props.showLabels || props.labels.length > 0 || !!slots?.label);
- });
- const lineWidth = vue.computed(() => parseFloat(props.lineWidth) || 4);
- const totalWidth = vue.computed(() => Math.max(props.modelValue.length * lineWidth.value, Number(props.width)));
- const boundary = vue.computed(() => {
- return {
- minX: 0,
- maxX: totalWidth.value,
- minY: 0,
- maxY: parseInt(props.height, 10)
- };
- });
- const items = vue.computed(() => props.modelValue.map(item => getPropertyFromItem(item, props.itemValue, item)));
- function genBars(values, boundary) {
- const {
- minX,
- maxX,
- minY,
- maxY
- } = boundary;
- const totalValues = values.length;
- let maxValue = props.max != null ? Number(props.max) : Math.max(...values);
- let minValue = props.min != null ? Number(props.min) : Math.min(...values);
- if (minValue > 0 && props.min == null) minValue = 0;
- if (maxValue < 0 && props.max == null) maxValue = 0;
- const gridX = maxX / totalValues;
- const gridY = (maxY - minY) / (maxValue - minValue || 1);
- const horizonY = maxY - Math.abs(minValue * gridY);
- return values.map((value, index) => {
- const height = Math.abs(gridY * value);
- return {
- x: minX + index * gridX,
- y: horizonY - height + +(value < 0) * height,
- height,
- value
- };
- });
- }
- const parsedLabels = vue.computed(() => {
- const labels = [];
- const points = genBars(items.value, boundary.value);
- const len = points.length;
- for (let i = 0; labels.length < len; i++) {
- const item = points[i];
- let value = props.labels[i];
- if (!value) {
- value = typeof item === 'object' ? item.value : item;
- }
- labels.push({
- x: item.x,
- value: String(value)
- });
- }
- return labels;
- });
- const bars = vue.computed(() => genBars(items.value, boundary.value));
- const offsetX = vue.computed(() => (Math.abs(bars.value[0].x - bars.value[1].x) - lineWidth.value) / 2);
- useRender(() => {
- const gradientData = !props.gradient.slice().length ? [''] : props.gradient.slice().reverse();
- return vue.createVNode("svg", {
- "display": "block"
- }, [vue.createVNode("defs", null, [vue.createVNode("linearGradient", {
- "id": id.value,
- "gradientUnits": "userSpaceOnUse",
- "x1": props.gradientDirection === 'left' ? '100%' : '0',
- "y1": props.gradientDirection === 'top' ? '100%' : '0',
- "x2": props.gradientDirection === 'right' ? '100%' : '0',
- "y2": props.gradientDirection === 'bottom' ? '100%' : '0'
- }, [gradientData.map((color, index) => vue.createVNode("stop", {
- "offset": index / Math.max(gradientData.length - 1, 1),
- "stop-color": color || 'currentColor'
- }, null))])]), vue.createVNode("clipPath", {
- "id": `${id.value}-clip`
- }, [bars.value.map(item => vue.createVNode("rect", {
- "x": item.x + offsetX.value,
- "y": item.y,
- "width": lineWidth.value,
- "height": item.height,
- "rx": typeof props.smooth === 'number' ? props.smooth : props.smooth ? 2 : 0,
- "ry": typeof props.smooth === 'number' ? props.smooth : props.smooth ? 2 : 0
- }, [props.autoDraw && vue.createVNode(vue.Fragment, null, [vue.createVNode("animate", {
- "attributeName": "y",
- "from": item.y + item.height,
- "to": item.y,
- "dur": `${autoDrawDuration.value}ms`,
- "fill": "freeze"
- }, null), vue.createVNode("animate", {
- "attributeName": "height",
- "from": "0",
- "to": item.height,
- "dur": `${autoDrawDuration.value}ms`,
- "fill": "freeze"
- }, null)])]))]), hasLabels.value && vue.createVNode("g", {
- "key": "labels",
- "style": {
- textAnchor: 'middle',
- dominantBaseline: 'mathematical',
- fill: 'currentColor'
- }
- }, [parsedLabels.value.map((item, i) => vue.createVNode("text", {
- "x": item.x + offsetX.value + lineWidth.value / 2,
- "y": parseInt(props.height, 10) - 2 + (parseInt(props.labelSize, 10) || 7 * 0.75),
- "font-size": Number(props.labelSize) || 7
- }, [slots.label?.({
- index: i,
- value: item.value
- }) ?? item.value]))]), vue.createVNode("g", {
- "clip-path": `url(#${id.value}-clip)`,
- "fill": `url(#${id.value})`
- }, [vue.createVNode("rect", {
- "x": 0,
- "y": 0,
- "width": Math.max(props.modelValue.length * lineWidth.value, Number(props.width)),
- "height": props.height
- }, null)])]);
- });
- }
- });
- // @ts-nocheck
- /* eslint-disable */
- // import { checkCollinear, getDistance, moveTo } from './math'
- /**
- * From https://github.com/unsplash/react-trend/blob/master/src/helpers/DOM.helpers.js#L18
- */
- function genPath(points, radius) {
- let fill = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
- let height = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 75;
- if (points.length === 0) return '';
- const start = points.shift();
- const end = points[points.length - 1];
- return (fill ? `M${start.x} ${height - start.x + 2} L${start.x} ${start.y}` : `M${start.x} ${start.y}`) + points.map((point, index) => {
- const next = points[index + 1];
- const prev = points[index - 1] || start;
- const isCollinear = next && checkCollinear(next, point, prev);
- if (!next || isCollinear) {
- return `L${point.x} ${point.y}`;
- }
- const threshold = Math.min(getDistance(prev, point), getDistance(next, point));
- const isTooCloseForRadius = threshold / 2 < radius;
- const radiusForPoint = isTooCloseForRadius ? threshold / 2 : radius;
- const before = moveTo(prev, point, radiusForPoint);
- const after = moveTo(next, point, radiusForPoint);
- return `L${before.x} ${before.y}S${point.x} ${point.y} ${after.x} ${after.y}`;
- }).join('') + (fill ? `L${end.x} ${height - start.x + 2} Z` : '');
- }
- function int(value) {
- return parseInt(value, 10);
- }
- /**
- * https://en.wikipedia.org/wiki/Collinearity
- * x=(x1+x2)/2
- * y=(y1+y2)/2
- */
- function checkCollinear(p0, p1, p2) {
- return int(p0.x + p2.x) === int(2 * p1.x) && int(p0.y + p2.y) === int(2 * p1.y);
- }
- function getDistance(p1, p2) {
- return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
- }
- function moveTo(to, from, radius) {
- const vector = {
- x: to.x - from.x,
- y: to.y - from.y
- };
- const length = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
- const unitVector = {
- x: vector.x / length,
- y: vector.y / length
- };
- return {
- x: from.x + unitVector.x * radius,
- y: from.y + unitVector.y * radius
- };
- }
- // Types
- const makeVTrendlineProps = propsFactory({
- fill: Boolean,
- ...makeLineProps()
- }, 'VTrendline');
- const VTrendline = genericComponent()({
- name: 'VTrendline',
- props: makeVTrendlineProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const uid = getUid();
- const id = vue.computed(() => props.id || `trendline-${uid}`);
- const autoDrawDuration = vue.computed(() => Number(props.autoDrawDuration) || (props.fill ? 500 : 2000));
- const lastLength = vue.ref(0);
- const path = vue.ref(null);
- function genPoints(values, boundary) {
- const {
- minX,
- maxX,
- minY,
- maxY
- } = boundary;
- const totalValues = values.length;
- const maxValue = props.max != null ? Number(props.max) : Math.max(...values);
- const minValue = props.min != null ? Number(props.min) : Math.min(...values);
- const gridX = (maxX - minX) / (totalValues - 1);
- const gridY = (maxY - minY) / (maxValue - minValue || 1);
- return values.map((value, index) => {
- return {
- x: minX + index * gridX,
- y: maxY - (value - minValue) * gridY,
- value
- };
- });
- }
- const hasLabels = vue.computed(() => {
- return Boolean(props.showLabels || props.labels.length > 0 || !!slots?.label);
- });
- const lineWidth = vue.computed(() => {
- return parseFloat(props.lineWidth) || 4;
- });
- const totalWidth = vue.computed(() => Number(props.width));
- const boundary = vue.computed(() => {
- const padding = Number(props.padding);
- return {
- minX: padding,
- maxX: totalWidth.value - padding,
- minY: padding,
- maxY: parseInt(props.height, 10) - padding
- };
- });
- const items = vue.computed(() => props.modelValue.map(item => getPropertyFromItem(item, props.itemValue, item)));
- const parsedLabels = vue.computed(() => {
- const labels = [];
- const points = genPoints(items.value, boundary.value);
- const len = points.length;
- for (let i = 0; labels.length < len; i++) {
- const item = points[i];
- let value = props.labels[i];
- if (!value) {
- value = typeof item === 'object' ? item.value : item;
- }
- labels.push({
- x: item.x,
- value: String(value)
- });
- }
- return labels;
- });
- vue.watch(() => props.modelValue, async () => {
- await vue.nextTick();
- if (!props.autoDraw || !path.value) return;
- const pathRef = path.value;
- const length = pathRef.getTotalLength();
- if (!props.fill) {
- // Initial setup to "hide" the line by using the stroke dash array
- pathRef.style.strokeDasharray = `${length}`;
- pathRef.style.strokeDashoffset = `${length}`;
- // Force reflow to ensure the transition starts from this state
- pathRef.getBoundingClientRect();
- // Animate the stroke dash offset to "draw" the line
- pathRef.style.transition = `stroke-dashoffset ${autoDrawDuration.value}ms ${props.autoDrawEasing}`;
- pathRef.style.strokeDashoffset = '0';
- } else {
- // Your existing logic for filled paths remains the same
- pathRef.style.transformOrigin = 'bottom center';
- pathRef.style.transition = 'none';
- pathRef.style.transform = `scaleY(0)`;
- pathRef.getBoundingClientRect();
- pathRef.style.transition = `transform ${autoDrawDuration.value}ms ${props.autoDrawEasing}`;
- pathRef.style.transform = `scaleY(1)`;
- }
- lastLength.value = length;
- }, {
- immediate: true
- });
- function genPath$1(fill) {
- return genPath(genPoints(items.value, boundary.value), props.smooth ? 8 : Number(props.smooth), fill, parseInt(props.height, 10));
- }
- useRender(() => {
- const gradientData = !props.gradient.slice().length ? [''] : props.gradient.slice().reverse();
- return vue.createVNode("svg", {
- "display": "block",
- "stroke-width": parseFloat(props.lineWidth) ?? 4
- }, [vue.createVNode("defs", null, [vue.createVNode("linearGradient", {
- "id": id.value,
- "gradientUnits": "userSpaceOnUse",
- "x1": props.gradientDirection === 'left' ? '100%' : '0',
- "y1": props.gradientDirection === 'top' ? '100%' : '0',
- "x2": props.gradientDirection === 'right' ? '100%' : '0',
- "y2": props.gradientDirection === 'bottom' ? '100%' : '0'
- }, [gradientData.map((color, index) => vue.createVNode("stop", {
- "offset": index / Math.max(gradientData.length - 1, 1),
- "stop-color": color || 'currentColor'
- }, null))])]), hasLabels.value && vue.createVNode("g", {
- "key": "labels",
- "style": {
- textAnchor: 'middle',
- dominantBaseline: 'mathematical',
- fill: 'currentColor'
- }
- }, [parsedLabels.value.map((item, i) => vue.createVNode("text", {
- "x": item.x + lineWidth.value / 2 + lineWidth.value / 2,
- "y": parseInt(props.height, 10) - 4 + (parseInt(props.labelSize, 10) || 7 * 0.75),
- "font-size": Number(props.labelSize) || 7
- }, [slots.label?.({
- index: i,
- value: item.value
- }) ?? item.value]))]), vue.createVNode("path", {
- "ref": path,
- "d": genPath$1(props.fill),
- "fill": props.fill ? `url(#${id.value})` : 'none',
- "stroke": props.fill ? 'none' : `url(#${id.value})`
- }, null), props.fill && vue.createVNode("path", {
- "d": genPath$1(false),
- "fill": "none",
- "stroke": props.color ?? props.gradient?.[0]
- }, null)]);
- });
- }
- });
- // Types
- // Types
- const makeVSparklineProps = propsFactory({
- type: {
- type: String,
- default: 'trend'
- },
- ...makeVBarlineProps(),
- ...makeVTrendlineProps()
- }, 'VSparkline');
- const VSparkline = genericComponent()({
- name: 'VSparkline',
- props: makeVSparklineProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.toRef(props, 'color'));
- const hasLabels = vue.computed(() => {
- return Boolean(props.showLabels || props.labels.length > 0 || !!slots?.label);
- });
- const totalHeight = vue.computed(() => {
- let height = parseInt(props.height, 10);
- if (hasLabels.value) height += parseInt(props.labelSize, 10) * 1.5;
- return height;
- });
- useRender(() => {
- const Tag = props.type === 'trend' ? VTrendline : VBarline;
- const lineProps = props.type === 'trend' ? VTrendline.filterProps(props) : VBarline.filterProps(props);
- return vue.createVNode(Tag, vue.mergeProps({
- "key": props.type,
- "class": textColorClasses.value,
- "style": textColorStyles.value,
- "viewBox": `0 0 ${props.width} ${parseInt(totalHeight.value, 10)}`
- }, lineProps), slots);
- });
- }
- });
- // Types
- const makeVSpeedDialProps = propsFactory({
- ...makeComponentProps(),
- ...makeVMenuProps({
- offset: 8,
- minWidth: 0,
- openDelay: 0,
- closeDelay: 100,
- location: 'top center',
- transition: 'scale-transition'
- })
- }, 'VSpeedDial');
- const VSpeedDial = genericComponent()({
- name: 'VSpeedDial',
- props: makeVSpeedDialProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const menuRef = vue.ref();
- const location = vue.computed(() => {
- const [y, x = 'center'] = props.location?.split(' ') ?? [];
- return `${y} ${x}`;
- });
- const locationClasses = vue.computed(() => ({
- [`v-speed-dial__content--${location.value.replace(' ', '-')}`]: true
- }));
- useRender(() => {
- const menuProps = VMenu.filterProps(props);
- return vue.createVNode(VMenu, vue.mergeProps(menuProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "class": props.class,
- "style": props.style,
- "contentClass": ['v-speed-dial__content', locationClasses.value, props.contentClass],
- "location": location.value,
- "ref": menuRef,
- "transition": "fade-transition"
- }), {
- ...slots,
- default: slotProps => vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- size: 'small'
- }
- }
- }, {
- default: () => [vue.createVNode(MaybeTransition, {
- "appear": true,
- "group": true,
- "transition": props.transition
- }, {
- default: () => [slots.default?.(slotProps)]
- })]
- })
- });
- });
- return {};
- }
- });
- // Types
- const VStepperSymbol = Symbol.for('vuetify:v-stepper');
- // Types
- const makeVStepperActionsProps = propsFactory({
- color: String,
- disabled: {
- type: [Boolean, String],
- default: false
- },
- prevText: {
- type: String,
- default: '$vuetify.stepper.prev'
- },
- nextText: {
- type: String,
- default: '$vuetify.stepper.next'
- }
- }, 'VStepperActions');
- const VStepperActions = genericComponent()({
- name: 'VStepperActions',
- props: makeVStepperActionsProps(),
- emits: {
- 'click:prev': () => true,
- 'click:next': () => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- function onClickPrev() {
- emit('click:prev');
- }
- function onClickNext() {
- emit('click:next');
- }
- useRender(() => {
- const prevSlotProps = {
- onClick: onClickPrev
- };
- const nextSlotProps = {
- onClick: onClickNext
- };
- return vue.createVNode("div", {
- "class": "v-stepper-actions"
- }, [vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- disabled: ['prev', true].includes(props.disabled),
- text: t(props.prevText),
- variant: 'text'
- }
- }
- }, {
- default: () => [slots.prev?.({
- props: prevSlotProps
- }) ?? vue.createVNode(VBtn, prevSlotProps, null)]
- }), vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- color: props.color,
- disabled: ['next', true].includes(props.disabled),
- text: t(props.nextText),
- variant: 'tonal'
- }
- }
- }, {
- default: () => [slots.next?.({
- props: nextSlotProps
- }) ?? vue.createVNode(VBtn, nextSlotProps, null)]
- })]);
- });
- return {};
- }
- });
- // Utilities
- const VStepperHeader = createSimpleFunctional('v-stepper-header');
- // Types
- const makeStepperItemProps = propsFactory({
- color: String,
- title: String,
- subtitle: String,
- complete: Boolean,
- completeIcon: {
- type: IconValue,
- default: '$complete'
- },
- editable: Boolean,
- editIcon: {
- type: IconValue,
- default: '$edit'
- },
- error: Boolean,
- errorIcon: {
- type: IconValue,
- default: '$error'
- },
- icon: IconValue,
- ripple: {
- type: [Boolean, Object],
- default: true
- },
- rules: {
- type: Array,
- default: () => []
- }
- }, 'StepperItem');
- const makeVStepperItemProps = propsFactory({
- ...makeStepperItemProps(),
- ...makeGroupItemProps()
- }, 'VStepperItem');
- const VStepperItem = genericComponent()({
- name: 'VStepperItem',
- directives: {
- Ripple
- },
- props: makeVStepperItemProps(),
- emits: {
- 'group:selected': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const group = useGroupItem(props, VStepperSymbol, true);
- const step = vue.computed(() => group?.value.value ?? props.value);
- const isValid = vue.computed(() => props.rules.every(handler => handler() === true));
- const isClickable = vue.computed(() => !props.disabled && props.editable);
- const canEdit = vue.computed(() => !props.disabled && props.editable);
- const hasError = vue.computed(() => props.error || !isValid.value);
- const hasCompleted = vue.computed(() => props.complete || props.rules.length > 0 && isValid.value);
- const icon = vue.computed(() => {
- if (hasError.value) return props.errorIcon;
- if (hasCompleted.value) return props.completeIcon;
- if (group.isSelected.value && props.editable) return props.editIcon;
- return props.icon;
- });
- const slotProps = vue.computed(() => ({
- canEdit: canEdit.value,
- hasError: hasError.value,
- hasCompleted: hasCompleted.value,
- title: props.title,
- subtitle: props.subtitle,
- step: step.value,
- value: props.value
- }));
- useRender(() => {
- const hasColor = (!group || group.isSelected.value || hasCompleted.value || canEdit.value) && !hasError.value && !props.disabled;
- const hasTitle = !!(props.title != null || slots.title);
- const hasSubtitle = !!(props.subtitle != null || slots.subtitle);
- function onClick() {
- group?.toggle();
- }
- return vue.withDirectives(vue.createVNode("button", {
- "class": ['v-stepper-item', {
- 'v-stepper-item--complete': hasCompleted.value,
- 'v-stepper-item--disabled': props.disabled,
- 'v-stepper-item--error': hasError.value
- }, group?.selectedClass.value],
- "disabled": !props.editable,
- "onClick": onClick
- }, [isClickable.value && genOverlays(true, 'v-stepper-item'), vue.createVNode(VAvatar, {
- "key": "stepper-avatar",
- "class": "v-stepper-item__avatar",
- "color": hasColor ? props.color : undefined,
- "size": 24
- }, {
- default: () => [slots.icon?.(slotProps.value) ?? (icon.value ? vue.createVNode(VIcon, {
- "icon": icon.value
- }, null) : step.value)]
- }), vue.createVNode("div", {
- "class": "v-stepper-item__content"
- }, [hasTitle && vue.createVNode("div", {
- "key": "title",
- "class": "v-stepper-item__title"
- }, [slots.title?.(slotProps.value) ?? props.title]), hasSubtitle && vue.createVNode("div", {
- "key": "subtitle",
- "class": "v-stepper-item__subtitle"
- }, [slots.subtitle?.(slotProps.value) ?? props.subtitle]), slots.default?.(slotProps.value)])]), [[vue.resolveDirective("ripple"), props.ripple && props.editable, null]]);
- });
- return {};
- }
- });
- const makeVStepperWindowProps = propsFactory({
- ...omit(makeVWindowProps(), ['continuous', 'nextIcon', 'prevIcon', 'showArrows', 'touch', 'mandatory'])
- }, 'VStepperWindow');
- const VStepperWindow = genericComponent()({
- name: 'VStepperWindow',
- props: makeVStepperWindowProps(),
- emits: {
- 'update:modelValue': v => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const group = vue.inject(VStepperSymbol, null);
- const _model = useProxiedModel(props, 'modelValue');
- const model = vue.computed({
- get() {
- // Always return modelValue if defined
- // or if not within a VStepper group
- if (_model.value != null || !group) return _model.value;
- // If inside of a VStepper, find the currently selected
- // item by id. Item value may be assigned by its index
- return group.items.value.find(item => group.selected.value.includes(item.id))?.value;
- },
- set(val) {
- _model.value = val;
- }
- });
- useRender(() => {
- const windowProps = VWindow.filterProps(props);
- return vue.createVNode(VWindow, vue.mergeProps({
- "_as": "VStepperWindow"
- }, windowProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "class": ['v-stepper-window', props.class],
- "style": props.style,
- "mandatory": false,
- "touch": false
- }), slots);
- });
- return {};
- }
- });
- const makeVStepperWindowItemProps = propsFactory({
- ...makeVWindowItemProps()
- }, 'VStepperWindowItem');
- const VStepperWindowItem = genericComponent()({
- name: 'VStepperWindowItem',
- props: makeVStepperWindowItemProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => {
- const windowItemProps = VWindowItem.filterProps(props);
- return vue.createVNode(VWindowItem, vue.mergeProps({
- "_as": "VStepperWindowItem"
- }, windowItemProps, {
- "class": ['v-stepper-window-item', props.class],
- "style": props.style
- }), slots);
- });
- return {};
- }
- });
- // Types
- const makeStepperProps = propsFactory({
- altLabels: Boolean,
- bgColor: String,
- completeIcon: IconValue,
- editIcon: IconValue,
- editable: Boolean,
- errorIcon: IconValue,
- hideActions: Boolean,
- items: {
- type: Array,
- default: () => []
- },
- itemTitle: {
- type: String,
- default: 'title'
- },
- itemValue: {
- type: String,
- default: 'value'
- },
- nonLinear: Boolean,
- flat: Boolean,
- ...makeDisplayProps()
- }, 'Stepper');
- const makeVStepperProps = propsFactory({
- ...makeStepperProps(),
- ...makeGroupProps({
- mandatory: 'force',
- selectedClass: 'v-stepper-item--selected'
- }),
- ...makeVSheetProps(),
- ...only(makeVStepperActionsProps(), ['prevText', 'nextText'])
- }, 'VStepper');
- const VStepper = genericComponent()({
- name: 'VStepper',
- props: makeVStepperProps(),
- emits: {
- 'update:modelValue': v => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- items: _items,
- next,
- prev,
- selected
- } = useGroup(props, VStepperSymbol);
- const {
- displayClasses,
- mobile
- } = useDisplay(props);
- const {
- completeIcon,
- editIcon,
- errorIcon,
- color,
- editable,
- prevText,
- nextText
- } = vue.toRefs(props);
- const items = vue.computed(() => props.items.map((item, index) => {
- const title = getPropertyFromItem(item, props.itemTitle, item);
- const value = getPropertyFromItem(item, props.itemValue, index + 1);
- return {
- title,
- value,
- raw: item
- };
- }));
- const activeIndex = vue.computed(() => {
- return _items.value.findIndex(item => selected.value.includes(item.id));
- });
- const disabled = vue.computed(() => {
- if (props.disabled) return props.disabled;
- if (activeIndex.value === 0) return 'prev';
- if (activeIndex.value === _items.value.length - 1) return 'next';
- return false;
- });
- provideDefaults({
- VStepperItem: {
- editable,
- errorIcon,
- completeIcon,
- editIcon,
- prevText,
- nextText
- },
- VStepperActions: {
- color,
- disabled,
- prevText,
- nextText
- }
- });
- useRender(() => {
- const sheetProps = VSheet.filterProps(props);
- const hasHeader = !!(slots.header || props.items.length);
- const hasWindow = props.items.length > 0;
- const hasActions = !props.hideActions && !!(hasWindow || slots.actions);
- return vue.createVNode(VSheet, vue.mergeProps(sheetProps, {
- "color": props.bgColor,
- "class": ['v-stepper', {
- 'v-stepper--alt-labels': props.altLabels,
- 'v-stepper--flat': props.flat,
- 'v-stepper--non-linear': props.nonLinear,
- 'v-stepper--mobile': mobile.value
- }, displayClasses.value, props.class],
- "style": props.style
- }), {
- default: () => [hasHeader && vue.createVNode(VStepperHeader, {
- "key": "stepper-header"
- }, {
- default: () => [items.value.map((_ref2, index) => {
- let {
- raw,
- ...item
- } = _ref2;
- return vue.createVNode(vue.Fragment, null, [!!index && vue.createVNode(VDivider, null, null), vue.createVNode(VStepperItem, item, {
- default: slots[`header-item.${item.value}`] ?? slots.header,
- icon: slots.icon,
- title: slots.title,
- subtitle: slots.subtitle
- })]);
- })]
- }), hasWindow && vue.createVNode(VStepperWindow, {
- "key": "stepper-window"
- }, {
- default: () => [items.value.map(item => vue.createVNode(VStepperWindowItem, {
- "value": item.value
- }, {
- default: () => slots[`item.${item.value}`]?.(item) ?? slots.item?.(item)
- }))]
- }), slots.default?.({
- prev,
- next
- }), hasActions && (slots.actions?.({
- next,
- prev
- }) ?? vue.createVNode(VStepperActions, {
- "key": "stepper-actions",
- "onClick:prev": prev,
- "onClick:next": next
- }, slots))]
- });
- });
- return {
- prev,
- next
- };
- }
- });
- // 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': value => true,
- 'update:indeterminate': value => 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 control = vue.ref();
- const isForcedColorsModeActive = IN_BROWSER && window.matchMedia('(forced-colors: active)').matches;
- 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;
- }
- }
- function onTrackClick(e) {
- e.stopPropagation();
- e.preventDefault();
- control.value?.input?.click();
- }
- useRender(() => {
- const [rootAttrs, controlAttrs] = filterInputAttrs(attrs);
- const inputProps = VInput.filterProps(props);
- const controlProps = VSelectionControl.filterProps(props);
- return vue.createVNode(VInput, vue.mergeProps({
- "class": ['v-switch', {
- 'v-switch--flat': props.flat
- }, {
- 'v-switch--inset': props.inset
- }, {
- 'v-switch--indeterminate': indeterminate.value
- }, loaderClasses.value, props.class]
- }, rootAttrs, 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,
- isValid
- } = _ref2;
- const slotProps = {
- model,
- isValid
- };
- 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: _ref3 => {
- let {
- backgroundColorClasses,
- backgroundColorStyles
- } = _ref3;
- return vue.createVNode("div", {
- "class": ['v-switch__track', !isForcedColorsModeActive ? backgroundColorClasses.value : undefined],
- "style": backgroundColorStyles.value,
- "onClick": onTrackClick
- }, [slots['track-true'] && vue.createVNode("div", {
- "key": "prepend",
- "class": "v-switch__track-true"
- }, [slots['track-true'](slotProps)]), slots['track-false'] && vue.createVNode("div", {
- "key": "append",
- "class": "v-switch__track-false"
- }, [slots['track-false'](slotProps)])]);
- },
- input: _ref4 => {
- let {
- inputNode,
- icon,
- backgroundColorClasses,
- backgroundColorStyles
- } = _ref4;
- return vue.createVNode(vue.Fragment, null, [inputNode, vue.createVNode("div", {
- "class": ['v-switch__thumb', {
- 'v-switch__thumb--filled': icon || props.loading
- }, props.inset || isForcedColorsModeActive ? undefined : backgroundColorClasses.value],
- "style": props.inset ? undefined : backgroundColorStyles.value
- }, [slots.thumb ? vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VIcon: {
- icon,
- size: 'x-small'
- }
- }
- }, {
- default: () => [slots.thumb({
- ...slotProps,
- icon
- })]
- }) : vue.createVNode(VScaleTransition, null, {
- default: () => [!props.loading ? icon && vue.createVNode(VIcon, {
- "key": String(icon),
- "icon": icon,
- "size": "x-small"
- }, null) : 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 rootEl = vue.ref();
- const sliderEl = vue.ref();
- const isHorizontal = vue.computed(() => props.direction === 'horizontal');
- const isSelected = vue.computed(() => rootEl.value?.group?.isSelected.value ?? false);
- function updateSlider(_ref2) {
- let {
- value
- } = _ref2;
- 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]) || 0;
- const initialScale = prevBox[widthHeight] / nextBox[widthHeight] || 0;
- 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
- }, btnProps, attrs, {
- "block": props.fixed,
- "maxWidth": props.fixed ? 300 : undefined,
- "onGroup:selected": updateSlider
- }), {
- ...slots,
- default: () => vue.createVNode(vue.Fragment, null, [slots.default?.() ?? props.text, !props.hideSlider && vue.createVNode("div", {
- "ref": sliderEl,
- "class": ['v-tab__slider', sliderColorClasses.value],
- "style": sliderColorStyles.value
- }, null)])
- });
- });
- return forwardRefs({}, rootEl);
- }
- });
- const makeVTabsWindowProps = propsFactory({
- ...omit(makeVWindowProps(), ['continuous', 'nextIcon', 'prevIcon', 'showArrows', 'touch', 'mandatory'])
- }, 'VTabsWindow');
- const VTabsWindow = genericComponent()({
- name: 'VTabsWindow',
- props: makeVTabsWindowProps(),
- emits: {
- 'update:modelValue': v => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const group = vue.inject(VTabsSymbol, null);
- const _model = useProxiedModel(props, 'modelValue');
- const model = vue.computed({
- get() {
- // Always return modelValue if defined
- // or if not within a VTabs group
- if (_model.value != null || !group) return _model.value;
- // If inside of a VTabs, find the currently selected
- // item by id. Item value may be assigned by its index
- return group.items.value.find(item => group.selected.value.includes(item.id))?.value;
- },
- set(val) {
- _model.value = val;
- }
- });
- useRender(() => {
- const windowProps = VWindow.filterProps(props);
- return vue.createVNode(VWindow, vue.mergeProps({
- "_as": "VTabsWindow"
- }, windowProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "class": ['v-tabs-window', props.class],
- "style": props.style,
- "mandatory": false,
- "touch": false
- }), slots);
- });
- return {};
- }
- });
- const makeVTabsWindowItemProps = propsFactory({
- ...makeVWindowItemProps()
- }, 'VTabsWindowItem');
- const VTabsWindowItem = genericComponent()({
- name: 'VTabsWindowItem',
- props: makeVTabsWindowItemProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- useRender(() => {
- const windowItemProps = VWindowItem.filterProps(props);
- return vue.createVNode(VWindowItem, vue.mergeProps({
- "_as": "VTabsWindowItem"
- }, windowItemProps, {
- "class": ['v-tabs-window-item', props.class],
- "style": props.style
- }), slots);
- });
- return {};
- }
- });
- function parseItems(items) {
- if (!items) return [];
- return items.map(item => {
- if (!isObject(item)) return {
- text: 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',
- selectedClass: 'v-tab-item--selected'
- }),
- ...makeDensityProps(),
- ...makeTagProps()
- }, 'VTabs');
- const VTabs = genericComponent()({
- name: 'VTabs',
- props: makeVTabsProps(),
- emits: {
- 'update:modelValue': v => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const model = useProxiedModel(props, 'modelValue');
- const items = vue.computed(() => parseItems(props.items));
- const {
- densityClasses
- } = useDensity(props);
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'bgColor'));
- const {
- scopeId
- } = useScopeId();
- 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);
- const hasWindow = !!(slots.window || props.items.length > 0);
- return vue.createVNode(vue.Fragment, null, [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
- }, scopeId, attrs), {
- default: () => [slots.default?.() ?? items.value.map(item => slots.tab?.({
- item
- }) ?? vue.createVNode(VTab, vue.mergeProps(item, {
- "key": item.text,
- "value": item.value
- }), {
- default: slots[`tab.${item.value}`] ? () => slots[`tab.${item.value}`]?.({
- item
- }) : undefined
- }))]
- }), hasWindow && vue.createVNode(VTabsWindow, vue.mergeProps({
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "key": "tabs-window"
- }, scopeId), {
- default: () => [items.value.map(item => slots.item?.({
- item
- }) ?? vue.createVNode(VTabsWindowItem, {
- "value": item.value
- }, {
- default: () => slots[`item.${item.value}`]?.({
- item
- })
- })), slots.window?.()]
- })]);
- });
- 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-input--plain-underlined': isPlainOrUnderlined.value
- }, props.class],
- "style": props.style
- }, rootAttrs, inputProps, {
- "centerAffix": rows.value === 1 && !isPlainOrUnderlined.value,
- "focused": isFocused.value
- }), {
- ...slots,
- default: _ref2 => {
- let {
- id,
- 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']
- }, fieldProps, {
- "id": id.value,
- "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'],
- "id": `${slotProps.id}-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,
- "disabled": props.disabled
- }, 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?.()]
- });
- };
- }
- });
- 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
- // 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 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)
- },
- lineThickness: {
- type: [String, Number],
- default: 2
- },
- lineColor: String,
- truncateLine: {
- type: String,
- validator: v => ['start', 'end', 'both'].includes(v)
- },
- ...only(makeVTimelineItemProps({
- lineInset: 0
- }), ['dotColor', 'fillDot', 'hideOpposite', 'iconColor', 'lineInset', 'size']),
- ...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'),
- dotColor: vue.toRef(props, 'dotColor'),
- fillDot: vue.toRef(props, 'fillDot'),
- hideOpposite: vue.toRef(props, 'hideOpposite'),
- iconColor: vue.toRef(props, 'iconColor'),
- lineColor: vue.toRef(props, 'lineColor'),
- lineInset: vue.toRef(props, 'lineInset'),
- size: vue.toRef(props, 'size')
- }
- });
- 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 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
- // Types
- const VValidation = genericComponent()({
- name: 'VValidation',
- props: makeValidationProps(),
- emits: {
- 'update:modelValue': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const validation = useValidation(props, 'validation');
- return () => slots.default?.(validation);
- }
- });
- const makeVCalendarIntervalEventProps = propsFactory({
- allDay: Boolean,
- interval: Object,
- intervalDivisions: {
- type: Number,
- required: true
- },
- intervalDuration: {
- type: Number,
- required: true
- },
- intervalHeight: {
- type: Number,
- required: true
- },
- event: Object
- }, 'VCalendarIntervalEvent');
- const VCalendarIntervalEvent = genericComponent()({
- name: 'VCalendarIntervalEvent',
- props: makeVCalendarIntervalEventProps(),
- setup(props) {
- const adapter = useDate();
- const calcHeight = () => {
- if (!props.event?.first && !props.event?.last || adapter.isEqual(props.event?.start, props.interval?.start)) {
- return {
- height: '100%',
- margin: convertToUnit(0)
- };
- } else {
- const {
- height,
- margin
- } = Array.from({
- length: props.intervalDivisions
- }, x => x * (props.intervalDuration / props.intervalDivisions)).reduce((total, div, index) => {
- if (adapter.isBefore(adapter.addMinutes(props.interval?.start, div), props.event?.start)) {
- return {
- height: convertToUnit(props.intervalHeight / props.intervalDivisions * index),
- margin: convertToUnit(props.intervalHeight / props.intervalDivisions * index)
- };
- }
- return {
- height: total.height,
- margin: total.margin
- };
- }, {
- height: '',
- margin: ''
- });
- return {
- height,
- margin
- };
- }
- };
- useRender(() => {
- return vue.createVNode(VSheet, {
- "height": calcHeight().height,
- "density": "comfortable",
- "style": `margin-top: ${calcHeight().margin}`,
- "class": "v-calendar-internal-event",
- "color": props.event?.color ?? undefined,
- "rounded": props.event?.first && props.event?.last ? true : props.event?.first ? 't' : props.event?.last ? 'b' : false
- }, {
- default: () => [props.event?.first ? props.event?.title : '']
- });
- });
- return {};
- }
- });
- const makeVCalendarIntervalProps = propsFactory({
- day: {
- type: Object,
- default: () => ({})
- },
- dayIndex: Number,
- events: Array,
- intervalDivisions: {
- type: Number,
- default: 2
- },
- intervalDuration: {
- type: Number,
- default: 60
- },
- intervalHeight: {
- type: Number,
- default: 48
- },
- intervalFormat: {
- type: [String, Function],
- default: 'fullTime12h'
- },
- intervalStart: {
- type: Number,
- default: 0
- }
- }, 'VCalendarInterval');
- const VCalendarInterval = genericComponent()({
- name: 'VCalendarInterval',
- props: {
- index: {
- type: Number,
- required: true
- },
- ...makeVCalendarIntervalProps()
- },
- setup(props, _ref) {
- const adapter = useDate();
- const interval = vue.computed(() => {
- const start = adapter.addMinutes(adapter.startOfDay(props.day.date), props.intervalDuration * (props.index + props.intervalStart));
- const end = adapter.addMinutes(adapter.startOfDay(props.day.date), props.intervalDuration * (props.index + props.intervalStart + 1) - 1);
- return {
- ...props.day,
- label: adapter.format(start, 'fullTime24h'),
- start,
- end,
- events: props.events ? props.events.filter(e => !e.allDay && (adapter.isEqual(start, e.start) || adapter.isWithinRange(e.start, [start, end]) || adapter.isWithinRange(start, [e.start, e.end]) || adapter.isEqual(end, e.end))).map(e => {
- return {
- ...e,
- first: adapter.isEqual(start, e.start) || adapter.isWithinRange(e.start, [start, end]),
- last: adapter.isEqual(end, e.end) || adapter.isWithinRange(e.end, [start, end])
- };
- }) : []
- };
- });
- useRender(() => {
- return props.dayIndex === 0 ? vue.createVNode("div", {
- "class": "v-calendar-day__row-with-label",
- "style": `height: ${convertToUnit(props.intervalHeight)}`
- }, [vue.createVNode("div", {
- "class": "v-calendar-day__row-label"
- }, [vue.createVNode("slot", {
- "name": "intervalFormat",
- "interval": interval.value
- }, [props.index ? props.intervalFormat ? typeof props.intervalFormat === 'string' ? adapter.format(interval.value.start, 'hours12h') : props.intervalFormat(interval.value) : interval.value.label : ''])]), vue.createVNode("div", {
- "class": "v-calendar-day__row-hairline"
- }, null), vue.createVNode("div", {
- "class": ['v-calendar-day__row-content', interval.value.events.some(e => !e.last) ? 'v-calendar-day__row-content-through' : '']
- }, [vue.createVNode("slot", {
- "name": "intervalBody",
- "interval": interval.value
- }, [interval.value.events?.map(event => vue.createVNode(VCalendarIntervalEvent, {
- "event": event,
- "interval": interval.value,
- "intervalDivisions": props.intervalDivisions,
- "intervalDuration": props.intervalDuration,
- "intervalHeight": props.intervalHeight
- }, null))])])]) : vue.createVNode("div", {
- "class": "v-calendar-day__row-without-label",
- "style": `height: ${convertToUnit(props.intervalHeight)}`
- }, [vue.createVNode("div", {
- "class": ['v-calendar-day__row-content', interval.value.events.some(e => !e.last) ? 'v-calendar-day__row-content-through' : '']
- }, [vue.createVNode("slot", {
- "name": "intervalBody",
- "interval": interval.value
- }, [interval.value.events?.filter(event => !event.allDay).map(event => vue.createVNode(VCalendarIntervalEvent, {
- "event": event,
- "interval": interval.value,
- "intervalDivisions": props.intervalDivisions,
- "intervalDuration": props.intervalDuration,
- "intervalHeight": props.intervalHeight
- }, null))])])]);
- });
- return {
- interval
- };
- }
- });
- const makeVCalendarDayProps = propsFactory({
- hideDayHeader: Boolean,
- intervals: {
- type: Number,
- default: 24
- },
- ...makeVCalendarIntervalProps()
- }, 'VCalendarDay');
- const VCalendarDay = genericComponent()({
- name: 'VCalendarDay',
- props: makeVCalendarDayProps(),
- setup(props) {
- const adapter = useDate();
- const intervals = vue.computed(() => [...Array.from({
- length: props.intervals
- }, (v, i) => i).filter((int, index) => props.intervalDuration * (index + props.intervalStart) < 1440)]);
- useRender(() => {
- const calendarIntervalProps = VCalendarInterval.filterProps(props);
- return vue.createVNode("div", {
- "class": "v-calendar-day__container"
- }, [!props.hideDayHeader && vue.createVNode("div", {
- "key": "calender-week-name",
- "class": "v-calendar-weekly__head-weekday"
- }, [adapter.format(props.day.date, 'weekdayShort'), vue.createVNode("div", null, [vue.createVNode(VBtn, {
- "icon": true,
- "text": adapter.format(props.day.date, 'dayOfMonth'),
- "variant": "text"
- }, null)])]), intervals.value.map((_, index) => vue.createVNode(VCalendarInterval, vue.mergeProps({
- "index": index
- }, calendarIntervalProps), null))]);
- });
- return {
- intervals
- };
- }
- });
- // Types
- const makeVCalendarHeaderProps = propsFactory({
- nextIcon: {
- type: String,
- default: '$next'
- },
- prevIcon: {
- type: String,
- default: '$prev'
- },
- title: String,
- text: {
- type: String,
- default: '$vuetify.calendar.today'
- },
- viewMode: {
- type: String,
- default: 'month'
- }
- }, 'VCalendarHeader');
- const VCalendarHeader = genericComponent()({
- name: 'VCalendarHeader',
- props: makeVCalendarHeaderProps(),
- emits: {
- 'click:next': () => true,
- 'click:prev': () => true,
- 'click:toToday': () => true
- },
- setup(props, _ref) {
- let {
- emit
- } = _ref;
- const {
- t
- } = useLocale();
- function prev() {
- emit('click:prev');
- }
- function next() {
- emit('click:next');
- }
- function toToday() {
- emit('click:toToday');
- }
- useRender(() => vue.createVNode("div", {
- "class": "v-calendar-header"
- }, [props.text && vue.createVNode(VBtn, {
- "key": "today",
- "class": "v-calendar-header__today",
- "text": t(props.text),
- "variant": "outlined",
- "onClick": toToday
- }, null), vue.createVNode(VBtn, {
- "density": "comfortable",
- "icon": props.prevIcon,
- "variant": "text",
- "onClick": prev
- }, null), vue.createVNode(VBtn, {
- "density": "comfortable",
- "icon": props.nextIcon,
- "variant": "text",
- "onClick": next
- }, null), vue.createVNode("div", {
- "class": "v-calendar-header__title"
- }, [props.title])]));
- return {};
- }
- });
- const makeVCalendarEventProps = propsFactory({
- allDay: Boolean,
- day: Object,
- event: Object
- }, 'VCalendarEvent');
- const VCalendarEvent = genericComponent()({
- name: 'VCalendarEvent',
- props: makeVCalendarEventProps(),
- setup(props) {
- useRender(() => vue.createVNode(VChip, {
- "color": props.allDay ? 'primary' : undefined,
- "density": "comfortable",
- "label": props.allDay,
- "width": "100%"
- }, {
- default: () => [vue.createVNode(VBadge, {
- "inline": true,
- "dot": true,
- "color": props.event?.color
- }, null), props.event?.title]
- }));
- return {};
- }
- });
- const makeVCalendarMonthDayProps = propsFactory({
- active: Boolean,
- color: String,
- day: Object,
- disabled: Boolean,
- events: Array,
- title: [Number, String]
- }, 'VCalendarMonthDay');
- const VCalendarMonthDay = genericComponent()({
- name: 'VCalendarMonthDay',
- props: makeVCalendarMonthDayProps(),
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- useRender(() => {
- const hasTitle = !!(props.title || slots.title?.({
- title: props.title
- }));
- return vue.createVNode("div", {
- "class": ['v-calendar-month__day']
- }, [!props.day?.isHidden && hasTitle && vue.createVNode("div", {
- "key": "title",
- "class": "v-calendar-weekly__day-label"
- }, [slots.title?.({
- title: props.title
- }) ?? vue.createVNode(VBtn, {
- "class": props.day?.isToday ? 'v-calendar-weekly__day-label__today' : undefined,
- "color": props.color,
- "disabled": props.disabled,
- "icon": true,
- "size": "x-small",
- "variant": props.day?.isToday ? undefined : 'flat'
- }, {
- default: () => [props.title]
- })]), !props.day?.isHidden && vue.createVNode("div", {
- "key": "content",
- "class": "v-calendar-weekly__day-content"
- }, [slots.content?.() ?? vue.createVNode("div", null, [vue.createVNode("div", {
- "class": "v-calendar-weekly__day-alldayevents-container"
- }, [props.events?.filter(event => event.allDay).map(event => slots.event ? slots.event({
- day: props.day,
- allDay: true,
- event
- }) : vue.createVNode(VCalendarEvent, {
- "day": props.day,
- "event": event,
- "allDay": true
- }, null))]), vue.createVNode("div", {
- "class": "v-calendar-weekly__day-events-container"
- }, [props.events?.filter(event => !event.allDay).map(event => slots.event ? slots.event({
- day: props.day,
- event,
- allDay: false
- }) : vue.createVNode(VCalendarEvent, {
- "day": props.day,
- "event": event
- }, null))])])]), !props.day?.isHidden && slots.default?.()]);
- });
- return {};
- }
- });
- const makeVCalendarProps = propsFactory({
- hideHeader: Boolean,
- hideWeekNumber: Boolean,
- ...makeCalendarProps(),
- ...makeVCalendarDayProps(),
- ...makeVCalendarHeaderProps()
- }, 'VCalender');
- const VCalendar = genericComponent()({
- name: 'VCalendar',
- props: makeVCalendarProps(),
- emits: {
- next: null,
- prev: null,
- 'update:modelValue': null
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const adapter = useDate();
- const {
- daysInMonth,
- daysInWeek,
- genDays,
- model,
- displayValue,
- weekNumbers,
- weekDays
- } = useCalendar(props);
- const dayNames = adapter.getWeekdays();
- function onClickNext() {
- if (props.viewMode === 'month') {
- model.value = [adapter.addMonths(displayValue.value, 1)];
- }
- if (props.viewMode === 'week') {
- model.value = [adapter.addDays(displayValue.value, 7)];
- }
- if (props.viewMode === 'day') {
- model.value = [adapter.addDays(displayValue.value, 1)];
- }
- }
- function onClickPrev() {
- if (props.viewMode === 'month') {
- model.value = [adapter.addMonths(displayValue.value, -1)];
- }
- if (props.viewMode === 'week') {
- model.value = [adapter.addDays(displayValue.value, -7)];
- }
- if (props.viewMode === 'day') {
- model.value = [adapter.addDays(displayValue.value, -1)];
- }
- }
- function onClickToday() {
- model.value = [adapter.date()];
- }
- const title = vue.computed(() => {
- return adapter.format(displayValue.value, 'monthAndYear');
- });
- useRender(() => {
- const calendarDayProps = VCalendarDay.filterProps(props);
- const calendarHeaderProps = VCalendarHeader.filterProps(props);
- return vue.createVNode("div", {
- "class": ['v-calendar', {
- 'v-calendar-monthly': props.viewMode === 'month',
- 'v-calendar-weekly': props.viewMode === 'week',
- 'v-calendar-day': props.viewMode === 'day'
- }]
- }, [vue.createVNode("div", null, [!props.hideHeader && (!slots.header ? vue.createVNode(VCalendarHeader, vue.mergeProps({
- "key": "calendar-header"
- }, calendarHeaderProps, {
- "title": title.value,
- "onClick:next": onClickNext,
- "onClick:prev": onClickPrev,
- "onClick:toToday": onClickToday
- }), null) : slots.header({
- title: title.value
- }))]), vue.createVNode("div", {
- "class": ['v-calendar__container', `days__${weekDays.value.length}`]
- }, [props.viewMode === 'month' && !props.hideDayHeader && vue.createVNode("div", {
- "class": ['v-calendar-weekly__head', `days__${weekDays.value.length}`, ...(!props.hideWeekNumber ? ['v-calendar-weekly__head-weeknumbers'] : [])],
- "key": "calenderWeeklyHead"
- }, [!props.hideWeekNumber ? vue.createVNode("div", {
- "key": "weekNumber0",
- "class": "v-calendar-weekly__head-weeknumber"
- }, null) : '', weekDays.value.map(weekday => vue.createVNode("div", {
- "class": `v-calendar-weekly__head-weekday${!props.hideWeekNumber ? '-with-weeknumber' : ''}`
- }, [dayNames[weekday]]))]), props.viewMode === 'month' && vue.createVNode("div", {
- "key": "VCalendarMonth",
- "class": ['v-calendar-month__days', `days${!props.hideWeekNumber ? '-with-weeknumbers' : ''}__${weekDays.value.length}`, ...(!props.hideWeekNumber ? ['v-calendar-month__weeknumbers'] : [])]
- }, [chunkArray(daysInMonth.value, weekDays.value.length).map((week, wi) => [!props.hideWeekNumber ? vue.createVNode("div", {
- "class": "v-calendar-month__weeknumber"
- }, [weekNumbers.value[wi]]) : '', week.map(day => vue.createVNode(VCalendarMonthDay, {
- "color": adapter.isSameDay(adapter.date(), day.date) ? 'primary' : undefined,
- "day": day,
- "title": day ? adapter.format(day.date, 'dayOfMonth') : 'NaN',
- "events": props.events?.filter(e => adapter.isSameDay(day.date, e.start) || adapter.isSameDay(day.date, e.end))
- }, {
- event: slots.event
- }))])]), props.viewMode === 'week' && daysInWeek.value.map((day, i) => vue.createVNode(VCalendarDay, vue.mergeProps(calendarDayProps, {
- "day": day,
- "dayIndex": i,
- "events": props.events?.filter(e => adapter.isSameDay(e.start, day.date) || adapter.isSameDay(e.end, day.date))
- }), null)), props.viewMode === 'day' && vue.createVNode(VCalendarDay, vue.mergeProps(calendarDayProps, {
- "day": genDays([displayValue.value], adapter.date())[0],
- "dayIndex": 0,
- "events": props.events?.filter(e => adapter.isSameDay(e.start, genDays([displayValue.value], adapter.date())[0].date) || adapter.isSameDay(e.end, genDays([displayValue.value], adapter.date())[0].date))
- }), null)])]);
- });
- return {
- daysInMonth,
- daysInWeek,
- genDays
- };
- }
- });
- // Types
- const makeVDateInputProps = propsFactory({
- hideActions: Boolean,
- ...makeFocusProps(),
- ...makeVConfirmEditProps(),
- ...makeVTextFieldProps({
- placeholder: 'mm/dd/yyyy',
- prependIcon: '$calendar'
- }),
- ...omit(makeVDatePickerProps({
- weeksInMonth: 'dynamic',
- hideHeader: true
- }), ['active'])
- }, 'VDateInput');
- const VDateInput = genericComponent()({
- name: 'VDateInput',
- props: makeVDateInputProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const adapter = useDate();
- const {
- isFocused,
- focus,
- blur
- } = useFocus(props);
- const model = useProxiedModel(props, 'modelValue', props.multiple ? [] : null);
- const menu = vue.shallowRef(false);
- const display = vue.computed(() => {
- const value = wrapInArray(model.value);
- if (!value.length) return null;
- if (props.multiple === true) {
- return t('$vuetify.datePicker.itemsSelected', value.length);
- }
- if (props.multiple === 'range') {
- const start = value[0];
- const end = value[value.length - 1];
- return adapter.isValid(start) && adapter.isValid(end) ? `${adapter.format(start, 'keyboardDate')} - ${adapter.format(end, 'keyboardDate')}` : '';
- }
- return adapter.isValid(model.value) ? adapter.format(model.value, 'keyboardDate') : '';
- });
- const isInteractive = vue.computed(() => !props.disabled && !props.readonly);
- function onKeydown(e) {
- if (e.key !== 'Enter') return;
- if (!menu.value || !isFocused.value) {
- menu.value = true;
- return;
- }
- const target = e.target;
- model.value = adapter.date(target.value);
- }
- function onClick(e) {
- e.preventDefault();
- e.stopPropagation();
- menu.value = true;
- }
- function onSave() {
- menu.value = false;
- }
- useRender(() => {
- const confirmEditProps = VConfirmEdit.filterProps(props);
- const datePickerProps = VDatePicker.filterProps(omit(props, ['active']));
- const textFieldProps = VTextField.filterProps(props);
- return vue.createVNode(VTextField, vue.mergeProps(textFieldProps, {
- "class": props.class,
- "style": props.style,
- "modelValue": display.value,
- "onKeydown": isInteractive.value ? onKeydown : undefined,
- "focused": menu.value || isFocused.value,
- "onFocus": focus,
- "onBlur": blur,
- "onClick:control": isInteractive.value ? onClick : undefined,
- "onClick:prepend": isInteractive.value ? onClick : undefined
- }), {
- default: () => [vue.createVNode(VMenu, {
- "modelValue": menu.value,
- "onUpdate:modelValue": $event => menu.value = $event,
- "activator": "parent",
- "min-width": "0",
- "closeOnContentClick": false,
- "openOnClick": false
- }, {
- default: () => [vue.createVNode(VConfirmEdit, vue.mergeProps(confirmEditProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "onSave": onSave
- }), {
- default: _ref2 => {
- let {
- actions,
- model: proxyModel
- } = _ref2;
- return vue.createVNode(VDatePicker, vue.mergeProps(datePickerProps, {
- "modelValue": props.hideActions ? model.value : proxyModel.value,
- "onUpdate:modelValue": val => {
- if (!props.hideActions) {
- proxyModel.value = val;
- } else {
- model.value = val;
- if (!props.multiple) menu.value = false;
- }
- },
- "onMousedown": e => e.preventDefault()
- }), {
- actions: !props.hideActions ? actions : undefined
- });
- }
- })]
- }), slots.default?.()]
- });
- });
- }
- });
- // Types
- const makeVFileUploadItemProps = propsFactory({
- clearable: Boolean,
- file: {
- type: Object,
- default: null
- },
- fileIcon: {
- type: String,
- // TODO: setup up a proper aliased icon
- default: 'mdi-file-document'
- },
- showSize: Boolean,
- ...makeVListItemProps({
- border: true,
- rounded: true,
- lines: 'two'
- })
- }, 'VFileUploadItem');
- const VFileUploadItem = genericComponent()({
- name: 'VFileUploadItem',
- props: makeVFileUploadItemProps(),
- emits: {
- 'click:remove': () => true,
- click: e => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const preview = vue.ref();
- const base = vue.computed(() => typeof props.showSize !== 'boolean' ? props.showSize : undefined);
- function onClickRemove() {
- emit('click:remove');
- }
- vue.watchEffect(() => {
- preview.value = props.file?.type.startsWith('image') ? URL.createObjectURL(props.file) : undefined;
- });
- useRender(() => {
- const listItemProps = VListItem.filterProps(props);
- return vue.createVNode(VListItem, vue.mergeProps(listItemProps, {
- "title": props.title ?? props.file?.name,
- "subtitle": props.showSize ? humanReadableFileSize(props.file?.size, base.value) : props.file?.type,
- "class": "v-file-upload-item"
- }), {
- ...slots,
- prepend: slotProps => vue.createVNode(vue.Fragment, null, [!slots.prepend ? vue.createVNode(VAvatar, {
- "icon": props.fileIcon,
- "image": preview.value,
- "rounded": true
- }, null) : vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VAvatar: {
- image: preview.value,
- icon: !preview.value ? props.fileIcon : undefined,
- rounded: true
- }
- }
- }, {
- default: () => [slots.prepend?.(slotProps) ?? vue.createVNode(VAvatar, null, null)]
- })]),
- append: slotProps => vue.createVNode(vue.Fragment, null, [props.clearable && vue.createVNode(vue.Fragment, null, [!slots.clear ? vue.createVNode(VBtn, {
- "icon": "$clear",
- "density": "comfortable",
- "variant": "text",
- "onClick": onClickRemove
- }, null) : vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- icon: '$clear',
- density: 'comfortable',
- variant: 'text'
- }
- }
- }, {
- default: () => [slots.clear?.({
- ...slotProps,
- props: {
- onClick: onClickRemove
- }
- }) ?? vue.createVNode(VBtn, null, null)]
- })]), slots.append?.(slotProps)])
- });
- });
- }
- });
- // Types
- const makeVFileUploadProps = propsFactory({
- browseText: {
- type: String,
- default: '$vuetify.fileUpload.browse'
- },
- dividerText: {
- type: String,
- default: '$vuetify.fileUpload.divider'
- },
- title: {
- type: String,
- default: '$vuetify.fileUpload.title'
- },
- subtitle: String,
- icon: {
- type: IconValue,
- default: '$upload'
- },
- modelValue: {
- type: [Array, Object],
- default: null,
- validator: val => {
- return wrapInArray(val).every(v => v != null && typeof v === 'object');
- }
- },
- clearable: Boolean,
- disabled: Boolean,
- hideBrowse: Boolean,
- multiple: Boolean,
- scrim: {
- type: [Boolean, String],
- default: true
- },
- showSize: Boolean,
- name: String,
- ...makeDelayProps(),
- ...makeDensityProps(),
- ...only(makeVDividerProps({
- length: 150
- }), ['length', 'thickness', 'opacity']),
- ...makeVSheetProps()
- }, 'VFileUpload');
- const VFileUpload = genericComponent()({
- name: 'VFileUpload',
- inheritAttrs: false,
- props: makeVFileUploadProps(),
- emits: {
- 'update:modelValue': files => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const {
- densityClasses
- } = useDensity(props);
- const model = useProxiedModel(props, 'modelValue', props.modelValue, val => wrapInArray(val), val => props.multiple || Array.isArray(props.modelValue) ? val : val[0]);
- const dragOver = vue.shallowRef(false);
- const vSheetRef = vue.ref(null);
- const inputRef = vue.ref(null);
- vue.onMounted(() => {
- vSheetRef.value?.$el.addEventListener('dragover', onDragOver);
- vSheetRef.value?.$el.addEventListener('drop', onDrop);
- });
- vue.onUnmounted(() => {
- vSheetRef.value?.$el.removeEventListener('dragover', onDragOver);
- vSheetRef.value?.$el.removeEventListener('drop', onDrop);
- });
- function onDragOver(e) {
- e.preventDefault();
- e.stopImmediatePropagation();
- dragOver.value = true;
- }
- function onDragLeave(e) {
- e.preventDefault();
- dragOver.value = false;
- }
- function onDrop(e) {
- e.preventDefault();
- e.stopImmediatePropagation();
- dragOver.value = false;
- const files = Array.from(e.dataTransfer?.files ?? []);
- if (!files.length) return;
- if (!props.multiple) {
- model.value = [files[0]];
- return;
- }
- const array = model.value.slice();
- for (const file of files) {
- if (!array.some(f => f.name === file.name)) {
- array.push(file);
- }
- }
- model.value = array;
- }
- function onClick() {
- inputRef.value?.click();
- }
- function onClickRemove(index) {
- model.value = model.value.filter((_, i) => i !== index);
- if (model.value.length > 0 || !inputRef.value) return;
- inputRef.value.value = '';
- }
- useRender(() => {
- const hasTitle = !!(slots.title || props.title);
- const hasIcon = !!(slots.icon || props.icon);
- const hasBrowse = !!(!props.hideBrowse && (slots.browse || props.density === 'default'));
- const cardProps = VSheet.filterProps(props);
- const dividerProps = VDivider.filterProps(props);
- const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
- const inputNode = vue.createVNode("input", vue.mergeProps({
- "ref": inputRef,
- "type": "file",
- "disabled": props.disabled,
- "multiple": props.multiple,
- "name": props.name,
- "onChange": e => {
- if (!e.target) return;
- const target = e.target;
- model.value = [...(target.files ?? [])];
- }
- }, inputAttrs), null);
- return vue.createVNode(vue.Fragment, null, [vue.createVNode(VSheet, vue.mergeProps({
- "ref": vSheetRef
- }, cardProps, {
- "class": ['v-file-upload', {
- 'v-file-upload--clickable': !hasBrowse,
- 'v-file-upload--disabled': props.disabled,
- 'v-file-upload--dragging': dragOver.value
- }, densityClasses.value],
- "onDragleave": onDragLeave,
- "onDragover": onDragOver,
- "onDrop": onDrop,
- "onClick": !hasBrowse ? onClick : undefined
- }, rootAttrs), {
- default: () => [hasIcon && vue.createVNode("div", {
- "key": "icon",
- "class": "v-file-upload-icon"
- }, [!slots.icon ? vue.createVNode(VIcon, {
- "key": "icon-icon",
- "icon": props.icon
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "icon-defaults",
- "defaults": {
- VIcon: {
- icon: props.icon
- }
- }
- }, {
- default: () => [slots.icon()]
- })]), hasTitle && vue.createVNode("div", {
- "key": "title",
- "class": "v-file-upload-title"
- }, [slots.title?.() ?? t(props.title)]), props.density === 'default' && vue.createVNode(vue.Fragment, null, [vue.createVNode("div", {
- "key": "upload-divider",
- "class": "v-file-upload-divider"
- }, [slots.divider?.() ?? vue.createVNode(VDivider, dividerProps, {
- default: () => [t(props.dividerText)]
- })]), hasBrowse && vue.createVNode(vue.Fragment, null, [!slots.browse ? vue.createVNode(VBtn, {
- "readonly": props.disabled,
- "size": "large",
- "text": t(props.browseText),
- "variant": "tonal",
- "onClick": onClick
- }, null) : vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- readonly: props.disabled,
- size: 'large',
- text: t(props.browseText),
- variant: 'tonal'
- }
- }
- }, {
- default: () => [slots.browse({
- props: {
- onClick
- }
- })]
- })]), props.subtitle && vue.createVNode("div", {
- "class": "v-file-upload-subtitle"
- }, [props.subtitle])]), vue.createVNode(VOverlay, {
- "model-value": dragOver.value,
- "contained": true,
- "scrim": props.scrim
- }, null), slots.input?.({
- inputNode
- }) ?? inputNode]
- }), model.value.length > 0 && vue.createVNode("div", {
- "class": "v-file-upload-items"
- }, [model.value.map((file, i) => {
- const slotProps = {
- file,
- props: {
- 'onClick:remove': () => onClickRemove(i)
- }
- };
- return vue.createVNode(VDefaultsProvider, {
- "key": i,
- "defaults": {
- VFileUploadItem: {
- file,
- clearable: props.clearable,
- disabled: props.disabled,
- showSize: props.showSize
- }
- }
- }, {
- default: () => [slots.item?.(slotProps) ?? vue.createVNode(VFileUploadItem, {
- "key": i,
- "onClick:remove": () => onClickRemove(i)
- }, slots)]
- });
- })])]);
- });
- }
- });
- // Types
- const makeVNumberInputProps = propsFactory({
- controlVariant: {
- type: String,
- default: 'default'
- },
- inset: Boolean,
- hideInput: Boolean,
- modelValue: {
- type: Number,
- default: null
- },
- min: {
- type: Number,
- default: Number.MIN_SAFE_INTEGER
- },
- max: {
- type: Number,
- default: Number.MAX_SAFE_INTEGER
- },
- step: {
- type: Number,
- default: 1
- },
- ...omit(makeVTextFieldProps({}), ['appendInnerIcon', 'modelValue', 'prependInnerIcon'])
- }, 'VNumberInput');
- const VNumberInput = genericComponent()({
- name: 'VNumberInput',
- props: {
- ...makeVNumberInputProps()
- },
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const _model = useProxiedModel(props, 'modelValue');
- const model = vue.computed({
- get: () => _model.value,
- // model.value could be empty string from VTextField
- // but _model.value should be eventually kept in type Number | null
- set(val) {
- if (val === null || val === '') {
- _model.value = null;
- return;
- }
- const value = Number(val);
- if (!isNaN(value) && value <= props.max && value >= props.min) {
- _model.value = value;
- }
- }
- });
- const vTextFieldRef = vue.ref();
- const stepDecimals = vue.computed(() => getDecimals(props.step));
- const modelDecimals = vue.computed(() => typeof model.value === 'number' ? getDecimals(model.value) : 0);
- const form = useForm(props);
- const controlsDisabled = vue.computed(() => form.isDisabled.value || form.isReadonly.value);
- const canIncrease = vue.computed(() => {
- if (controlsDisabled.value) return false;
- return (model.value ?? 0) + props.step <= props.max;
- });
- const canDecrease = vue.computed(() => {
- if (controlsDisabled.value) return false;
- return (model.value ?? 0) - props.step >= props.min;
- });
- const controlVariant = vue.computed(() => {
- return props.hideInput ? 'stacked' : props.controlVariant;
- });
- const incrementIcon = vue.computed(() => controlVariant.value === 'split' ? '$plus' : '$collapse');
- const decrementIcon = vue.computed(() => controlVariant.value === 'split' ? '$minus' : '$expand');
- const controlNodeSize = vue.computed(() => controlVariant.value === 'split' ? 'default' : 'small');
- const controlNodeDefaultHeight = vue.computed(() => controlVariant.value === 'stacked' ? 'auto' : '100%');
- const incrementSlotProps = vue.computed(() => ({
- click: onClickUp
- }));
- const decrementSlotProps = vue.computed(() => ({
- click: onClickDown
- }));
- vue.onMounted(() => {
- if (!controlsDisabled.value) {
- clampModel();
- }
- });
- function toggleUpDown() {
- let increment = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
- if (controlsDisabled.value) return;
- if (model.value == null) {
- model.value = clamp(0, props.min, props.max);
- return;
- }
- const decimals = Math.max(modelDecimals.value, stepDecimals.value);
- if (increment) {
- if (canIncrease.value) model.value = +(model.value + props.step).toFixed(decimals);
- } else {
- if (canDecrease.value) model.value = +(model.value - props.step).toFixed(decimals);
- }
- }
- function onClickUp(e) {
- e.stopPropagation();
- toggleUpDown();
- }
- function onClickDown(e) {
- e.stopPropagation();
- toggleUpDown(false);
- }
- function onBeforeinput(e) {
- if (!e.data) return;
- const existingTxt = e.target?.value;
- const selectionStart = e.target?.selectionStart;
- const selectionEnd = e.target?.selectionEnd;
- const potentialNewInputVal = existingTxt ? existingTxt.slice(0, selectionStart) + e.data + existingTxt.slice(selectionEnd) : e.data;
- // Only numbers, "-", "." are allowed
- // AND "-", "." are allowed only once
- // AND "-" is only allowed at the start
- if (!/^-?(\d+(\.\d*)?|(\.\d+)|\d*|\.)$/.test(potentialNewInputVal)) {
- e.preventDefault();
- }
- }
- async function onKeydown(e) {
- if (['Enter', 'ArrowLeft', 'ArrowRight', 'Backspace', 'Delete', 'Tab'].includes(e.key) || e.ctrlKey) return;
- if (['ArrowDown', 'ArrowUp'].includes(e.key)) {
- e.preventDefault();
- clampModel();
- // _model is controlled, so need to wait until props['modelValue'] is updated
- await vue.nextTick();
- if (e.key === 'ArrowDown') {
- toggleUpDown(false);
- } else {
- toggleUpDown();
- }
- }
- }
- function onControlMousedown(e) {
- e.stopPropagation();
- }
- function clampModel() {
- if (!vTextFieldRef.value) return;
- const inputText = vTextFieldRef.value.value;
- if (inputText && !isNaN(+inputText)) {
- model.value = clamp(+inputText, props.min, props.max);
- } else {
- model.value = null;
- }
- }
- useRender(() => {
- const {
- modelValue: _,
- ...textFieldProps
- } = VTextField.filterProps(props);
- function incrementControlNode() {
- return !slots.increment ? vue.createVNode(VBtn, {
- "disabled": !canIncrease.value,
- "flat": true,
- "key": "increment-btn",
- "height": controlNodeDefaultHeight.value,
- "data-testid": "increment",
- "aria-hidden": "true",
- "icon": incrementIcon.value,
- "onClick": onClickUp,
- "onMousedown": onControlMousedown,
- "size": controlNodeSize.value,
- "tabindex": "-1"
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "increment-defaults",
- "defaults": {
- VBtn: {
- disabled: !canIncrease.value,
- flat: true,
- height: controlNodeDefaultHeight.value,
- size: controlNodeSize.value,
- icon: incrementIcon.value
- }
- }
- }, {
- default: () => [slots.increment(incrementSlotProps.value)]
- });
- }
- function decrementControlNode() {
- return !slots.decrement ? vue.createVNode(VBtn, {
- "disabled": !canDecrease.value,
- "flat": true,
- "key": "decrement-btn",
- "height": controlNodeDefaultHeight.value,
- "data-testid": "decrement",
- "aria-hidden": "true",
- "icon": decrementIcon.value,
- "size": controlNodeSize.value,
- "tabindex": "-1",
- "onClick": onClickDown,
- "onMousedown": onControlMousedown
- }, null) : vue.createVNode(VDefaultsProvider, {
- "key": "decrement-defaults",
- "defaults": {
- VBtn: {
- disabled: !canDecrease.value,
- flat: true,
- height: controlNodeDefaultHeight.value,
- size: controlNodeSize.value,
- icon: decrementIcon.value
- }
- }
- }, {
- default: () => [slots.decrement(decrementSlotProps.value)]
- });
- }
- function controlNode() {
- return vue.createVNode("div", {
- "class": "v-number-input__control"
- }, [decrementControlNode(), vue.createVNode(VDivider, {
- "vertical": controlVariant.value !== 'stacked'
- }, null), incrementControlNode()]);
- }
- function dividerNode() {
- return !props.hideInput && !props.inset ? vue.createVNode(VDivider, {
- "vertical": true
- }, null) : undefined;
- }
- const appendInnerControl = controlVariant.value === 'split' ? vue.createVNode("div", {
- "class": "v-number-input__control"
- }, [vue.createVNode(VDivider, {
- "vertical": true
- }, null), incrementControlNode()]) : props.reverse ? undefined : vue.createVNode(vue.Fragment, null, [dividerNode(), controlNode()]);
- const hasAppendInner = slots['append-inner'] || appendInnerControl;
- const prependInnerControl = controlVariant.value === 'split' ? vue.createVNode("div", {
- "class": "v-number-input__control"
- }, [decrementControlNode(), vue.createVNode(VDivider, {
- "vertical": true
- }, null)]) : props.reverse ? vue.createVNode(vue.Fragment, null, [controlNode(), dividerNode()]) : undefined;
- const hasPrependInner = slots['prepend-inner'] || prependInnerControl;
- return vue.createVNode(VTextField, vue.mergeProps({
- "ref": vTextFieldRef,
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "onBeforeinput": onBeforeinput,
- "onChange": clampModel,
- "onKeydown": onKeydown,
- "class": ['v-number-input', {
- 'v-number-input--default': controlVariant.value === 'default',
- 'v-number-input--hide-input': props.hideInput,
- 'v-number-input--inset': props.inset,
- 'v-number-input--reverse': props.reverse,
- 'v-number-input--split': controlVariant.value === 'split',
- 'v-number-input--stacked': controlVariant.value === 'stacked'
- }, props.class]
- }, textFieldProps, {
- "style": props.style,
- "inputmode": "decimal"
- }), {
- ...slots,
- 'append-inner': hasAppendInner ? 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), appendInnerControl]);
- } : undefined,
- 'prepend-inner': hasPrependInner ? function () {
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
- args[_key2] = arguments[_key2];
- }
- return vue.createVNode(vue.Fragment, null, [prependInnerControl, slots['prepend-inner']?.(...args)]);
- } : undefined
- });
- });
- return forwardRefs({}, vTextFieldRef);
- }
- });
- // Types
- const makeVStepperVerticalActionsProps = propsFactory({
- ...makeVStepperActionsProps()
- }, 'VStepperActions');
- const VStepperVerticalActions = genericComponent()({
- name: 'VStepperVerticalActions',
- props: makeVStepperVerticalActionsProps(),
- emits: {
- 'click:prev': () => true,
- 'click:next': () => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- function onClickPrev() {
- emit('click:prev');
- }
- function onClickNext() {
- emit('click:next');
- }
- useRender(() => {
- const stepperActionsProps = VStepperActions.filterProps(props);
- return vue.createVNode(VStepperActions, vue.mergeProps({
- "class": "v-stepper-vertical-actions"
- }, stepperActionsProps, {
- "onClick:prev": onClickPrev,
- "onClick:next": onClickNext
- }), slots);
- });
- return {};
- }
- });
- // Types
- const makeVStepperVerticalItemProps = propsFactory({
- hideActions: Boolean,
- ...makeStepperItemProps(),
- ...omit(makeVExpansionPanelProps({
- expandIcon: '',
- collapseIcon: ''
- }), ['hideActions'])
- }, 'VStepperVerticalItem');
- const VStepperVerticalItem = genericComponent()({
- name: 'VStepperVerticalItem',
- props: makeVStepperVerticalItemProps(),
- emits: {
- 'click:next': () => true,
- 'click:prev': () => true,
- 'click:finish': () => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const vExpansionPanelRef = vue.ref();
- const step = vue.computed(() => !isNaN(parseInt(props.value)) ? Number(props.value) : props.value);
- const groupItem = vue.computed(() => vExpansionPanelRef.value?.groupItem);
- const isSelected = vue.computed(() => groupItem.value?.isSelected.value ?? false);
- const isValid = vue.computed(() => isSelected.value ? props.rules.every(handler => handler() === true) : null);
- const canEdit = vue.computed(() => !props.disabled && props.editable);
- const hasError = vue.computed(() => props.error || isSelected.value && !isValid.value);
- const hasCompleted = vue.computed(() => props.complete || props.rules.length > 0 && isValid.value === true);
- const disabled = vue.computed(() => {
- if (props.disabled) return props.disabled;
- if (groupItem.value?.isFirst.value) return 'prev';
- return false;
- });
- const icon = vue.computed(() => {
- if (hasError.value) return props.errorIcon;
- if (hasCompleted.value) return props.completeIcon;
- if (groupItem.value?.isSelected.value && props.editable) return props.editIcon;
- return props.icon;
- });
- const slotProps = vue.computed(() => ({
- canEdit: canEdit.value,
- hasError: hasError.value,
- hasCompleted: hasCompleted.value,
- title: props.title,
- subtitle: props.subtitle,
- step: step.value,
- value: props.value
- }));
- const actionProps = vue.computed(() => ({
- ...slotProps.value,
- prev: onClickPrev,
- next: onClickNext
- }));
- function onClickNext() {
- emit('click:next');
- if (groupItem.value?.isLast.value) return;
- groupItem.value.group.next();
- }
- function onClickPrev() {
- emit('click:prev');
- groupItem.value.group.prev();
- }
- useRender(() => {
- const hasColor = (hasCompleted.value || groupItem.value?.isSelected.value) && !hasError.value && !props.disabled;
- const hasActions = !props.hideActions || !!slots.actions;
- const expansionPanelProps = VExpansionPanel.filterProps(props);
- return vue.createVNode(VExpansionPanel, vue.mergeProps({
- "_as": "VStepperVerticalItem",
- "ref": vExpansionPanelRef
- }, expansionPanelProps, {
- "class": ['v-stepper-vertical-item', {
- 'v-stepper-vertical-item--complete': hasCompleted.value,
- 'v-stepper-vertical-item--disabled': props.disabled,
- 'v-stepper-vertical-item--editable': canEdit.value,
- 'v-stepper-vertical-item--error': hasError.value
- }, props.class],
- "readonly": !props.editable,
- "style": props.style,
- "color": "",
- "hide-actions": false,
- "value": step.value
- }), {
- title: () => vue.createVNode(vue.Fragment, null, [vue.createVNode(VAvatar, {
- "key": "stepper-avatar",
- "class": "v-stepper-vertical-item__avatar",
- "color": hasColor ? props.color : undefined,
- "size": 24,
- "start": true
- }, {
- default: () => [slots.icon?.(slotProps.value) ?? (icon.value ? vue.createVNode(VIcon, {
- "icon": icon.value
- }, null) : step.value)]
- }), vue.createVNode("div", null, [vue.createVNode("div", {
- "class": "v-stepper-vertical-item__title"
- }, [slots.title?.(slotProps.value) ?? props.title]), vue.createVNode("div", {
- "class": "v-stepper-vertical-item__subtitle"
- }, [slots.subtitle?.(slotProps.value) ?? props.subtitle])])]),
- text: () => vue.createVNode(vue.Fragment, null, [slots.default?.(slotProps.value) ?? props.text, hasActions && vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VStepperVerticalActions: {
- disabled: disabled.value,
- finish: groupItem.value?.isLast.value
- }
- }
- }, {
- default: () => [slots.actions?.(actionProps.value) ?? vue.createVNode(VStepperVerticalActions, {
- "onClick:next": onClickNext,
- "onClick:prev": onClickPrev
- }, {
- prev: slots.prev ? () => slots.prev?.(actionProps.value) : undefined,
- next: slots.next ? () => slots.next?.(actionProps.value) : undefined
- })]
- })])
- });
- });
- return {};
- }
- });
- // Types
- const makeVStepperVerticalProps = propsFactory({
- prevText: {
- type: String,
- default: '$vuetify.stepper.prev'
- },
- nextText: {
- type: String,
- default: '$vuetify.stepper.next'
- },
- ...makeStepperProps(),
- ...omit(makeVExpansionPanelsProps({
- mandatory: 'force',
- variant: 'accordion'
- }), ['static'])
- }, 'VStepperVertical');
- const VStepperVertical = genericComponent()({
- name: 'VStepperVertical',
- props: makeVStepperVerticalProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const vExpansionPanelsRef = vue.ref();
- const {
- color,
- eager,
- editable,
- prevText,
- nextText,
- hideActions
- } = vue.toRefs(props);
- const model = useProxiedModel(props, 'modelValue');
- const items = vue.computed(() => props.items.map((item, index) => {
- const title = getPropertyFromItem(item, props.itemTitle, item);
- const value = getPropertyFromItem(item, props.itemValue, index + 1);
- return {
- title,
- value,
- raw: item
- };
- }));
- provideDefaults({
- VStepperVerticalItem: {
- color,
- eager,
- editable,
- prevText,
- nextText,
- hideActions,
- static: true
- },
- VStepperActions: {
- color
- }
- });
- useRender(() => {
- const expansionPanelProps = VExpansionPanels.filterProps(props);
- return vue.createVNode(VExpansionPanels, vue.mergeProps(expansionPanelProps, {
- "modelValue": model.value,
- "onUpdate:modelValue": $event => model.value = $event,
- "ref": vExpansionPanelsRef,
- "class": ['v-stepper', {
- 'v-stepper--alt-labels': props.altLabels,
- 'v-stepper--flat': props.flat,
- 'v-stepper--non-linear': props.nonLinear,
- 'v-stepper--mobile': props.mobile
- }, props.class],
- "style": props.style
- }), {
- ...slots,
- default: _ref2 => {
- let {
- prev,
- next
- } = _ref2;
- return vue.createVNode(vue.Fragment, null, [items.value.map(_ref3 => {
- let {
- raw,
- ...item
- } = _ref3;
- return vue.createVNode(VStepperVerticalItem, item, {
- ...slots,
- default: slots[`item.${item.value}`]
- });
- }), slots.default?.({
- prev,
- next,
- step: model.value
- })]);
- }
- });
- });
- return {};
- }
- });
- const VPullToRefresh = genericComponent()({
- name: 'VPullToRefresh',
- props: {
- disabled: Boolean,
- pullDownThreshold: {
- type: Number,
- default: 64
- }
- },
- emits: {
- load: options => true
- },
- setup(props, _ref) {
- let {
- slots,
- emit
- } = _ref;
- let touchstartY = 0;
- let scrollParents = [];
- const touchDiff = vue.shallowRef(0);
- const containerRef = vue.ref();
- const refreshing = vue.shallowRef(false);
- const goingUp = vue.shallowRef(false);
- const touching = vue.shallowRef(false);
- const canRefresh = vue.computed(() => touchDiff.value >= props.pullDownThreshold && !refreshing.value);
- const topOffset = vue.computed(() => clamp(touchDiff.value, 0, props.pullDownThreshold));
- function onTouchstart(e) {
- if (refreshing.value || props.disabled) return;
- touching.value = true;
- touchstartY = 'clientY' in e ? e.clientY : e.touches[0].clientY;
- }
- function onTouchmove(e) {
- if (refreshing.value || !touching.value || props.disabled) return;
- const touchY = 'clientY' in e ? e.clientY : e.touches[0].clientY;
- if (scrollParents.length && !scrollParents[0].scrollTop) {
- touchDiff.value = touchY - touchstartY;
- }
- }
- function onTouchend(e) {
- if (refreshing.value || props.disabled) return;
- touching.value = false;
- if (canRefresh.value) {
- function done() {
- if (!refreshing.value) return;
- touchDiff.value = 0;
- refreshing.value = false;
- }
- emit('load', {
- done
- });
- refreshing.value = true;
- } else {
- touchDiff.value = 0;
- }
- }
- vue.onMounted(() => {
- scrollParents = getScrollParents(containerRef.value);
- });
- vue.watch([topOffset, refreshing], () => {
- if (scrollParents.length) {
- const stopScrolling = topOffset.value && !refreshing.value;
- scrollParents.forEach(p => p.style.overflow = stopScrolling ? 'hidden' : 'auto');
- }
- });
- vue.watch(topOffset, (newVal, oldVal) => {
- goingUp.value = newVal < oldVal;
- });
- useRender(() => {
- return vue.createVNode("div", {
- "class": ['v-pull-to-refresh'],
- "onTouchstart": onTouchstart,
- "onTouchmove": onTouchmove,
- "onTouchend": onTouchend,
- "onMousedown": onTouchstart,
- "onMouseup": onTouchend,
- "onMouseleave": onTouchend,
- "onMousemove": onTouchmove,
- "ref": containerRef
- }, [vue.createVNode("div", {
- "class": ['v-pull-to-refresh__pull-down', {
- 'v-pull-to-refresh__pull-down--touching': touching.value
- }],
- "style": {
- top: convertToUnit(-1 * props.pullDownThreshold + topOffset.value),
- height: convertToUnit(props.pullDownThreshold)
- }
- }, [slots.pullDownPanel ? slots.pullDownPanel({
- canRefresh: canRefresh.value,
- goingUp: goingUp.value,
- refreshing: refreshing.value
- }) : vue.createVNode("div", {
- "class": ['v-pull-to-refresh__pull-down-default']
- }, [refreshing.value ? vue.createVNode(VProgressCircular, {
- "indeterminate": true,
- "active": false
- }, null) : vue.createVNode(VIcon, {
- "icon": canRefresh.value || goingUp.value ? '$sortAsc' : '$sortDesc'
- }, null)])]), vue.createVNode("div", {
- "class": ['v-pull-to-refresh__scroll-container', {
- 'v-pull-to-refresh__scroll-container--touching': touching.value
- }],
- "style": {
- top: convertToUnit(topOffset.value)
- }
- }, [slots.default?.()])]);
- });
- }
- });
- // Types
- const makeVSnackbarQueueProps = propsFactory({
- // TODO: Port this to Snackbar on dev
- closable: [Boolean, String],
- closeText: {
- type: String,
- default: '$vuetify.dismiss'
- },
- modelValue: {
- type: Array,
- default: () => []
- },
- ...omit(makeVSnackbarProps(), ['modelValue'])
- }, 'VSnackbarQueue');
- const VSnackbarQueue = genericComponent()({
- name: 'VSnackbarQueue',
- props: makeVSnackbarQueueProps(),
- emits: {
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const isActive = vue.shallowRef(false);
- const isVisible = vue.shallowRef(false);
- const current = vue.shallowRef();
- vue.watch(() => props.modelValue.length, (val, oldVal) => {
- if (!isVisible.value && val > oldVal) {
- showNext();
- }
- });
- vue.watch(isActive, val => {
- if (val) isVisible.value = true;
- });
- function onAfterLeave() {
- if (props.modelValue.length) {
- showNext();
- } else {
- current.value = undefined;
- isVisible.value = false;
- }
- }
- function showNext() {
- const [next, ...rest] = props.modelValue;
- emit('update:modelValue', rest);
- current.value = typeof next === 'string' ? {
- text: next
- } : next;
- vue.nextTick(() => {
- isActive.value = true;
- });
- }
- function onClickClose() {
- isActive.value = false;
- }
- const btnProps = vue.computed(() => ({
- color: typeof props.closable === 'string' ? props.closable : undefined,
- text: t(props.closeText)
- }));
- useRender(() => {
- const hasActions = !!(props.closable || slots.actions);
- const {
- modelValue: _,
- ...snackbarProps
- } = VSnackbar.filterProps(props);
- return vue.createVNode(vue.Fragment, null, [isVisible.value && !!current.value && (slots.default ? vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VSnackbar: current.value
- }
- }, {
- default: () => [slots.default({
- item: current.value
- })]
- }) : vue.createVNode(VSnackbar, vue.mergeProps(snackbarProps, current.value, {
- "modelValue": isActive.value,
- "onUpdate:modelValue": $event => isActive.value = $event,
- "onAfterLeave": onAfterLeave
- }), {
- text: slots.text ? () => slots.text?.({
- item: current.value
- }) : undefined,
- actions: hasActions ? () => vue.createVNode(vue.Fragment, null, [!slots.actions ? vue.createVNode(VBtn, vue.mergeProps(btnProps.value, {
- "onClick": onClickClose
- }), null) : vue.createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: btnProps.value
- }
- }, {
- default: () => [slots.actions({
- item: current.value,
- props: {
- onClick: onClickClose
- }
- })]
- })]) : undefined
- }))]);
- });
- }
- });
- function pad(n) {
- let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2;
- return String(n).padStart(length, '0');
- }
- // Types
- const makeVTimePickerClockProps = propsFactory({
- allowedValues: Function,
- ampm: Boolean,
- color: String,
- disabled: Boolean,
- displayedValue: null,
- double: Boolean,
- format: {
- type: Function,
- default: val => val
- },
- max: {
- type: Number,
- required: true
- },
- min: {
- type: Number,
- required: true
- },
- scrollable: Boolean,
- readonly: Boolean,
- rotate: {
- type: Number,
- default: 0
- },
- step: {
- type: Number,
- default: 1
- },
- modelValue: {
- type: Number
- }
- }, 'VTimePickerClock');
- const VTimePickerClock = genericComponent()({
- name: 'VTimePickerClock',
- props: makeVTimePickerClockProps(),
- emits: {
- change: val => true,
- input: val => true
- },
- setup(props, _ref) {
- let {
- emit
- } = _ref;
- const clockRef = vue.ref(null);
- const innerClockRef = vue.ref(null);
- const inputValue = vue.ref(undefined);
- const isDragging = vue.ref(false);
- const valueOnMouseDown = vue.ref(null);
- const valueOnMouseUp = vue.ref(null);
- const {
- textColorClasses,
- textColorStyles
- } = useTextColor(vue.toRef(props, 'color'));
- const {
- backgroundColorClasses,
- backgroundColorStyles
- } = useBackgroundColor(vue.toRef(props, 'color'));
- const count = vue.computed(() => props.max - props.min + 1);
- const roundCount = vue.computed(() => props.double ? count.value / 2 : count.value);
- const degreesPerUnit = vue.computed(() => 360 / roundCount.value);
- const degrees = vue.computed(() => degreesPerUnit.value * Math.PI / 180);
- const displayedValue = vue.computed(() => props.modelValue == null ? props.min : props.modelValue);
- const innerRadiusScale = vue.computed(() => 0.62);
- const genChildren = vue.computed(() => {
- const children = [];
- for (let value = props.min; value <= props.max; value = value + props.step) {
- children.push(value);
- }
- return children;
- });
- vue.watch(() => props.modelValue, val => {
- inputValue.value = val;
- });
- function update(value) {
- if (inputValue.value !== value) {
- inputValue.value = value;
- }
- emit('input', value);
- }
- function isAllowed(value) {
- return !props.allowedValues || props.allowedValues(value);
- }
- function wheel(e) {
- if (!props.scrollable || props.disabled) return;
- e.preventDefault();
- const delta = Math.sign(-e.deltaY || 1);
- let value = displayedValue.value;
- do {
- value = value + delta;
- value = (value - props.min + count.value) % count.value + props.min;
- } while (!isAllowed(value) && value !== displayedValue.value);
- if (value !== props.displayedValue) {
- update(value);
- }
- }
- function isInner(value) {
- return props.double && value - props.min >= roundCount.value;
- }
- function handScale(value) {
- return isInner(value) ? innerRadiusScale.value : 1;
- }
- function getPosition(value) {
- const rotateRadians = props.rotate * Math.PI / 180;
- return {
- x: Math.sin((value - props.min) * degrees.value + rotateRadians) * handScale(value),
- y: -Math.cos((value - props.min) * degrees.value + rotateRadians) * handScale(value)
- };
- }
- function angleToValue(angle, insideClick) {
- const value = (Math.round(angle / degreesPerUnit.value) + (insideClick ? roundCount.value : 0)) % count.value + props.min;
- // Necessary to fix edge case when selecting left part of the value(s) at 12 o'clock
- if (angle < 360 - degreesPerUnit.value / 2) return value;
- return insideClick ? props.max - roundCount.value + 1 : props.min;
- }
- function getTransform(i) {
- const {
- x,
- y
- } = getPosition(i);
- return {
- left: `${50 + x * 50}%`,
- top: `${50 + y * 50}%`
- };
- }
- function euclidean(p0, p1) {
- const dx = p1.x - p0.x;
- const dy = p1.y - p0.y;
- return Math.sqrt(dx * dx + dy * dy);
- }
- function angle(center, p1) {
- const value = 2 * Math.atan2(p1.y - center.y - euclidean(center, p1), p1.x - center.x);
- return Math.abs(value * 180 / Math.PI);
- }
- function setMouseDownValue(value) {
- if (valueOnMouseDown.value === null) {
- valueOnMouseDown.value = value;
- }
- valueOnMouseUp.value = value;
- update(value);
- }
- function onDragMove(e) {
- e.preventDefault();
- if (!isDragging.value && e.type !== 'click' || !clockRef.value) return;
- const {
- width,
- top,
- left
- } = clockRef.value?.getBoundingClientRect();
- const {
- width: innerWidth
- } = innerClockRef.value?.getBoundingClientRect() ?? {
- width: 0
- };
- const {
- clientX,
- clientY
- } = 'touches' in e ? e.touches[0] : e;
- const center = {
- x: width / 2,
- y: -width / 2
- };
- const coords = {
- x: clientX - left,
- y: top - clientY
- };
- const handAngle = Math.round(angle(center, coords) - props.rotate + 360) % 360;
- const insideClick = props.double && euclidean(center, coords) < (innerWidth + innerWidth * innerRadiusScale.value) / 4;
- const checksCount = Math.ceil(15 / degreesPerUnit.value);
- let value;
- for (let i = 0; i < checksCount; i++) {
- value = angleToValue(handAngle + i * degreesPerUnit.value, insideClick);
- if (isAllowed(value)) return setMouseDownValue(value);
- value = angleToValue(handAngle - i * degreesPerUnit.value, insideClick);
- if (isAllowed(value)) return setMouseDownValue(value);
- }
- }
- function onMouseDown(e) {
- if (props.disabled) return;
- e.preventDefault();
- window.addEventListener('mousemove', onDragMove);
- window.addEventListener('touchmove', onDragMove);
- window.addEventListener('mouseup', onMouseUp);
- window.addEventListener('touchend', onMouseUp);
- valueOnMouseDown.value = null;
- valueOnMouseUp.value = null;
- isDragging.value = true;
- onDragMove(e);
- }
- function onMouseUp(e) {
- e.stopPropagation();
- window.removeEventListener('mousemove', onDragMove);
- window.removeEventListener('touchmove', onDragMove);
- window.removeEventListener('mouseup', onMouseUp);
- window.removeEventListener('touchend', onMouseUp);
- isDragging.value = false;
- if (valueOnMouseUp.value !== null && isAllowed(valueOnMouseUp.value)) {
- emit('change', valueOnMouseUp.value);
- }
- }
- useRender(() => {
- return vue.createVNode("div", {
- "class": [{
- 'v-time-picker-clock': true,
- 'v-time-picker-clock--indeterminate': props.modelValue == null,
- 'v-time-picker-clock--readonly': props.readonly
- }],
- "onMousedown": onMouseDown,
- "onTouchstart": onMouseDown,
- "onWheel": wheel,
- "ref": clockRef
- }, [vue.createVNode("div", {
- "class": "v-time-picker-clock__inner",
- "ref": innerClockRef
- }, [vue.createVNode("div", {
- "class": [{
- 'v-time-picker-clock__hand': true,
- 'v-time-picker-clock__hand--inner': isInner(props.modelValue)
- }, textColorClasses.value],
- "style": [{
- transform: `rotate(${props.rotate + degreesPerUnit.value * (displayedValue.value - props.min)}deg) scaleY(${handScale(displayedValue.value)})`
- }, textColorStyles.value]
- }, null), genChildren.value.map(value => {
- const isActive = value === displayedValue.value;
- return vue.createVNode("div", {
- "class": [{
- 'v-time-picker-clock__item': true,
- 'v-time-picker-clock__item--active': isActive,
- 'v-time-picker-clock__item--disabled': props.disabled || !isAllowed(value)
- }, isActive && backgroundColorClasses.value],
- "style": [getTransform(value), isActive && backgroundColorStyles.value]
- }, [vue.createVNode("span", null, [props.format(value)])]);
- })])]);
- });
- }
- });
- // @ts-nocheck
- /* eslint-disable */
- var SelectingTimes = /*#__PURE__*/function (SelectingTimes) {
- SelectingTimes[SelectingTimes["Hour"] = 1] = "Hour";
- SelectingTimes[SelectingTimes["Minute"] = 2] = "Minute";
- SelectingTimes[SelectingTimes["Second"] = 3] = "Second";
- return SelectingTimes;
- }(SelectingTimes || {});
- const makeVTimePickerControlsProps = propsFactory({
- ampm: Boolean,
- ampmInTitle: Boolean,
- ampmReadonly: Boolean,
- color: String,
- disabled: Boolean,
- hour: Number,
- minute: Number,
- second: Number,
- period: String,
- readonly: Boolean,
- useSeconds: Boolean,
- selecting: Number,
- value: Number
- }, 'VTimePickerControls');
- const VTimePickerControls = genericComponent()({
- name: 'VTimePickerControls',
- props: makeVTimePickerControlsProps(),
- emits: {
- 'update:period': data => true,
- 'update:selecting': data => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- useRender(() => {
- let hour = props.hour;
- if (props.ampm) {
- hour = hour ? (hour - 1) % 12 + 1 : 12;
- }
- return vue.createVNode("div", {
- "class": "v-time-picker-controls"
- }, [vue.createVNode("div", {
- "class": {
- 'v-time-picker-controls__time': true,
- 'v-time-picker-controls__time--with-seconds': props.useSeconds
- }
- }, [vue.createVNode(VBtn, {
- "active": props.selecting === 1,
- "color": props.selecting === 1 ? props.color : undefined,
- "disabled": props.disabled,
- "variant": "tonal",
- "class": {
- 'v-time-picker-controls__time__btn': true,
- 'v-time-picker-controls__time--with-ampm__btn': props.ampm,
- 'v-time-picker-controls__time--with-seconds__btn': props.useSeconds
- },
- "text": props.hour == null ? '--' : pad(`${hour}`),
- "onClick": () => emit('update:selecting', SelectingTimes.Hour)
- }, null), vue.createVNode("span", {
- "class": ['v-time-picker-controls__time__separator', {
- 'v-time-picker-controls--with-seconds__time__separator': props.useSeconds
- }]
- }, [vue.createTextVNode(":")]), vue.createVNode(VBtn, {
- "active": props.selecting === 2,
- "color": props.selecting === 2 ? props.color : undefined,
- "class": {
- 'v-time-picker-controls__time__btn': true,
- 'v-time-picker-controls__time__btn__active': props.selecting === 2,
- 'v-time-picker-controls__time--with-ampm__btn': props.ampm,
- 'v-time-picker-controls__time--with-seconds__btn': props.useSeconds
- },
- "disabled": props.disabled,
- "variant": "tonal",
- "text": props.minute == null ? '--' : pad(props.minute),
- "onClick": () => emit('update:selecting', SelectingTimes.Minute)
- }, null), props.useSeconds && vue.createVNode("span", {
- "class": ['v-time-picker-controls__time__separator', {
- 'v-time-picker-controls--with-seconds__time__separator': props.useSeconds
- }],
- "key": "secondsDivider"
- }, [vue.createTextVNode(":")]), props.useSeconds && vue.createVNode(VBtn, {
- "key": "secondsVal",
- "variant": "tonal",
- "onClick": () => emit('update:selecting', SelectingTimes.Second),
- "class": {
- 'v-time-picker-controls__time__btn': true,
- 'v-time-picker-controls__time__btn__active': props.selecting === 3,
- 'v-time-picker-controls__time--with-seconds__btn': props.useSeconds
- },
- "disabled": props.disabled,
- "text": props.second == null ? '--' : pad(props.second)
- }, null), props.ampm && props.ampmInTitle && vue.createVNode("div", {
- "class": ['v-time-picker-controls__ampm', {
- 'v-time-picker-controls__ampm--readonly': props.ampmReadonly
- }]
- }, [vue.createVNode(VBtn, {
- "active": props.period === 'am',
- "color": props.period === 'am' ? props.color : undefined,
- "class": {
- 'v-time-picker-controls__ampm__am': true,
- 'v-time-picker-controls__ampm__btn': true,
- 'v-time-picker-controls__ampm__btn__active': props.period === 'am'
- },
- "disabled": props.disabled,
- "text": t('$vuetify.timePicker.am'),
- "variant": props.disabled && props.period === 'am' ? 'elevated' : 'tonal',
- "onClick": () => props.period !== 'am' ? emit('update:period', 'am') : null
- }, null), vue.createVNode(VBtn, {
- "active": props.period === 'pm',
- "color": props.period === 'pm' ? props.color : undefined,
- "class": {
- 'v-time-picker-controls__ampm__pm': true,
- 'v-time-picker-controls__ampm__btn': true,
- 'v-time-picker-controls__ampm__btn__active': props.period === 'pm'
- },
- "disabled": props.disabled,
- "text": t('$vuetify.timePicker.pm'),
- "variant": props.disabled && props.period === 'pm' ? 'elevated' : 'tonal',
- "onClick": () => props.period !== 'pm' ? emit('update:period', 'pm') : null
- }, null)])])]);
- });
- return {};
- }
- });
- // Types
- const rangeHours24 = createRange(24);
- const rangeHours12am = createRange(12);
- const rangeHours12pm = rangeHours12am.map(v => v + 12);
- const range60 = createRange(60);
- const selectingNames = {
- 1: 'hour',
- 2: 'minute',
- 3: 'second'
- };
- const makeVTimePickerProps = propsFactory({
- allowedHours: [Function, Array],
- allowedMinutes: [Function, Array],
- allowedSeconds: [Function, Array],
- ampmInTitle: Boolean,
- disabled: Boolean,
- format: {
- type: String,
- default: 'ampm'
- },
- max: String,
- min: String,
- modelValue: null,
- readonly: Boolean,
- scrollable: Boolean,
- useSeconds: Boolean,
- ...omit(makeVPickerProps({
- title: '$vuetify.timePicker.title'
- }), ['landscape'])
- }, 'VTimePicker');
- const VTimePicker = genericComponent()({
- name: 'VTimePicker',
- props: makeVTimePickerProps(),
- emits: {
- 'update:hour': val => true,
- 'update:minute': val => true,
- 'update:period': val => true,
- 'update:second': val => true,
- 'update:modelValue': val => true
- },
- setup(props, _ref) {
- let {
- emit,
- slots
- } = _ref;
- const {
- t
- } = useLocale();
- const inputHour = vue.ref(null);
- const inputMinute = vue.ref(null);
- const inputSecond = vue.ref(null);
- const lazyInputHour = vue.ref(null);
- const lazyInputMinute = vue.ref(null);
- const lazyInputSecond = vue.ref(null);
- const period = vue.ref('am');
- const selecting = vue.ref(SelectingTimes.Hour);
- const controlsRef = vue.ref(null);
- const clockRef = vue.ref(null);
- const isAllowedHourCb = vue.computed(() => {
- let cb;
- if (props.allowedHours instanceof Array) {
- cb = val => props.allowedHours.includes(val);
- } else {
- cb = props.allowedHours;
- }
- if (!props.min && !props.max) return cb;
- const minHour = props.min ? Number(props.min.split(':')[0]) : 0;
- const maxHour = props.max ? Number(props.max.split(':')[0]) : 23;
- return val => {
- return val >= minHour * 1 && val <= maxHour * 1 && (!cb || cb(val));
- };
- });
- const isAllowedMinuteCb = vue.computed(() => {
- let cb;
- const isHourAllowed = !isAllowedHourCb.value || inputHour.value === null || isAllowedHourCb.value(inputHour.value);
- if (props.allowedMinutes instanceof Array) {
- cb = val => props.allowedMinutes.includes(val);
- } else {
- cb = props.allowedMinutes;
- }
- if (!props.min && !props.max) {
- return isHourAllowed ? cb : () => false;
- }
- const [minHour, minMinute] = props.min ? props.min.split(':').map(Number) : [0, 0];
- const [maxHour, maxMinute] = props.max ? props.max.split(':').map(Number) : [23, 59];
- const minTime = minHour * 60 + minMinute * 1;
- const maxTime = maxHour * 60 + maxMinute * 1;
- return val => {
- const time = 60 * inputHour.value + val;
- return time >= minTime && time <= maxTime && isHourAllowed && (!cb || cb(val));
- };
- });
- const isAllowedSecondCb = vue.computed(() => {
- let cb;
- const isHourAllowed = !isAllowedHourCb.value || inputHour.value === null || isAllowedHourCb.value(inputHour.value);
- const isMinuteAllowed = isHourAllowed && (!isAllowedMinuteCb.value || inputMinute.value === null || isAllowedMinuteCb.value(inputMinute.value));
- if (props.allowedSeconds instanceof Array) {
- cb = val => props.allowedSeconds.includes(val);
- } else {
- cb = props.allowedSeconds;
- }
- if (!props.min && !props.max) {
- return isMinuteAllowed ? cb : () => false;
- }
- const [minHour, minMinute, minSecond] = props.min ? props.min.split(':').map(Number) : [0, 0, 0];
- const [maxHour, maxMinute, maxSecond] = props.max ? props.max.split(':').map(Number) : [23, 59, 59];
- const minTime = minHour * 3600 + minMinute * 60 + (minSecond || 0) * 1;
- const maxTime = maxHour * 3600 + maxMinute * 60 + (maxSecond || 0) * 1;
- return val => {
- const time = 3600 * inputHour.value + 60 * inputMinute.value + val;
- return time >= minTime && time <= maxTime && isMinuteAllowed && (!cb || cb(val));
- };
- });
- const isAmPm = vue.computed(() => {
- return props.format === 'ampm';
- });
- vue.watch(() => props.modelValue, val => setInputData(val));
- vue.onMounted(() => {
- setInputData(props.modelValue);
- });
- function genValue() {
- if (inputHour.value != null && inputMinute.value != null && (!props.useSeconds || inputSecond.value != null)) {
- return `${pad(inputHour.value)}:${pad(inputMinute.value)}` + (props.useSeconds ? `:${pad(inputSecond.value)}` : '');
- }
- return null;
- }
- function emitValue() {
- const value = genValue();
- if (value !== null) emit('update:modelValue', value);
- }
- function convert24to12(hour) {
- return hour ? (hour - 1) % 12 + 1 : 12;
- }
- function convert12to24(hour, period) {
- return hour % 12 + (period === 'pm' ? 12 : 0);
- }
- function setInputData(value) {
- if (value == null || value === '') {
- inputHour.value = null;
- inputMinute.value = null;
- inputSecond.value = null;
- } else if (value instanceof Date) {
- inputHour.value = value.getHours();
- inputMinute.value = value.getMinutes();
- inputSecond.value = value.getSeconds();
- } else {
- const [hour,, minute,, second, period] = value.trim().toLowerCase().match(/^(\d+):(\d+)(:(\d+))?([ap]m)?$/) || new Array(6);
- inputHour.value = period ? convert12to24(parseInt(hour, 10), period) : parseInt(hour, 10);
- inputMinute.value = parseInt(minute, 10);
- inputSecond.value = parseInt(second || 0, 10);
- }
- period.value = inputHour.value == null || inputHour.value < 12 ? 'am' : 'pm';
- }
- function firstAllowed(type, value) {
- const allowedFn = type === 'hour' ? isAllowedHourCb.value : type === 'minute' ? isAllowedMinuteCb.value : isAllowedSecondCb.value;
- if (!allowedFn) return value;
- // TODO: clean up (Note from V2 code)
- const range = type === 'minute' ? range60 : type === 'second' ? range60 : isAmPm.value ? value < 12 ? rangeHours12am : rangeHours12pm : rangeHours24;
- const first = range.find(v => allowedFn((v + value) % range.length + range[0]));
- return ((first || 0) + value) % range.length + range[0];
- }
- function setPeriod(val) {
- period.value = val;
- if (inputHour.value != null) {
- const newHour = inputHour.value + (period.value === 'am' ? -12 : 12);
- inputHour.value = firstAllowed('hour', newHour);
- }
- emit('update:period', val);
- emitValue();
- return true;
- }
- function onInput(value) {
- if (selecting.value === SelectingTimes.Hour) {
- inputHour.value = isAmPm.value ? convert12to24(value, period.value) : value;
- } else if (selecting.value === SelectingTimes.Minute) {
- inputMinute.value = value;
- } else {
- inputSecond.value = value;
- }
- }
- function onChange(value) {
- switch (selectingNames[selecting.value]) {
- case 'hour':
- emit('update:hour', value);
- break;
- case 'minute':
- emit('update:minute', value);
- break;
- case 'second':
- emit('update:second', value);
- break;
- }
- const emitChange = selecting.value === (props.useSeconds ? SelectingTimes.Second : SelectingTimes.Minute);
- if (selecting.value === SelectingTimes.Hour) {
- selecting.value = SelectingTimes.Minute;
- } else if (props.useSeconds && selecting.value === SelectingTimes.Minute) {
- selecting.value = SelectingTimes.Second;
- }
- if (inputHour.value === lazyInputHour.value && inputMinute.value === lazyInputMinute.value && (!props.useSeconds || inputSecond.value === lazyInputSecond.value)) return;
- const time = genValue();
- if (time === null) return;
- lazyInputHour.value = inputHour.value;
- lazyInputMinute.value = inputMinute.value;
- props.useSeconds && (lazyInputSecond.value = inputSecond.value);
- emitChange && emitValue();
- }
- useRender(() => {
- const pickerProps = VPicker.filterProps(props);
- const timePickerControlsProps = VTimePickerControls.filterProps(props);
- const timePickerClockProps = VTimePickerClock.filterProps(omit(props, ['format', 'modelValue', 'min', 'max']));
- return vue.createVNode(VPicker, vue.mergeProps(pickerProps, {
- "color": undefined,
- "class": ['v-time-picker', props.class],
- "style": props.style
- }), {
- title: () => slots.title?.() ?? vue.createVNode("div", {
- "class": "v-time-picker__title"
- }, [t(props.title)]),
- header: () => vue.createVNode(VTimePickerControls, vue.mergeProps(timePickerControlsProps, {
- "ampm": isAmPm.value || props.ampmInTitle,
- "ampmReadonly": isAmPm.value && !props.ampmInTitle,
- "hour": inputHour.value,
- "minute": inputMinute.value,
- "period": period.value,
- "second": inputSecond.value,
- "selecting": selecting.value,
- "onUpdate:period": val => setPeriod(val),
- "onUpdate:selecting": value => selecting.value = value,
- "ref": controlsRef
- }), null),
- default: () => vue.createVNode(VTimePickerClock, vue.mergeProps(timePickerClockProps, {
- "allowedValues": selecting.value === SelectingTimes.Hour ? isAllowedHourCb.value : selecting.value === SelectingTimes.Minute ? isAllowedMinuteCb.value : isAllowedSecondCb.value,
- "double": selecting.value === SelectingTimes.Hour && !isAmPm.value,
- "format": selecting.value === SelectingTimes.Hour ? isAmPm.value ? convert24to12 : val => val : val => pad(val, 2),
- "max": selecting.value === SelectingTimes.Hour ? isAmPm.value && period.value === 'am' ? 11 : 23 : 59,
- "min": selecting.value === SelectingTimes.Hour && isAmPm.value && period.value === 'pm' ? 12 : 0,
- "size": 20,
- "step": selecting.value === SelectingTimes.Hour ? 1 : 5,
- "modelValue": selecting.value === SelectingTimes.Hour ? inputHour.value : selecting.value === SelectingTimes.Minute ? inputMinute.value : inputSecond.value,
- "onChange": onChange,
- "onInput": onInput,
- "ref": clockRef
- }), null),
- actions: slots.actions
- });
- });
- }
- });
- // Types
- const makeVTreeviewGroupProps = propsFactory({
- ...omit(makeVListGroupProps({
- collapseIcon: '$treeviewCollapse',
- expandIcon: '$treeviewExpand'
- }), ['subgroup'])
- }, 'VTreeviewGroup');
- const VTreeviewGroup = genericComponent()({
- name: 'VTreeviewGroup',
- props: makeVTreeviewGroupProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const vListGroupRef = vue.ref();
- const toggleIcon = vue.computed(() => vListGroupRef.value?.isOpen ? props.collapseIcon : props.expandIcon);
- const activatorDefaults = vue.computed(() => ({
- VTreeviewItem: {
- prependIcon: undefined,
- appendIcon: undefined,
- active: vListGroupRef.value?.isOpen,
- toggleIcon: toggleIcon.value
- }
- }));
- useRender(() => {
- const listGroupProps = VListGroup.filterProps(props);
- return vue.createVNode(VListGroup, vue.mergeProps(listGroupProps, {
- "ref": vListGroupRef,
- "class": ['v-treeview-group', props.class],
- "subgroup": true
- }), {
- ...slots,
- activator: slots.activator ? slotProps => vue.createVNode(vue.Fragment, null, [vue.createVNode(VDefaultsProvider, {
- "defaults": activatorDefaults.value
- }, {
- default: () => [slots.activator?.(slotProps)]
- })]) : undefined
- });
- });
- return {};
- }
- });
- // Types
- const VTreeviewSymbol = Symbol.for('vuetify:v-treeview');
- const makeVTreeviewItemProps = propsFactory({
- loading: Boolean,
- onToggleExpand: EventProp(),
- toggleIcon: IconValue,
- ...makeVListItemProps({
- slim: true
- })
- }, 'VTreeviewItem');
- const VTreeviewItem = genericComponent()({
- name: 'VTreeviewItem',
- props: makeVTreeviewItemProps(),
- setup(props, _ref) {
- let {
- attrs,
- slots,
- emit
- } = _ref;
- const link = useLink(props, attrs);
- const vListItemRef = vue.ref();
- const isActivatableGroupActivator = vue.computed(() => vListItemRef.value?.root.activatable.value && vListItemRef.value?.isGroupActivator);
- const isClickable = vue.computed(() => !props.disabled && props.link !== false && (props.link || link.isClickable.value || props.value != null && !!vListItemRef.value?.list || isActivatableGroupActivator.value));
- function activateGroupActivator(e) {
- if (isClickable.value && isActivatableGroupActivator.value) {
- vListItemRef.value?.activate(!vListItemRef.value?.isActivated, e);
- }
- }
- const visibleIds = vue.inject(VTreeviewSymbol, {
- visibleIds: vue.ref()
- }).visibleIds;
- useRender(() => {
- const listItemProps = omit(VListItem.filterProps(props), ['onClick']);
- const hasPrepend = slots.prepend || props.toggleIcon;
- return vue.createVNode(VListItem, vue.mergeProps({
- "ref": vListItemRef
- }, listItemProps, {
- "active": vListItemRef.value?.isActivated,
- "class": ['v-treeview-item', {
- 'v-treeview-item--activatable-group-activator': isActivatableGroupActivator.value,
- 'v-treeview-item--filtered': visibleIds.value && !visibleIds.value.has(vListItemRef.value?.id)
- }, props.class],
- "ripple": false,
- "onClick": props.onClick ?? activateGroupActivator
- }), {
- ...slots,
- prepend: hasPrepend ? slotProps => {
- return vue.createVNode(vue.Fragment, null, [props.toggleIcon && vue.createVNode(VListItemAction, {
- "start": false
- }, {
- default: () => [vue.createVNode(VBtn, {
- "density": "compact",
- "icon": props.toggleIcon,
- "loading": props.loading,
- "variant": "text",
- "onClick": props.onToggleExpand
- }, {
- loader() {
- return vue.createVNode(VProgressCircular, {
- "indeterminate": "disable-shrink",
- "size": "20",
- "width": "2"
- }, null);
- }
- })]
- }), slots.prepend?.(slotProps)]);
- } : undefined
- });
- });
- return {};
- }
- });
- // Types
- const makeVTreeviewChildrenProps = propsFactory({
- loadChildren: Function,
- loadingIcon: {
- type: String,
- default: '$loading'
- },
- items: Array,
- openOnClick: {
- type: Boolean,
- default: undefined
- },
- indeterminateIcon: {
- type: IconValue,
- default: '$checkboxIndeterminate'
- },
- falseIcon: IconValue,
- trueIcon: IconValue,
- returnObject: Boolean,
- selectable: Boolean,
- selectedColor: String,
- selectStrategy: [String, Function, Object]
- }, 'VTreeviewChildren');
- const VTreeviewChildren = genericComponent()({
- name: 'VTreeviewChildren',
- props: makeVTreeviewChildrenProps(),
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const isLoading = vue.reactive(new Set());
- const isClickOnOpen = vue.computed(() => props.openOnClick != null ? props.openOnClick : props.selectable);
- async function checkChildren(item) {
- try {
- if (!props.items?.length || !props.loadChildren) return;
- if (item?.children?.length === 0) {
- isLoading.add(item.value);
- await props.loadChildren(item.raw);
- }
- } finally {
- isLoading.delete(item.value);
- }
- }
- function selectItem(select, isSelected) {
- if (props.selectable) {
- select(!isSelected);
- }
- }
- return () => slots.default?.() ?? props.items?.map(item => {
- const {
- children,
- props: itemProps
- } = item;
- const loading = isLoading.has(item.value);
- const slotsWithItem = {
- prepend: slotProps => vue.createVNode(vue.Fragment, null, [props.selectable && (!children || children && !['leaf', 'single-leaf'].includes(props.selectStrategy)) && vue.createVNode("div", null, [vue.createVNode(VCheckboxBtn, {
- "key": item.value,
- "modelValue": slotProps.isSelected,
- "loading": loading,
- "color": props.selectedColor,
- "indeterminate": slotProps.isIndeterminate,
- "indeterminateIcon": props.indeterminateIcon,
- "falseIcon": props.falseIcon,
- "trueIcon": props.trueIcon,
- "onClick": vue.withModifiers(() => selectItem(slotProps.select, slotProps.isSelected), ['stop']),
- "onKeydown": e => {
- if (!['Enter', 'Space'].includes(e.key)) return;
- e.stopPropagation();
- selectItem(slotProps.select, slotProps.isSelected);
- }
- }, null)]), slots.prepend?.({
- ...slotProps,
- item: item.raw,
- internalItem: item
- })]),
- append: slots.append ? slotProps => slots.append?.({
- ...slotProps,
- item: item.raw,
- internalItem: item
- }) : undefined,
- title: slots.title ? slotProps => slots.title?.({
- ...slotProps,
- item: item.raw,
- internalItem: item
- }) : undefined
- };
- const treeviewGroupProps = VTreeviewGroup.filterProps(itemProps);
- const treeviewChildrenProps = VTreeviewChildren.filterProps(props);
- return children ? vue.createVNode(VTreeviewGroup, vue.mergeProps(treeviewGroupProps, {
- "value": props.returnObject ? item.raw : treeviewGroupProps?.value
- }), {
- activator: _ref2 => {
- let {
- props: activatorProps
- } = _ref2;
- const listItemProps = {
- ...itemProps,
- ...activatorProps,
- value: itemProps?.value,
- onToggleExpand: [() => checkChildren(item), activatorProps.onClick],
- onClick: isClickOnOpen.value ? [() => checkChildren(item), activatorProps.onClick] : undefined
- };
- return vue.createVNode(VTreeviewItem, vue.mergeProps(listItemProps, {
- "value": props.returnObject ? vue.toRaw(item.raw) : itemProps.value,
- "loading": loading
- }), slotsWithItem);
- },
- default: () => vue.createVNode(VTreeviewChildren, vue.mergeProps(treeviewChildrenProps, {
- "items": children,
- "returnObject": props.returnObject
- }), slots)
- }) : slots.item?.({
- props: itemProps,
- item: item.raw,
- internalItem: item
- }) ?? vue.createVNode(VTreeviewItem, vue.mergeProps(itemProps, {
- "value": props.returnObject ? vue.toRaw(item.raw) : itemProps.value
- }), slotsWithItem);
- });
- }
- });
- function flatten(items) {
- let flat = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
- for (const item of items) {
- flat.push(item);
- if (item.children) flatten(item.children, flat);
- }
- return flat;
- }
- const makeVTreeviewProps = propsFactory({
- openAll: Boolean,
- search: String,
- ...makeFilterProps({
- filterKeys: ['title']
- }),
- ...makeVTreeviewChildrenProps(),
- ...omit(makeVListProps({
- collapseIcon: '$treeviewCollapse',
- expandIcon: '$treeviewExpand',
- slim: true
- }), ['itemType', 'nav', 'openStrategy']),
- modelValue: {
- type: Array,
- default: () => []
- }
- }, 'VTreeview');
- const VTreeview = genericComponent()({
- name: 'VTreeview',
- props: makeVTreeviewProps(),
- emits: {
- 'update:opened': val => true,
- 'update:activated': val => true,
- 'update:selected': val => true,
- 'update:modelValue': val => true,
- 'click:open': value => true,
- 'click:select': value => true
- },
- setup(props, _ref) {
- let {
- slots
- } = _ref;
- const {
- items
- } = useListItems(props);
- const activeColor = vue.toRef(props, 'activeColor');
- const baseColor = vue.toRef(props, 'baseColor');
- const color = vue.toRef(props, 'color');
- const activated = useProxiedModel(props, 'activated');
- const model = useProxiedModel(props, 'modelValue');
- const _selected = useProxiedModel(props, 'selected', props.modelValue);
- const selected = vue.computed({
- get: () => _selected.value,
- set(val) {
- _selected.value = val;
- model.value = val;
- }
- });
- const vListRef = vue.ref();
- const opened = vue.computed(() => props.openAll ? openAll(items.value) : props.opened);
- const flatItems = vue.computed(() => flatten(items.value));
- const search = vue.toRef(props, 'search');
- const {
- filteredItems
- } = useFilter(props, flatItems, search);
- const visibleIds = vue.computed(() => {
- if (!search.value) return null;
- const getPath = vListRef.value?.getPath;
- if (!getPath) return null;
- return new Set(filteredItems.value.flatMap(item => {
- const itemVal = props.returnObject ? item.raw : item.props.value;
- return [...getPath(itemVal), ...getChildren(itemVal)].map(vue.toRaw);
- }));
- });
- function getChildren(id) {
- const arr = [];
- const queue = (vListRef.value?.children.get(id) ?? []).slice();
- while (queue.length) {
- const child = queue.shift();
- if (!child) continue;
- arr.push(child);
- queue.push(...(vListRef.value?.children.get(child) ?? []).slice());
- }
- return arr;
- }
- function openAll(items) {
- let ids = [];
- for (const i of items) {
- if (!i.children) continue;
- ids.push(props.returnObject ? vue.toRaw(i.raw) : i.value);
- if (i.children) {
- ids = ids.concat(openAll(i.children));
- }
- }
- return ids;
- }
- vue.provide(VTreeviewSymbol, {
- visibleIds
- });
- provideDefaults({
- VTreeviewGroup: {
- activeColor,
- baseColor,
- color,
- collapseIcon: vue.toRef(props, 'collapseIcon'),
- expandIcon: vue.toRef(props, 'expandIcon')
- },
- VTreeviewItem: {
- activeClass: vue.toRef(props, 'activeClass'),
- activeColor,
- baseColor,
- color,
- density: vue.toRef(props, 'density'),
- disabled: vue.toRef(props, 'disabled'),
- lines: vue.toRef(props, 'lines'),
- variant: vue.toRef(props, 'variant')
- }
- });
- useRender(() => {
- const listProps = VList.filterProps(props);
- const treeviewChildrenProps = VTreeviewChildren.filterProps(props);
- return vue.createVNode(VList, vue.mergeProps({
- "ref": vListRef
- }, listProps, {
- "class": ['v-treeview', props.class],
- "open-strategy": "multiple",
- "style": props.style,
- "opened": opened.value,
- "activated": activated.value,
- "onUpdate:activated": $event => activated.value = $event,
- "selected": selected.value,
- "onUpdate:selected": $event => selected.value = $event
- }), {
- default: () => [vue.createVNode(VTreeviewChildren, vue.mergeProps(treeviewChildrenProps, {
- "returnObject": props.returnObject,
- "items": items.value
- }), slots)]
- });
- });
- return {};
- }
- });
- 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,
- VBottomSheet: VBottomSheet,
- VBreadcrumbs: VBreadcrumbs,
- VBreadcrumbsDivider: VBreadcrumbsDivider,
- VBreadcrumbsItem: VBreadcrumbsItem,
- VBtn: VBtn,
- VBtnGroup: VBtnGroup,
- VBtnToggle: VBtnToggle,
- VCalendar: VCalendar,
- VCalendarDay: VCalendarDay,
- VCalendarHeader: VCalendarHeader,
- VCalendarInterval: VCalendarInterval,
- VCalendarIntervalEvent: VCalendarIntervalEvent,
- VCalendarMonthDay: VCalendarMonthDay,
- 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,
- VConfirmEdit: VConfirmEdit,
- VContainer: VContainer,
- VCounter: VCounter,
- VDataIterator: VDataIterator,
- VDataTable: VDataTable,
- VDataTableFooter: VDataTableFooter,
- VDataTableHeaders: VDataTableHeaders,
- VDataTableRow: VDataTableRow,
- VDataTableRows: VDataTableRows,
- VDataTableServer: VDataTableServer,
- VDataTableVirtual: VDataTableVirtual,
- VDateInput: VDateInput,
- VDatePicker: VDatePicker,
- VDatePickerControls: VDatePickerControls,
- VDatePickerHeader: VDatePickerHeader,
- VDatePickerMonth: VDatePickerMonth,
- VDatePickerMonths: VDatePickerMonths,
- VDatePickerYears: VDatePickerYears,
- VDefaultsProvider: VDefaultsProvider,
- VDialog: VDialog,
- VDialogBottomTransition: VDialogBottomTransition,
- VDialogTopTransition: VDialogTopTransition,
- VDialogTransition: VDialogTransition,
- VDivider: VDivider,
- VEmptyState: VEmptyState,
- VExpandTransition: VExpandTransition,
- VExpandXTransition: VExpandXTransition,
- VExpansionPanel: VExpansionPanel,
- VExpansionPanelText: VExpansionPanelText,
- VExpansionPanelTitle: VExpansionPanelTitle,
- VExpansionPanels: VExpansionPanels,
- VFab: VFab,
- VFabTransition: VFabTransition,
- VFadeTransition: VFadeTransition,
- VField: VField,
- VFieldLabel: VFieldLabel,
- VFileInput: VFileInput,
- VFileUpload: VFileUpload,
- VFileUploadItem: VFileUploadItem,
- VFooter: VFooter,
- VForm: VForm,
- VHover: VHover,
- VIcon: VIcon,
- VImg: VImg,
- VInfiniteScroll: VInfiniteScroll,
- 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,
- VNumberInput: VNumberInput,
- VOtpInput: VOtpInput,
- VOverlay: VOverlay,
- VPagination: VPagination,
- VParallax: VParallax,
- VPicker: VPicker,
- VPickerTitle: VPickerTitle,
- VProgressCircular: VProgressCircular,
- VProgressLinear: VProgressLinear,
- VPullToRefresh: VPullToRefresh,
- 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,
- VSkeletonLoader: VSkeletonLoader,
- VSlideGroup: VSlideGroup,
- VSlideGroupItem: VSlideGroupItem,
- VSlideXReverseTransition: VSlideXReverseTransition,
- VSlideXTransition: VSlideXTransition,
- VSlideYReverseTransition: VSlideYReverseTransition,
- VSlideYTransition: VSlideYTransition,
- VSlider: VSlider,
- VSnackbar: VSnackbar,
- VSnackbarQueue: VSnackbarQueue,
- VSpacer: VSpacer,
- VSparkline: VSparkline,
- VSpeedDial: VSpeedDial,
- VStepper: VStepper,
- VStepperActions: VStepperActions,
- VStepperHeader: VStepperHeader,
- VStepperItem: VStepperItem,
- VStepperVertical: VStepperVertical,
- VStepperVerticalActions: VStepperVerticalActions,
- VStepperVerticalItem: VStepperVerticalItem,
- VStepperWindow: VStepperWindow,
- VStepperWindowItem: VStepperWindowItem,
- VSvgIcon: VSvgIcon,
- VSwitch: VSwitch,
- VSystemBar: VSystemBar,
- VTab: VTab,
- VTable: VTable,
- VTabs: VTabs,
- VTabsWindow: VTabsWindow,
- VTabsWindowItem: VTabsWindowItem,
- VTextField: VTextField,
- VTextarea: VTextarea,
- VThemeProvider: VThemeProvider,
- VTimePicker: VTimePicker,
- VTimePickerClock: VTimePickerClock,
- VTimePickerControls: VTimePickerControls,
- VTimeline: VTimeline,
- VTimelineItem: VTimelineItem,
- VToolbar: VToolbar,
- VToolbarItems: VToolbarItems,
- VToolbarTitle: VToolbarTitle,
- VTooltip: VTooltip,
- VTreeview: VTreeview,
- VTreeviewGroup: VTreeviewGroup,
- VTreeviewItem: VTreeviewItem,
- 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
- };
- // Utilities
- // Types
- function useDirectiveComponent(component, props) {
- const concreteComponent = typeof component === 'string' ? vue.resolveComponent(component) : component;
- const hook = mountComponent(concreteComponent, props);
- return {
- mounted: hook,
- updated: hook,
- unmounted(el) {
- vue.render(null, el);
- }
- };
- }
- function mountComponent(component, props) {
- return function (el, binding, vnode) {
- const _props = typeof props === 'function' ? props(binding) : props;
- const text = binding.value?.text ?? binding.value ?? _props?.text;
- const value = isObject(binding.value) ? binding.value : {};
- // Get the children from the props or directive value, or the element's children
- const children = () => text ?? el.textContent;
- // If vnode.ctx is the same as the instance, then we're bound to a plain element
- // and need to find the nearest parent component instance to inherit provides from
- const provides = (vnode.ctx === binding.instance.$ ? findComponentParent(vnode, binding.instance.$)?.provides : vnode.ctx?.provides) ?? binding.instance.$.provides;
- const node = vue.h(component, vue.mergeProps(_props, value), children);
- node.appContext = Object.assign(Object.create(null), binding.instance.$.appContext, {
- provides
- });
- vue.render(node, el);
- };
- }
- function findComponentParent(vnode, root) {
- // Walk the tree from root until we find the child vnode
- const stack = new Set();
- const walk = children => {
- for (const child of children) {
- if (!child) continue;
- if (child === vnode || child.el && vnode.el && child.el === vnode.el) {
- return true;
- }
- stack.add(child);
- let result;
- if (child.suspense) {
- result = walk([child.ssContent]);
- } else if (Array.isArray(child.children)) {
- result = walk(child.children);
- } else if (child.component?.vnode) {
- result = walk([child.component?.subTree]);
- }
- if (result) {
- return result;
- }
- stack.delete(child);
- }
- return false;
- };
- if (!walk([root.subTree])) {
- consoleError('Could not find original vnode, component will not inherit provides');
- return root;
- }
- // Return the first component parent
- const result = Array.from(stack).reverse();
- for (const child of result) {
- if (child.component) {
- return child.component;
- }
- }
- return root;
- }
- // Components
- // Types
- const Tooltip = useDirectiveComponent(VTooltip, binding => {
- return {
- activator: 'parent',
- location: binding.arg?.replace('-', ' '),
- text: typeof binding.value === 'boolean' ? undefined : binding.value
- };
- });
- var directives = /*#__PURE__*/Object.freeze({
- __proto__: null,
- ClickOutside: ClickOutside,
- Intersect: Intersect,
- Mutate: Mutate,
- Resize: Resize,
- Ripple: Ripple,
- Scroll: Scroll,
- Tooltip: Tooltip,
- Touch: Touch
- });
- // 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, locale);
- const goTo = createGoTo(options.goTo, locale);
- 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(DateOptionsSymbol, date.options);
- app.provide(DateAdapterSymbol, date.instance);
- app.provide(GoToSymbol, goTo);
- 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,
- goTo
- };
- }
- const version$1 = "3.7.6";
- 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];
- }
- }
- // Icons
- // Types
- const md1 = {
- defaults: {
- global: {
- rounded: 'sm'
- },
- VAvatar: {
- rounded: 'circle'
- },
- VAutocomplete: {
- variant: 'underlined'
- },
- VBanner: {
- color: 'primary'
- },
- VBtn: {
- color: 'primary',
- rounded: 0
- },
- VCheckbox: {
- color: 'secondary'
- },
- VCombobox: {
- variant: 'underlined'
- },
- VSelect: {
- variant: 'underlined'
- },
- VSlider: {
- color: 'primary'
- },
- VTabs: {
- color: 'primary'
- },
- VTextarea: {
- variant: 'underlined'
- },
- VTextField: {
- variant: 'underlined'
- },
- VToolbar: {
- VBtn: {
- color: null
- }
- }
- },
- icons: {
- defaultSet: 'mdi',
- sets: {
- mdi
- }
- },
- theme: {
- themes: {
- light: {
- colors: {
- primary: '#3F51B5',
- 'primary-darken-1': '#303F9F',
- 'primary-lighten-1': '#C5CAE9',
- secondary: '#FF4081',
- 'secondary-darken-1': '#F50057',
- 'secondary-lighten-1': '#FF80AB',
- accent: '#009688'
- }
- }
- }
- }
- };
- // Icons
- // Types
- const md2 = {
- defaults: {
- global: {
- rounded: 'md'
- },
- VAvatar: {
- rounded: 'circle'
- },
- VAutocomplete: {
- variant: 'filled'
- },
- VBanner: {
- color: 'primary'
- },
- VBtn: {
- color: 'primary'
- },
- VCheckbox: {
- color: 'secondary'
- },
- VCombobox: {
- variant: 'filled'
- },
- VSelect: {
- variant: 'filled'
- },
- VSlider: {
- color: 'primary'
- },
- VTabs: {
- color: 'primary'
- },
- VTextarea: {
- variant: 'filled'
- },
- VTextField: {
- variant: 'filled'
- },
- VToolbar: {
- VBtn: {
- color: null
- }
- }
- },
- icons: {
- defaultSet: 'mdi',
- sets: {
- mdi
- }
- },
- theme: {
- themes: {
- light: {
- colors: {
- primary: '#6200EE',
- 'primary-darken-1': '#3700B3',
- secondary: '#03DAC6',
- 'secondary-darken-1': '#018786',
- error: '#B00020'
- }
- }
- }
- }
- };
- // Icons
- // Types
- const md3 = {
- defaults: {
- VAppBar: {
- flat: true
- },
- VAutocomplete: {
- variant: 'filled'
- },
- VBanner: {
- color: 'primary'
- },
- VBottomSheet: {
- contentClass: 'rounded-t-xl overflow-hidden'
- },
- VBtn: {
- color: 'primary',
- rounded: 'xl'
- },
- VBtnGroup: {
- rounded: 'xl',
- VBtn: {
- rounded: null
- }
- },
- VCard: {
- rounded: 'lg'
- },
- VCheckbox: {
- color: 'secondary',
- inset: true
- },
- VChip: {
- rounded: 'sm'
- },
- VCombobox: {
- variant: 'filled'
- },
- VNavigationDrawer: {
- // VList: {
- // nav: true,
- // VListItem: {
- // rounded: 'xl',
- // },
- // },
- },
- VSelect: {
- variant: 'filled'
- },
- VSlider: {
- color: 'primary'
- },
- VTabs: {
- color: 'primary'
- },
- VTextarea: {
- variant: 'filled'
- },
- VTextField: {
- variant: 'filled'
- },
- VToolbar: {
- VBtn: {
- color: null
- }
- }
- },
- icons: {
- defaultSet: 'mdi',
- sets: {
- mdi
- }
- },
- theme: {
- themes: {
- light: {
- colors: {
- primary: '#6750a4',
- secondary: '#b4b0bb',
- tertiary: '#7d5260',
- error: '#b3261e',
- surface: '#fffbfe'
- }
- }
- }
- }
- };
- var index = /*#__PURE__*/Object.freeze({
- __proto__: null,
- md1: md1,
- md2: md2,
- md3: md3
- });
- /* eslint-disable local-rules/sort-imports */
- const version = "3.7.6";
- /* eslint-disable local-rules/sort-imports */
- const createVuetify = function () {
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- return createVuetify$1({
- components,
- directives,
- ...options
- });
- };
- exports.blueprints = index;
- exports.components = components;
- exports.createVuetify = createVuetify;
- exports.directives = directives;
- exports.useDate = useDate;
- exports.useDefaults = useDefaults;
- exports.useDisplay = useDisplay;
- exports.useGoTo = useGoTo;
- exports.useLayout = useLayout;
- exports.useLocale = useLocale;
- exports.useRtl = useRtl;
- exports.useTheme = useTheme;
- exports.version = version;
- }));
|