commit 60bf30211923f97e5ae82f7be99507ef0ce24072 Author: 阿怪 <690927457@qq.com> Date: Sun Oct 8 21:21:21 2023 +0800 init diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..b9168e8 --- /dev/null +++ b/App.vue @@ -0,0 +1,168 @@ + + + diff --git a/api/index.js b/api/index.js new file mode 100644 index 0000000..262eb57 --- /dev/null +++ b/api/index.js @@ -0,0 +1,404 @@ +import net from './request.js'; + +// import store from '../store'; + +const API = { + /* + 首页信息 + */ + getIndexInfo: data => net.GET('/api/index/index'), // 首页信息 + getIndexBanner: data => net.GET('/api/banner/index',data), // 轮播图 + getIndexNotice: data => net.GET('/api/news/notice'), // 公告 + getGoodsDetail: data => net.GET('/api/goods/detail',data),// 商品详情(普通商品) + getSeckillGoodsDetail: data => net.GET('/api/seckill_goods/detail',data),// 商品详情(秒杀) + getGroupGoodsDetail: data => net.GET('/api/group_goods/detail',data),// 商品详情(团购) + getGoodsList: data => net.GET('/api/goods/lists',data),// 商品列表(普通商品) + getSeckillGoodsList: data => net.GET('/api/seckill_goods/lists',data),// 商品列表(限时) + getGroupGoodsList: data => net.GET('/api/group_goods/lists?page=&keyword=',data),// 商品列表(团购) + getNewinfo: data => net.GET('/api/goods/getGoodsSpec',data), // 根据商品规格更新数据 + getCategoryList:data => net.GET('/api/goods_category/lists'), // 获取商品分类 + getCategory:data => net.GET('/api/goods/category',data), // 根据分类Id获取分类商品 + getCartList:data => net.GET('/api/cart/lists',data), // 获取购物车列表 + addCart:data => net.POST('/api/cart/add',data), // 加入购物车 + delCart:data => net.POST('/api/cart/delete',data), // 删除购物车 + updateCart:data => net.POST('/api/cart/edit',data), // 更新购物车 + login:data => net.POST('/api/user/wechatLogin',data), // 登录 + login_test:data => net.GET('/api/user/testLogin?id=1'), // 登录 测试专用 + zhuce:data => net.POST('/api/user/profile',data), // 注册 + getOrderList:data => net.GET('/api/order/lists',data), //订单列表 + getOrderGroupList:data => net.GET('/api/group_order/lists',data), //订单列表(团购) + getOrderSeckillList:data => net.GET('/api/seckill_order/lists',data), //订单列表(秒杀) + pay:data => net.POST('/api/order/pay',data), //支付 + payGroup:data => net.POST('/api/group_order/pay',data), //支付(团购) + paySeckill:data => net.POST('/api/seckill_order/pay',data), //支付(秒杀) + refund:data => net.POST('/api/order/refund',data), //退款 + getOrderInviteList:data => net.GET('/api/invite/order',data), //分销订单 + + getOrderBaseinfo:data => net.POST('/api/order/preview',data), //获取订单提交页面的基本信息 + getOrderGroupBaseinfo:data => net.POST('/api/group_order/preview',data), //获取订单提交页面的基本信息(团购) + getOrderSeckillBaseinfo:data => net.POST('/api/seckill_order/preview',data), //获取订单提交页面的基本信息(秒杀) + getOrderCartinfo:data => net.POST('/api/order/cartPreview',data), //获取订单提交页面的基本信息(购物车来的) + getDelivery:data => net.GET('/api/index/delivery',data), //获取配送相关的选项(普通商品) + staffApply:data => net.POST('/api/invite/apply',data), //业务员申请 + deliveryApply:data => net.POST('/api/staff/apply',data), //配送员申请 + getDeliveryArea:data => net.GET('/api/staff/getDeliveryArea'), //获取配送区域 + + getAddressList:data => net.GET('/api/address/lists'), //地址列表 + getAddDetail:data => net.GET('/api/address/detail',data), //地址详情 + addAddress:data => net.POST('/api/address/add',data), //新增地址 + editAddress:data => net.POST('/api/address/edit',data), //修改地址 + delAddress:data => net.GET('/api/address/delete',data), //删除地址 + getDefaultAddress:data => net.GET('/api/address/getDefault'), //获取默认地址 + + orderSubmitFunc:data => net.POST('/api/order/order',data), //提交订单(普通订单) + orderSubmitCartFunc:data => net.POST('/api/order/cartOrder',data), //提交订单(购物车) + orderSubmitGroupFunc:data => net.POST('/api/group_order/order',data), //提交订单(团购订单) + orderSubmitSeckillFunc:data => net.POST('/api/seckill_order/order',data), //提交订单(秒杀订单) + + orderDetail:data => net.GET('/api/order/detail',data), //订单详情-普通订单 (顾客) + orderGroupDetail:data => net.GET('/api/group_order/detail',data), //订单详情-团购订单 + orderSeckillDetail:data => net.GET('/api/seckill_order/detail',data), //订单详情-秒杀订单 + orderStaffDetail:data => net.GET('/api/staff/orderDetail',data), //订单详情-配送订单 + orderLeaderDetail:data => net.GET('/api/leader/orderDetail',data), //订单详情-管理员订单 + orderCancel:data => net.POST('/api/order/cancle',data), //取消订单 + orderCancelGroup:data => net.POST('/api/group_order/cancle',data), //取消订单 (团购) + orderCancelSeckill:data => net.POST('/api/seckill_order/cancle',data), //取消订单 (秒杀) + /* + 用户相关 + */ + getUserInfo:data => net.GET('/api/user/userInfo',data), //获取用户信息 + updateUserInfo:data => net.POST('/api/user/profile',data), //更新用户信息 + rechargeFunc:data => net.POST('/api/recharge/recharge',data), //充值 + withdrawalFunc:data => net.POST('/api/withdrawl/submit',data), //提现 + vipBuy:data => net.POST('/api/vip/order',data), //购买VIP + vipConfig:data => net.GET('/api/vip/config'), //会员说明 + + /* + 优惠券 + */ + getCouponsList:data => net.GET('/api/coupon/userCoupons',data), //优惠券 + getCouponsCenterList:data => net.GET('/api/coupon/lists',data), //领券中心 + couponsCenterReceive:data => net.POST('/api/coupon/receive',data), //领取优惠 + + getMyStars:data => net.GET('/api/collect/lists',data), //我的收藏 + /* + 推广中心 + */ + inviteCenter:data => net.GET('/api/invite/index',data), //首页 + inviteCenterwithdrawl:data => net.POST('/api/withdrawl/submit',data), //提现 + inviteCenterwithdrawlDetail:data => net.GET('/api/invite/withdrawlDetail',data), //提现明细 + inviteCenterwithdrawlRecodes:data => net.GET('/api/invite/record',data), //提现明细(佣金) + getShareQrcode:data => net.GET('/api/user/getShareQrcode'), //用户分销二维码 + /* + 配置相关 + */ + getConfig:data => net.GET('/api/index/config'), + setDeliveryTime:data => net.POST('/api/staff/setDeliveryTime',data), // 设置配送时间 + getDeliveryTime:data => net.GET('/api/staff/getDeliveryTime'), // 获取配送时间 + getStaffOrder:data => net.GET('/api/staff/orderLists',data), // 获取订单管理列表(配送员) + getManageOrder:data => net.GET('/api/leader/orderLists',data), // 获取订单管理列表(团长) + deliveryPhoto:data => net.POST('/api/staff/deliveryPhoto',data), // 送达拍照 + reveiceOrder:data => net.POST('/api/staff/reveiceOrder',data), // 接单 + reveiceOrderOk:data => net.POST('/api/leader/assignOrder',data), // 派单 + getStaffList:data => net.GET('/api/leader/staffList'), // 配送员列表 + goodsBuyFunc:data => net.POST('/api/leader/goodsBuy',data), // 商品申购 + getRecordList:data => net.GET('/api/leader/recordList',data), // 货物入库 + /** + * + * 登录类信息 + * + */ + // 检查更新 + getUpdateVersion:data => net.GET('/api/v1/index/version'), + // 获取定位 + getLocationInfo:data => net.GET('/api/v1/index/ip',data), + // 验证码登陆 + codeLogin: data => net.POST('/code/login', data), + // H5扫码登录邀请接口 + inviteLogin: data => net.POST('/api/v1/invite/login', data), + // 发送手机验证码接口 + sendVerifyCode: data => net.POST('/api/v1/sms/send', { send_type: 'student', ...data}), + // 注销账号 + unRegister: data => net.POST('/api/v1/student/delete', data), + // 授权登录 + accessLogin: (data, t = 'wx') => net.POST(`/api/v1/${t}/login`, data), + // 退出登录 + logOut: data => net.POST('/api/v1/code/logout', data), + + // 获取省份 + getProvince: data => net.GET('/api/v1/colleges/getProvince', data), + // 根据学员所选择的教学点获取院校列表接口 + collegesList: data => net.GET('/api/v1/colleges/list', data), + // 通过市反查省/自治区/直辖市 + getProvinceByCity: data => net.GET('/api/v1/region/getProvinceByCity', data), + + /** + * + * 用户信息 + * + */ + + // 学员个人信息接口 + selectUserInfo: data => net.GET('/api/v1/student/info', data), + // 登录成功后填写学员信息接口 + userUpdate: data => net.POST('/api/v1/student/update', data), + // 邀请二维码 + qrcode: data => net.POST('/api/v1/student/invite/qrcode', data), + uploadBase64: data => net.POST('/api/v1/student/uploadBase64', data), + // 获取被邀请人列表接口 + inviteList: data => net.GET('/api/v1/student/invite/list', data), + // 积分列表 + scoreList: data => net.GET('/point', data), + // 余额明细 + balanceList: data => net.POST('/api/v1/balance/detail/get/list', data), + // 模拟测试记录 + recordList: data => net.GET('/api/v1/test-record/mock/examination/record', data), + // 练习题错误集详情 + practiceList: data => net.GET('/api/v1/test-record/practice/list', data), + + /** + * + * 首页数据 + * + */ + // 首页配置获取 + indexConfig: data => net.GET('/api/v1/index/config', data), + // 轮播 + // indexBanner: data => net.GET('/app/banner', data), + indexBanner: data => net.POST('/api/v1/index/lbt', data), + // 获取咨询文章列表 + // wzList: data => net.GET('/app/consult-wz', data), + wzList: data => net.POST('/api/v1/index/wz/list', data), + // 获取咨询文章 + // wzInfo: id => net.GET(`/app/consult-wz/${id}`), + wzInfo: id => net.GET(`/api/v1/index/wz/${id}`), + + // 获取课程分页 + getCourseList: (data) => net.GET(`/app/course/page`,data), + + // 获取推荐院校列表 + // recommendwzList: data => net.GET('/app/academy', data), + recommendwzList: data => net.POST('/api/v1/index/academy/list', data), + // 获取推荐院校文章 + // recommendwzInfo: id => net.GET(`/app/academy/${id}`), + recommendwzInfo: id => net.GET(`/api/v1/index/academy/${id}`), + // 推荐院校文章阅读量累计 + // recomendaddReadNumber: data => net.PUT('/app/academy/num',data), + recomendaddReadNumber: data => net.POST('/api/v1/index/academy/add/num', data), + + //获取考试大纲列表 + syllabusList: data => net.POST('/api/v1/index/syllabus/list', data), + + // 搜索 + search: data => net.POST('/api/v1/index/search', data), + // 阅读量累计 + addReadNumber: data => net.PUT('/app/consult-wz/num', data), + // 师资团队列表 + lecturerList: data => net.GET('/api/v1/index/lecturer', data), + // 师资详情 + lecturerDetail: id => net.GET(`/api/v1/index/lecturer/${id}`), + // 获取资料列表 + indexMaterial: data => net.GET('/api/v1/index/material', data), + // indexMaterial: data => net.GET('/app/material', data), + // 获取资料详情 + materialDetail: data => net.GET(`/api/v1/index/material/${data.id}`,{buyer_id:data.buyer_id}), + // 获取精品课程 + indexBoutiqueCourse: data => net.GET('/api/v1/index/boutique/course', data), + // 获取精品课程详情 + boutiqueCourseDetail: id => net.GET(`/api/v1/index/boutique/course/${id}`), + + // 获取课程 + courseList: data => net.POST('/api/v1/course/get', data), + // 获取套餐 + comboList: data => net.POST('/api/v1/combo/course/get', data), + // courseList: data => net.GET('/app/course/page', data), + // 获取课程详情 + courseDetail: (id, data) => net.GET(`/api/v1/course/${id}`, data), + // courseDetail: (id, data) => net.GET(`/app/course`, {id}), + // 获取线下课程 + offlineCourseList: data => net.POST('/api/v1/offline/course/get', data), + // 获取线下课程详情 + offlineCourseDetail: id => net.GET(`/api/v1/offline/course/${id}`), + // 获取套餐课程详情 + getComboDetail: data => net.GET(`/api/v1/combo/course/${data.id}`,{buyer_id:data.buyer_id}), + + // 获取直播课列表 + // liveCourseList: data => net.GET('/api/v1/sys-course-live', data), + liveCourseList: data => net.GET('/api/v1/api-live-course', data), + // 直播课详情 + viewCourse: (id, data) => net.GET('/api/v1/sys-course-live/'+id,{buyer_id:data.buyer_id}), + // 直播课详情 测试 + viewCourse_test: (id, data) => net.GET('/api/v1/api-live-course/'+id,{buyer_id:data.buyer_id}), + /*题库 管理*/ + //题库 + getQuestionExercise:data => net.GET('/exercises', data), + + // 科目 + subjectList: data => net.GET('/api/v1/public/subject', data), + // subjectList: data => net.GET('/app/subject/list', data), + // 获取学员学习列表接口 + learningList: data => net.GET('/api/v1/learning', data), + // 学习课程详情 + learningDetail: data => net.GET(`/api/v1/learning/course/${data}`), + // 学习直播课程详情 + learningLiveDetail: data => net.GET(`/api/v1/learning/course/live/${data}`), + // 学员学习计时接口 + // "time_type": "stop" //计时类型 start-开始计时 stop-停止计时 + studyDuration: data => net.POST('/api/v1/learning/course/duration', data), + // 学习统计API + courseStatistics: data => net.POST('/api/v1/learning/course/statistics', data), + // 题型分类 + questionBankType: data => net.GET('/api/v1/questionBank/type', data), + // 网课、测试、题库详情 + exercisesDetails: data => net.GET(`/api/v1/exercises/detail/${data}`), + // 测试练习题列表 + testList: data => net.GET('/api/v1/exercises/test/list', data), + // 模拟试卷列表 + examinationList: data => net.GET('/api/v1/examination/list', data), + // 获取题库、网课题目列表接口 + exerciseSubjectList: data => net.GET('/api/v1/exercise/subject/list', data), + // 试题分类 + exercisesType: data => net.GET('/api/v1/exercises/type', data), + // 模拟题详情 + examinationDetail: id => net.GET(`/api/v1/examination/detail/${id}`), + // 开始答题 + startTest: data => net.POST('/api/v1/exercises/start/answer', data),// question_bank_id + // 交卷 + submitTest: data => net.POST('/api/v1/exercises/submit', data), + // 下一题 + nextSubject: data => net.POST('/api/v1/exercises/next', data), + // 重新答题 + againAnswer: data => net.POST('/api/v1/exercises/againAnswer', data), + // 答题成绩报告 + scoreReport: data => net.GET('/api/v1/exercises/achievement/report', data), + // 获取团购列表 + getGroupList: data => net.GET('/api/v1/group/page', data), + // 获取团购详情 + getGroupPurchaseData: data => net.GET('/api/v1/group', data), + //发起拼团 + starGroupPurchase:data => net.POST('/api/v1/group',data), + //加入拼团 + joinGroupPurchase:data => net.POST('/api/v1/group/join',data), + /** + * + * 支付接口 + * + */ + // 支付接口 + wxOrAlipay: data => net.POST('/api/v1/pay', data), + // 获取openid + getOpenID: data => { + return uni.request({ + url:'https://api.weixin.qq.com/sns/oauth2/access_token', + method:'GET', + // header: { + // ...header, + // ...headers + // }, + data + }) + }, + // 余额支付 + yuePay: data => net.POST('/api/v1/student/pay/balance', data), + //H5下单API + // v3_pay:data => net.POST('https://api.mch.weixin.qq.com/v3/pay/transactions/h5',data) + v3_pay:data => { + return uni.request({ + url: 'https://api.mch.weixin.qq.com/v3/pay/transactions/h5', + method:'POST', + header: { + "Content-Type": "application/json", + }, + data + }) + }, + //测试 + pay_check:data => net.POST('/api/v1/wxpay/check',data), + pay_callback:data => net.POST('/api/v1/wxpay/callback',data), + /** + * + * 地址接口 + * + */ + // 列表 + addressList: data => net.POST('/api/v1/address', data), // student_id + // 新增/编辑 + addressAction: data => net.POST(`/api/v1/address/add`, data), + editaddressAction: data => net.PUT(`/api/v1/address`, data), + // 删除 + addressDelete: data => net.DELETE('/api/v1/address', data), // id + + /** + * + * 购物车接口 + * + */ + // 列表 + cartList: data => net.POST('/api/v1/shopping/cart', data), + // 添加 + cartAdd: data => net.POST('/api/v1/shopping/cart/add', data), + // 编辑 + cartUpdate: data => net.POST('/api/v1/shopping/cart/update', data), + // 删除 + cartDelete: data => net.POST('/api/v1/shopping/cart/delete', data), // id + + /** + * + * 订单接口 + * + */ + + // 订单查询 + orderList: data => net.POST('/api/v1/api-order/get/my/order/list', data), + // 确认收货 + orderUpdate: data => net.POST('/api/v1/api-order/update/material/order', data), + // 删除 + orderDelete: data => net.POST('/api/v1/api-order/delete/order', data), + + /** + * 商品价格合计 + * @param { order_count_list: [{ id: '', order_type: '', num: ''}] } + * + */ + orderCount: data => net.POST('/api/v1/api-order/order/count', data), + + /** + * 资料,在线课程的立即购买/购物车 + * @param { goods: [{ id: '', order_type: '', num: ''}], student_id: '' } + * + */ + orderBuynow: data => net.POST('/api/v1/api-order/order/buynow', data), + // 新增资料订单 + orderMaterialAdd: data => net.POST('/api/v1/api-order/add/material/order', data), + // 新增在线课程订单 + orderOnlineAdd: data => net.POST('/api/v1/api-order/add/online/order', data), + // 直播课订单 + orderLiveAdd: data => net.POST('/api/v1/api-order/add/live/order', data), + // 新增套餐课程订单 + orderComboAdd: data => net.POST('/api/v1/api-order/add/combo/order', data), + // 新增线下订单==报名 + orderOfflineAdd: data => net.POST('/api/v1/api-order/add/offline/order', data), + // 新增团购订单 + orderGroupAdd: data => net.POST('/api/v1/api-order/add/group/order', data), + + // 分享平台 + shareProvider: () => net.getShareProvider(), + // 支付方式 + paymentProvider: () => net.getPaymentProvider(), + // 物流查询 + queryKuaidi: data => net.POST('/api/v1/kuaidi/poll/query', data), + + // SHARE: () => net.SHARE(), + + // 提现 + transfer: data => net.POST('/api/v1/wxpay/transfer', data), + + // 获取我的收藏分页列表 + getStarList: data => net.POST('/api/v1/favorite/get', data), + // 取消收藏 + cancelStar: data => net.DELETE('/api/v1/favorite',data), + //添加收藏 + addStar:data => net.POST('/api/v1/favorite',data) +}; + +export default API \ No newline at end of file diff --git a/api/request.js b/api/request.js new file mode 100644 index 0000000..58da4ab --- /dev/null +++ b/api/request.js @@ -0,0 +1,208 @@ +import config from '../config' + +// import store from '../store' + +const loginUrl = 'pages/user/login'; + +export default { + REQUEST(url, method = 'GET', data, checkLogin = true, header) { + let token = uni.getStorageSync('access_token') || ''; + const headers = { + "Content-Type": "application/json", + "Authorization": token, + "x-token": token, + "token":token, + // "X-Forwarded-For":'client_ip' + // 'Referer':'twzxjy.com' + } + var pages = getCurrentPages(); + var page = pages[pages.length - 1]; + + return uni.request({ + url: config.baseUrl + url, + method, + header: { + ...header, + ...headers + }, + data + }).then(res => { + // console.log(res) + if (res.statusCode === 200 && res.data) { + if (res.data.code === 409) { + uni.showModal({ + title:"提示", + content:"您的账号已在其他设备登录,已强制下线!", + confirmColor: '#006647', + showCancel: false, + success: (res) => { + if (res.confirm) { + uni.removeStorageSync('access_token'); + uni.removeStorageSync('user_info'); + if (checkLogin && page.route != loginUrl) { + uni.navigateTo({ + url: '/' + loginUrl + }); + } + } + } + }); + return { + ...res.data + } + } + if (res.data.code === 5) { // 用户认证失败 + uni.removeStorageSync('access_token'); + if(page.route != loginUrl && checkLogin) { + uni.navigateTo({ + url: '/' + loginUrl + }); + } + } + return res.data; + } else { + const reg = /abort/; + let code = 0; + let msg = (res[0] && res[0].errMsg) || '未知错误'; + if ((res[0] && res[0].errMsg) && reg.test(res[0].errMsg)) { + msg = '网络请求中断' + } + return { + code, + msg, + data: null + } + } + }).catch(parmas => { + // console.log(params) + return parmas + //      return Promise.reject() + }) + }, + + GET(url, body, checkLogin = true, header) { + return this.REQUEST(url, 'GET', body, checkLogin, header); + }, + POST(url, body, checkLogin = true, header) { + return this.REQUEST(url, 'POST', body, checkLogin, header); + }, + PUT(url, body, header) { + return this.REQUEST(url, 'PUT', body, header); + }, + DELETE(url, body, header) { + return this.REQUEST(url, 'DELETE', body, header); + }, + UPLOAD(data) { + return new Promise((resolve, reject) => { + let token = uni.getStorageSync('access_token') || ''; + uni.uploadFile({ + ...data, + url: config.base_url + data.url, + header: { + "Access-Token": token + }, + success(res) { + res.data = JSON.parse(res.data); + if (res.data.code === 401) { + uni.removeStorageSync('access_token'); + uni.removeStorageSync('userInfo'); + + uni.navigateTo({ + url: '/pages/login/login' + }); + } + resolve(res); + }, + fail(e) { + console.log(e); + reject(e) + }, + }); + }); + }, + getShareProvider: () => { + return uni.getProvider({ + service: "share" + }).then(res => { + let data = [] + for (let i = 0; i < res.provider.length; i++) { + switch (res.provider[i]) { + case 'weixin': + data.push({ + name: '微信好友', + id: 'weixin', + icon: '/static/wx.png' + }) + data.push({ + name: '朋友圈', + id: 'weixin', + type: 'WXSenceTimeline', + icon: '/static/pyq.png' + }) + break; + case 'qq': + data.push({ + name: 'QQ好友', + id: 'qq', + icon: '/static/qq.png' + }) + break; + default: + break; + } + } + return data; + }).catch(parmas => { + return Promise.reject() + }); + }, + getPaymentProvider: () => { + return uni.getProvider({ + service: "payment" + }).then(res => { + let data = []; + const aliPay = { + name: '支付宝支付', + id: 'alipay', + icon: '/static/order/zfbp@3x.png' + }; + + const wxPay = { + name: '微信支付', + id: 'wxpay', + icon: '/static/order/wxp@3x.png' + }; + + const yuePay = { + name: '余额支付', + id: 'yepay', + icon: '/static/order/yep@3x.png' + } + + for (let i = 0; i < res[1].provider.length; i++) { + switch (res[1].provider[i]) { + case 'alipay': + data.push({ + ...aliPay + }) + break + case 'wxpay': + data.push({ + ...wxPay + }) + break; + default: + break; + } + } + + //#ifdef H5 + return [aliPay, wxPay, yuePay]; + //#endif + + return [...data, yuePay]; + }).catch(parmas => { + return Promise.reject() + }); + } +} diff --git a/components/.DS_Store b/components/.DS_Store new file mode 100644 index 0000000..fab2580 Binary files /dev/null and b/components/.DS_Store differ diff --git a/components/customer-skeleton/customer-skeleton.vue b/components/customer-skeleton/customer-skeleton.vue new file mode 100644 index 0000000..9db4ff8 --- /dev/null +++ b/components/customer-skeleton/customer-skeleton.vue @@ -0,0 +1,74 @@ + + + + + \ No newline at end of file diff --git a/components/emptyCard.vue b/components/emptyCard.vue new file mode 100644 index 0000000..e6896c4 --- /dev/null +++ b/components/emptyCard.vue @@ -0,0 +1,46 @@ + + + \ No newline at end of file diff --git a/components/goodsCard.vue b/components/goodsCard.vue new file mode 100644 index 0000000..39d8605 --- /dev/null +++ b/components/goodsCard.vue @@ -0,0 +1,219 @@ + + + \ No newline at end of file diff --git a/components/goodsCart.vue b/components/goodsCart.vue new file mode 100644 index 0000000..fd295b7 --- /dev/null +++ b/components/goodsCart.vue @@ -0,0 +1,225 @@ + + + \ No newline at end of file diff --git a/components/goodsCartPay.vue b/components/goodsCartPay.vue new file mode 100644 index 0000000..16e093f --- /dev/null +++ b/components/goodsCartPay.vue @@ -0,0 +1,169 @@ + + + \ No newline at end of file diff --git a/components/goodsInfo.vue b/components/goodsInfo.vue new file mode 100644 index 0000000..6007912 --- /dev/null +++ b/components/goodsInfo.vue @@ -0,0 +1,139 @@ + + + \ No newline at end of file diff --git a/components/goodsSpecs.vue b/components/goodsSpecs.vue new file mode 100644 index 0000000..ada8f5e --- /dev/null +++ b/components/goodsSpecs.vue @@ -0,0 +1,439 @@ + + + \ No newline at end of file diff --git a/components/goodsSpecs2.vue b/components/goodsSpecs2.vue new file mode 100644 index 0000000..7cbd4e0 --- /dev/null +++ b/components/goodsSpecs2.vue @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/components/i-skeleton/i-skeleton.vue b/components/i-skeleton/i-skeleton.vue new file mode 100644 index 0000000..f056c5d --- /dev/null +++ b/components/i-skeleton/i-skeleton.vue @@ -0,0 +1,136 @@ + + + + + \ No newline at end of file diff --git a/components/mapPlat/mapPlat.nvue b/components/mapPlat/mapPlat.nvue new file mode 100644 index 0000000..27ff583 --- /dev/null +++ b/components/mapPlat/mapPlat.nvue @@ -0,0 +1,128 @@ + + + + + diff --git a/components/myButton.vue b/components/myButton.vue new file mode 100644 index 0000000..f77d399 --- /dev/null +++ b/components/myButton.vue @@ -0,0 +1,46 @@ + + + \ No newline at end of file diff --git a/components/myCoupon.vue b/components/myCoupon.vue new file mode 100644 index 0000000..229d835 --- /dev/null +++ b/components/myCoupon.vue @@ -0,0 +1,298 @@ + + + \ No newline at end of file diff --git a/components/mySwiper.vue b/components/mySwiper.vue new file mode 100644 index 0000000..c1811ce --- /dev/null +++ b/components/mySwiper.vue @@ -0,0 +1,97 @@ + + + \ No newline at end of file diff --git a/components/notice.vue b/components/notice.vue new file mode 100644 index 0000000..efd7cef --- /dev/null +++ b/components/notice.vue @@ -0,0 +1,71 @@ + + + \ No newline at end of file diff --git a/components/searchBox.vue b/components/searchBox.vue new file mode 100644 index 0000000..65a765c --- /dev/null +++ b/components/searchBox.vue @@ -0,0 +1,61 @@ + + + \ No newline at end of file diff --git a/config/index.js b/config/index.js new file mode 100644 index 0000000..84dfcd8 --- /dev/null +++ b/config/index.js @@ -0,0 +1,21 @@ +// isdev 为 true 表示开发环境 false 表示发布环境 +const isdev = true; +const baseUrl = isdev ? 'http://niunai.zhitou1688.com' : 'http://niunai.zhitou1688.com';// 办公室接口 & 测试环境 +// const baseUrl = isdev ? 'http://192.168.1.133:8899' : 'https://api.gwkjxb.com';// 办公室接口 & 正式环境 +// const baseUrl = 'https://api.gwkjxb.com';// 正式环境(由于本地测试后台没有启动,暂时通用正式服) + +// const baseUrl = isdev ? 'http://1.117.68.37:8000' : 'https://apiwx.twzxjy.com';// 支付测试接口 +const shareUrl = isdev ? 'https://h5.gwkjxb.com/' : 'http://test_h5.gwkjxb.com/'; +const teacher_admin_url = 'http://teacher.gwkjxb.com/#/login' +const config = { + appName: '牛奶配送', + baseUrl, + appVersion: '1.0.6', + developer: '牛奶配送', + // appLogo: require('../static/logo.png'), + shareUrl, + teacher_admin_url, + appID:'wx2a050f9a5c87a6dc', + isdev +} +export default config \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..c3ff205 --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + +
+ + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..6983d08 --- /dev/null +++ b/main.js @@ -0,0 +1,24 @@ +import App from './App' + +// #ifndef VUE3 +import Vue from 'vue' +import './uni.promisify.adaptor' +Vue.config.productionTip = false +App.mpType = 'app' +const app = new Vue({ + ...App +}) +app.$mount() +// #endif + +// #ifdef VUE3 +import * as Pinia from 'pinia'; +import { createSSRApp } from 'vue' +export function createApp() { + const app = createSSRApp(App) + app.use(Pinia.createPinia()) + return { + app + } +} +// #endif \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..0f88dd7 --- /dev/null +++ b/manifest.json @@ -0,0 +1,72 @@ +{ + "name" : "vision-record", + "appid" : "__UNI__A2B2065", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + /* 5+App特有相关 */ + "app-plus" : { + "usingComponents" : true, + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + /* 模块配置 */ + "modules" : {}, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + /* ios打包配置 */ + "ios" : {}, + /* SDK配置 */ + "sdkConfigs" : {} + } + }, + /* 快应用特有相关 */ + "quickapp" : {}, + /* 小程序特有相关 */ + "mp-weixin" : { + "appid" : "", + "setting" : { + "urlCheck" : false + }, + "usingComponents" : true + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "vueVersion" : "3" +} diff --git a/node_modules/.bin/vue-demi-fix b/node_modules/.bin/vue-demi-fix new file mode 100644 index 0000000..dba2771 --- /dev/null +++ b/node_modules/.bin/vue-demi-fix @@ -0,0 +1,12 @@ +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../vue-demi/bin/vue-demi-fix.js" "$@" +else + exec node "$basedir/../vue-demi/bin/vue-demi-fix.js" "$@" +fi diff --git a/node_modules/.bin/vue-demi-fix.cmd b/node_modules/.bin/vue-demi-fix.cmd new file mode 100644 index 0000000..567cf78 --- /dev/null +++ b/node_modules/.bin/vue-demi-fix.cmd @@ -0,0 +1,17 @@ +@ECHO off +GOTO start +:find_dp0 +SET dp0=%~dp0 +EXIT /b +:start +SETLOCAL +CALL :find_dp0 + +IF EXIST "%dp0%\node.exe" ( + SET "_prog=%dp0%\node.exe" +) ELSE ( + SET "_prog=node" + SET PATHEXT=%PATHEXT:;.JS;=;% +) + +endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vue-demi\bin\vue-demi-fix.js" %* diff --git a/node_modules/.bin/vue-demi-fix.ps1 b/node_modules/.bin/vue-demi-fix.ps1 new file mode 100644 index 0000000..adecc34 --- /dev/null +++ b/node_modules/.bin/vue-demi-fix.ps1 @@ -0,0 +1,28 @@ +#!/usr/bin/env pwsh +$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent + +$exe="" +if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { + # Fix case when both the Windows and Linux builds of Node + # are installed in the same directory + $exe=".exe" +} +$ret=0 +if (Test-Path "$basedir/node$exe") { + # Support pipeline input + if ($MyInvocation.ExpectingInput) { + $input | & "$basedir/node$exe" "$basedir/../vue-demi/bin/vue-demi-fix.js" $args + } else { + & "$basedir/node$exe" "$basedir/../vue-demi/bin/vue-demi-fix.js" $args + } + $ret=$LASTEXITCODE +} else { + # Support pipeline input + if ($MyInvocation.ExpectingInput) { + $input | & "node$exe" "$basedir/../vue-demi/bin/vue-demi-fix.js" $args + } else { + & "node$exe" "$basedir/../vue-demi/bin/vue-demi-fix.js" $args + } + $ret=$LASTEXITCODE +} +exit $ret diff --git a/node_modules/.bin/vue-demi-switch b/node_modules/.bin/vue-demi-switch new file mode 100644 index 0000000..458c052 --- /dev/null +++ b/node_modules/.bin/vue-demi-switch @@ -0,0 +1,12 @@ +#!/bin/sh +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") + +case `uname` in + *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;; +esac + +if [ -x "$basedir/node" ]; then + exec "$basedir/node" "$basedir/../vue-demi/bin/vue-demi-switch.js" "$@" +else + exec node "$basedir/../vue-demi/bin/vue-demi-switch.js" "$@" +fi diff --git a/node_modules/.bin/vue-demi-switch.cmd b/node_modules/.bin/vue-demi-switch.cmd new file mode 100644 index 0000000..fce7991 --- /dev/null +++ b/node_modules/.bin/vue-demi-switch.cmd @@ -0,0 +1,17 @@ +@ECHO off +GOTO start +:find_dp0 +SET dp0=%~dp0 +EXIT /b +:start +SETLOCAL +CALL :find_dp0 + +IF EXIST "%dp0%\node.exe" ( + SET "_prog=%dp0%\node.exe" +) ELSE ( + SET "_prog=node" + SET PATHEXT=%PATHEXT:;.JS;=;% +) + +endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vue-demi\bin\vue-demi-switch.js" %* diff --git a/node_modules/.bin/vue-demi-switch.ps1 b/node_modules/.bin/vue-demi-switch.ps1 new file mode 100644 index 0000000..fbb4d69 --- /dev/null +++ b/node_modules/.bin/vue-demi-switch.ps1 @@ -0,0 +1,28 @@ +#!/usr/bin/env pwsh +$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent + +$exe="" +if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { + # Fix case when both the Windows and Linux builds of Node + # are installed in the same directory + $exe=".exe" +} +$ret=0 +if (Test-Path "$basedir/node$exe") { + # Support pipeline input + if ($MyInvocation.ExpectingInput) { + $input | & "$basedir/node$exe" "$basedir/../vue-demi/bin/vue-demi-switch.js" $args + } else { + & "$basedir/node$exe" "$basedir/../vue-demi/bin/vue-demi-switch.js" $args + } + $ret=$LASTEXITCODE +} else { + # Support pipeline input + if ($MyInvocation.ExpectingInput) { + $input | & "node$exe" "$basedir/../vue-demi/bin/vue-demi-switch.js" $args + } else { + & "node$exe" "$basedir/../vue-demi/bin/vue-demi-switch.js" $args + } + $ret=$LASTEXITCODE +} +exit $ret diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json new file mode 100644 index 0000000..58bb735 --- /dev/null +++ b/node_modules/.package-lock.json @@ -0,0 +1,69 @@ +{ + "name": "version-record", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "node_modules/@vue/devtools-api": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", + "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" + }, + "node_modules/pinia": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.6.tgz", + "integrity": "sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==", + "dependencies": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.3.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz", + "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==", + "peer": true + }, + "node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + } + } +} diff --git a/node_modules/@vue/devtools-api/lib/cjs/api/api.js b/node_modules/@vue/devtools-api/lib/cjs/api/api.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/api/api.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@vue/devtools-api/lib/cjs/api/app.js b/node_modules/@vue/devtools-api/lib/cjs/api/app.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/api/app.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@vue/devtools-api/lib/cjs/api/component.js b/node_modules/@vue/devtools-api/lib/cjs/api/component.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/api/component.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@vue/devtools-api/lib/cjs/api/context.js b/node_modules/@vue/devtools-api/lib/cjs/api/context.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/api/context.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@vue/devtools-api/lib/cjs/api/hooks.js b/node_modules/@vue/devtools-api/lib/cjs/api/hooks.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/api/hooks.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@vue/devtools-api/lib/cjs/api/index.js b/node_modules/@vue/devtools-api/lib/cjs/api/index.js new file mode 100644 index 0000000..22f7589 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/api/index.js @@ -0,0 +1,22 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./api.js"), exports); +__exportStar(require("./app.js"), exports); +__exportStar(require("./component.js"), exports); +__exportStar(require("./context.js"), exports); +__exportStar(require("./hooks.js"), exports); +__exportStar(require("./util.js"), exports); diff --git a/node_modules/@vue/devtools-api/lib/cjs/api/util.js b/node_modules/@vue/devtools-api/lib/cjs/api/util.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/api/util.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@vue/devtools-api/lib/cjs/const.js b/node_modules/@vue/devtools-api/lib/cjs/const.js new file mode 100644 index 0000000..84d408c --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/const.js @@ -0,0 +1,5 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.HOOK_PLUGIN_SETTINGS_SET = exports.HOOK_SETUP = void 0; +exports.HOOK_SETUP = 'devtools-plugin:setup'; +exports.HOOK_PLUGIN_SETTINGS_SET = 'plugin:settings:set'; diff --git a/node_modules/@vue/devtools-api/lib/cjs/env.js b/node_modules/@vue/devtools-api/lib/cjs/env.js new file mode 100644 index 0000000..178d457 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/env.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.isProxyAvailable = exports.getTarget = exports.getDevtoolsGlobalHook = void 0; +function getDevtoolsGlobalHook() { + return getTarget().__VUE_DEVTOOLS_GLOBAL_HOOK__; +} +exports.getDevtoolsGlobalHook = getDevtoolsGlobalHook; +function getTarget() { + // @ts-ignore + return (typeof navigator !== 'undefined' && typeof window !== 'undefined') + ? window + : typeof global !== 'undefined' + ? global + : {}; +} +exports.getTarget = getTarget; +exports.isProxyAvailable = typeof Proxy === 'function'; diff --git a/node_modules/@vue/devtools-api/lib/cjs/index.js b/node_modules/@vue/devtools-api/lib/cjs/index.js new file mode 100644 index 0000000..249ac4d --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/index.js @@ -0,0 +1,44 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setupDevtoolsPlugin = void 0; +const env_js_1 = require("./env.js"); +const const_js_1 = require("./const.js"); +const proxy_js_1 = require("./proxy.js"); +__exportStar(require("./api/index.js"), exports); +__exportStar(require("./plugin.js"), exports); +__exportStar(require("./time.js"), exports); +function setupDevtoolsPlugin(pluginDescriptor, setupFn) { + const descriptor = pluginDescriptor; + const target = (0, env_js_1.getTarget)(); + const hook = (0, env_js_1.getDevtoolsGlobalHook)(); + const enableProxy = env_js_1.isProxyAvailable && descriptor.enableEarlyProxy; + if (hook && (target.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__ || !enableProxy)) { + hook.emit(const_js_1.HOOK_SETUP, pluginDescriptor, setupFn); + } + else { + const proxy = enableProxy ? new proxy_js_1.ApiProxy(descriptor, hook) : null; + const list = target.__VUE_DEVTOOLS_PLUGINS__ = target.__VUE_DEVTOOLS_PLUGINS__ || []; + list.push({ + pluginDescriptor: descriptor, + setupFn, + proxy, + }); + if (proxy) + setupFn(proxy.proxiedTarget); + } +} +exports.setupDevtoolsPlugin = setupDevtoolsPlugin; diff --git a/node_modules/@vue/devtools-api/lib/cjs/plugin.js b/node_modules/@vue/devtools-api/lib/cjs/plugin.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/plugin.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/@vue/devtools-api/lib/cjs/proxy.js b/node_modules/@vue/devtools-api/lib/cjs/proxy.js new file mode 100644 index 0000000..5385e60 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/proxy.js @@ -0,0 +1,111 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ApiProxy = void 0; +const const_js_1 = require("./const.js"); +const time_js_1 = require("./time.js"); +class ApiProxy { + constructor(plugin, hook) { + this.target = null; + this.targetQueue = []; + this.onQueue = []; + this.plugin = plugin; + this.hook = hook; + const defaultSettings = {}; + if (plugin.settings) { + for (const id in plugin.settings) { + const item = plugin.settings[id]; + defaultSettings[id] = item.defaultValue; + } + } + const localSettingsSaveId = `__vue-devtools-plugin-settings__${plugin.id}`; + let currentSettings = Object.assign({}, defaultSettings); + try { + const raw = localStorage.getItem(localSettingsSaveId); + const data = JSON.parse(raw); + Object.assign(currentSettings, data); + } + catch (e) { + // noop + } + this.fallbacks = { + getSettings() { + return currentSettings; + }, + setSettings(value) { + try { + localStorage.setItem(localSettingsSaveId, JSON.stringify(value)); + } + catch (e) { + // noop + } + currentSettings = value; + }, + now() { + return (0, time_js_1.now)(); + }, + }; + if (hook) { + hook.on(const_js_1.HOOK_PLUGIN_SETTINGS_SET, (pluginId, value) => { + if (pluginId === this.plugin.id) { + this.fallbacks.setSettings(value); + } + }); + } + this.proxiedOn = new Proxy({}, { + get: (_target, prop) => { + if (this.target) { + return this.target.on[prop]; + } + else { + return (...args) => { + this.onQueue.push({ + method: prop, + args, + }); + }; + } + }, + }); + this.proxiedTarget = new Proxy({}, { + get: (_target, prop) => { + if (this.target) { + return this.target[prop]; + } + else if (prop === 'on') { + return this.proxiedOn; + } + else if (Object.keys(this.fallbacks).includes(prop)) { + return (...args) => { + this.targetQueue.push({ + method: prop, + args, + resolve: () => { }, + }); + return this.fallbacks[prop](...args); + }; + } + else { + return (...args) => { + return new Promise(resolve => { + this.targetQueue.push({ + method: prop, + args, + resolve, + }); + }); + }; + } + }, + }); + } + async setRealTarget(target) { + this.target = target; + for (const item of this.onQueue) { + this.target.on[item.method](...item.args); + } + for (const item of this.targetQueue) { + item.resolve(await this.target[item.method](...item.args)); + } + } +} +exports.ApiProxy = ApiProxy; diff --git a/node_modules/@vue/devtools-api/lib/cjs/time.js b/node_modules/@vue/devtools-api/lib/cjs/time.js new file mode 100644 index 0000000..5b17a25 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/cjs/time.js @@ -0,0 +1,28 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.now = exports.isPerformanceSupported = void 0; +let supported; +let perf; +function isPerformanceSupported() { + var _a; + if (supported !== undefined) { + return supported; + } + if (typeof window !== 'undefined' && window.performance) { + supported = true; + perf = window.performance; + } + else if (typeof global !== 'undefined' && ((_a = global.perf_hooks) === null || _a === void 0 ? void 0 : _a.performance)) { + supported = true; + perf = global.perf_hooks.performance; + } + else { + supported = false; + } + return supported; +} +exports.isPerformanceSupported = isPerformanceSupported; +function now() { + return isPerformanceSupported() ? perf.now() : Date.now(); +} +exports.now = now; diff --git a/node_modules/@vue/devtools-api/lib/esm/api/api.d.ts b/node_modules/@vue/devtools-api/lib/esm/api/api.d.ts new file mode 100644 index 0000000..071312a --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/api.d.ts @@ -0,0 +1,108 @@ +import type { ComponentBounds, Hookable } from './hooks.js'; +import type { Context } from './context.js'; +import type { ComponentInstance, ComponentState, StateBase } from './component.js'; +import type { App } from './app.js'; +import type { ID } from './util.js'; +export interface DevtoolsPluginApi { + on: Hookable; + notifyComponentUpdate(instance?: ComponentInstance): void; + addTimelineLayer(options: TimelineLayerOptions): void; + addTimelineEvent(options: TimelineEventOptions): void; + addInspector(options: CustomInspectorOptions): void; + sendInspectorTree(inspectorId: string): void; + sendInspectorState(inspectorId: string): void; + selectInspectorNode(inspectorId: string, nodeId: string): void; + getComponentBounds(instance: ComponentInstance): Promise; + getComponentName(instance: ComponentInstance): Promise; + getComponentInstances(app: App): Promise; + highlightElement(instance: ComponentInstance): void; + unhighlightElement(): void; + getSettings(pluginId?: string): TSettings; + now(): number; + /** + * @private Not implemented yet + */ + setSettings(values: TSettings): void; +} +export interface AppRecord { + id: string; + name: string; + instanceMap: Map; + rootInstance: ComponentInstance; +} +export interface TimelineLayerOptions { + id: string; + label: string; + color: number; + skipScreenshots?: boolean; + groupsOnly?: boolean; + ignoreNoDurationGroups?: boolean; + screenshotOverlayRender?: (event: TimelineEvent & ScreenshotOverlayEvent, ctx: ScreenshotOverlayRenderContext) => ScreenshotOverlayRenderResult | Promise; +} +export interface ScreenshotOverlayEvent { + layerId: string; + renderMeta: any; +} +export interface ScreenshotOverlayRenderContext { + screenshot: ScreenshotData; + events: (TimelineEvent & ScreenshotOverlayEvent)[]; + index: number; +} +export declare type ScreenshotOverlayRenderResult = HTMLElement | string | false; +export interface ScreenshotData { + time: number; +} +export interface TimelineEventOptions { + layerId: string; + event: TimelineEvent; + all?: boolean; +} +export interface TimelineEvent { + time: number; + data: TData; + logType?: 'default' | 'warning' | 'error'; + meta?: TMeta; + groupId?: ID; + title?: string; + subtitle?: string; +} +export interface TimelineMarkerOptions { + id: string; + time: number; + color: number; + label: string; + all?: boolean; +} +export interface CustomInspectorOptions { + id: string; + label: string; + icon?: string; + treeFilterPlaceholder?: string; + stateFilterPlaceholder?: string; + noSelectionText?: string; + actions?: { + icon: string; + tooltip?: string; + action: () => void | Promise; + }[]; + nodeActions?: { + icon: string; + tooltip?: string; + action: (nodeId: string) => void | Promise; + }[]; +} +export interface CustomInspectorNode { + id: string; + label: string; + children?: CustomInspectorNode[]; + tags?: InspectorNodeTag[]; +} +export interface InspectorNodeTag { + label: string; + textColor: number; + backgroundColor: number; + tooltip?: string; +} +export interface CustomInspectorState { + [key: string]: (StateBase | Omit)[]; +} diff --git a/node_modules/@vue/devtools-api/lib/esm/api/api.js b/node_modules/@vue/devtools-api/lib/esm/api/api.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/api.js @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/api/app.d.ts b/node_modules/@vue/devtools-api/lib/esm/api/app.d.ts new file mode 100644 index 0000000..42638c0 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/app.d.ts @@ -0,0 +1 @@ +export declare type App = any; diff --git a/node_modules/@vue/devtools-api/lib/esm/api/app.js b/node_modules/@vue/devtools-api/lib/esm/api/app.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/app.js @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/api/component.d.ts b/node_modules/@vue/devtools-api/lib/esm/api/component.d.ts new file mode 100644 index 0000000..335dd04 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/component.d.ts @@ -0,0 +1,78 @@ +import type { InspectorNodeTag } from './api.js'; +import type { ID } from './util.js'; +export declare type ComponentInstance = any; +export interface ComponentTreeNode { + uid: ID; + id: string; + name: string; + renderKey: string | number; + inactive: boolean; + isFragment: boolean; + hasChildren: boolean; + children: ComponentTreeNode[]; + domOrder?: number[]; + consoleId?: string; + isRouterView?: boolean; + macthedRouteSegment?: string; + tags: InspectorNodeTag[]; + autoOpen: boolean; + meta?: any; +} +export interface InspectedComponentData { + id: string; + name: string; + file: string; + state: ComponentState[]; + functional?: boolean; +} +export interface StateBase { + key: string; + value: any; + editable?: boolean; + objectType?: 'ref' | 'reactive' | 'computed' | 'other'; + raw?: string; +} +export interface ComponentStateBase extends StateBase { + type: string; +} +export interface ComponentPropState extends ComponentStateBase { + meta?: { + type: string; + required: boolean; + /** Vue 1 only */ + mode?: 'default' | 'sync' | 'once'; + }; +} +export declare type ComponentBuiltinCustomStateTypes = 'function' | 'map' | 'set' | 'reference' | 'component' | 'component-definition' | 'router' | 'store'; +export interface ComponentCustomState extends ComponentStateBase { + value: CustomState; +} +export declare type CustomState = { + _custom: { + type: ComponentBuiltinCustomStateTypes | string; + objectType?: string; + display?: string; + tooltip?: string; + value?: any; + abstract?: boolean; + file?: string; + uid?: number; + readOnly?: boolean; + /** Configure immediate child fields */ + fields?: { + abstract?: boolean; + }; + id?: any; + actions?: { + icon: string; + tooltip?: string; + action: () => void | Promise; + }[]; + /** internal */ + _reviveId?: number; + }; +}; +export declare type ComponentState = ComponentStateBase | ComponentPropState | ComponentCustomState; +export interface ComponentDevtoolsOptions { + hide?: boolean; +} diff --git a/node_modules/@vue/devtools-api/lib/esm/api/component.js b/node_modules/@vue/devtools-api/lib/esm/api/component.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/component.js @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/api/context.d.ts b/node_modules/@vue/devtools-api/lib/esm/api/context.d.ts new file mode 100644 index 0000000..29388f1 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/context.d.ts @@ -0,0 +1,5 @@ +import type { AppRecord } from './api.js'; +export interface Context { + currentTab: string; + currentAppRecord: AppRecord; +} diff --git a/node_modules/@vue/devtools-api/lib/esm/api/context.js b/node_modules/@vue/devtools-api/lib/esm/api/context.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/context.js @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/api/hooks.d.ts b/node_modules/@vue/devtools-api/lib/esm/api/hooks.d.ts new file mode 100644 index 0000000..c980b13 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/hooks.d.ts @@ -0,0 +1,180 @@ +import type { ComponentTreeNode, InspectedComponentData, ComponentInstance, ComponentDevtoolsOptions } from './component.js'; +import type { App } from './app.js'; +import type { CustomInspectorNode, CustomInspectorState, TimelineEvent } from './api.js'; +export declare const enum Hooks { + TRANSFORM_CALL = "transformCall", + GET_APP_RECORD_NAME = "getAppRecordName", + GET_APP_ROOT_INSTANCE = "getAppRootInstance", + REGISTER_APPLICATION = "registerApplication", + WALK_COMPONENT_TREE = "walkComponentTree", + VISIT_COMPONENT_TREE = "visitComponentTree", + WALK_COMPONENT_PARENTS = "walkComponentParents", + INSPECT_COMPONENT = "inspectComponent", + GET_COMPONENT_BOUNDS = "getComponentBounds", + GET_COMPONENT_NAME = "getComponentName", + GET_COMPONENT_INSTANCES = "getComponentInstances", + GET_ELEMENT_COMPONENT = "getElementComponent", + GET_COMPONENT_ROOT_ELEMENTS = "getComponentRootElements", + EDIT_COMPONENT_STATE = "editComponentState", + GET_COMPONENT_DEVTOOLS_OPTIONS = "getAppDevtoolsOptions", + GET_COMPONENT_RENDER_CODE = "getComponentRenderCode", + INSPECT_TIMELINE_EVENT = "inspectTimelineEvent", + TIMELINE_CLEARED = "timelineCleared", + GET_INSPECTOR_TREE = "getInspectorTree", + GET_INSPECTOR_STATE = "getInspectorState", + EDIT_INSPECTOR_STATE = "editInspectorState", + SET_PLUGIN_SETTINGS = "setPluginSettings" +} +export interface ComponentBounds { + left: number; + top: number; + width: number; + height: number; +} +export declare type HookPayloads = { + [Hooks.TRANSFORM_CALL]: { + callName: string; + inArgs: any[]; + outArgs: any[]; + }; + [Hooks.GET_APP_RECORD_NAME]: { + app: App; + name: string; + }; + [Hooks.GET_APP_ROOT_INSTANCE]: { + app: App; + root: ComponentInstance; + }; + [Hooks.REGISTER_APPLICATION]: { + app: App; + }; + [Hooks.WALK_COMPONENT_TREE]: { + componentInstance: ComponentInstance; + componentTreeData: ComponentTreeNode[]; + maxDepth: number; + filter: string; + recursively: boolean; + }; + [Hooks.VISIT_COMPONENT_TREE]: { + app: App; + componentInstance: ComponentInstance; + treeNode: ComponentTreeNode; + filter: string; + }; + [Hooks.WALK_COMPONENT_PARENTS]: { + componentInstance: ComponentInstance; + parentInstances: ComponentInstance[]; + }; + [Hooks.INSPECT_COMPONENT]: { + app: App; + componentInstance: ComponentInstance; + instanceData: InspectedComponentData; + }; + [Hooks.GET_COMPONENT_BOUNDS]: { + componentInstance: ComponentInstance; + bounds: ComponentBounds; + }; + [Hooks.GET_COMPONENT_NAME]: { + componentInstance: ComponentInstance; + name: string; + }; + [Hooks.GET_COMPONENT_INSTANCES]: { + app: App; + componentInstances: ComponentInstance[]; + }; + [Hooks.GET_ELEMENT_COMPONENT]: { + element: HTMLElement | any; + componentInstance: ComponentInstance; + }; + [Hooks.GET_COMPONENT_ROOT_ELEMENTS]: { + componentInstance: ComponentInstance; + rootElements: (HTMLElement | any)[]; + }; + [Hooks.EDIT_COMPONENT_STATE]: { + app: App; + componentInstance: ComponentInstance; + path: string[]; + type: string; + state: EditStatePayload; + set: (object: any, path?: string | (string[]), value?: any, cb?: (object: any, field: string, value: any) => void) => void; + }; + [Hooks.GET_COMPONENT_DEVTOOLS_OPTIONS]: { + componentInstance: ComponentInstance; + options: ComponentDevtoolsOptions; + }; + [Hooks.GET_COMPONENT_RENDER_CODE]: { + componentInstance: ComponentInstance; + code: string; + }; + [Hooks.INSPECT_TIMELINE_EVENT]: { + app: App; + layerId: string; + event: TimelineEvent; + all?: boolean; + data: any; + }; + [Hooks.TIMELINE_CLEARED]: Record; + [Hooks.GET_INSPECTOR_TREE]: { + app: App; + inspectorId: string; + filter: string; + rootNodes: CustomInspectorNode[]; + }; + [Hooks.GET_INSPECTOR_STATE]: { + app: App; + inspectorId: string; + nodeId: string; + state: CustomInspectorState; + }; + [Hooks.EDIT_INSPECTOR_STATE]: { + app: App; + inspectorId: string; + nodeId: string; + path: string[]; + type: string; + state: EditStatePayload; + set: (object: any, path?: string | (string[]), value?: any, cb?: (object: any, field: string, value: any) => void) => void; + }; + [Hooks.SET_PLUGIN_SETTINGS]: { + app: App; + pluginId: string; + key: string; + newValue: any; + oldValue: any; + settings: any; + }; +}; +export declare type EditStatePayload = { + value: any; + newKey?: string | null; + remove?: undefined | false; +} | { + value?: undefined; + newKey?: undefined; + remove: true; +}; +export declare type HookHandler = (payload: TPayload, ctx: TContext) => void | Promise; +export interface Hookable { + transformCall(handler: HookHandler): any; + getAppRecordName(handler: HookHandler): any; + getAppRootInstance(handler: HookHandler): any; + registerApplication(handler: HookHandler): any; + walkComponentTree(handler: HookHandler): any; + visitComponentTree(handler: HookHandler): any; + walkComponentParents(handler: HookHandler): any; + inspectComponent(handler: HookHandler): any; + getComponentBounds(handler: HookHandler): any; + getComponentName(handler: HookHandler): any; + getComponentInstances(handler: HookHandler): any; + getElementComponent(handler: HookHandler): any; + getComponentRootElements(handler: HookHandler): any; + editComponentState(handler: HookHandler): any; + getComponentDevtoolsOptions(handler: HookHandler): any; + getComponentRenderCode(handler: HookHandler): any; + inspectTimelineEvent(handler: HookHandler): any; + timelineCleared(handler: HookHandler): any; + getInspectorTree(handler: HookHandler): any; + getInspectorState(handler: HookHandler): any; + editInspectorState(handler: HookHandler): any; + setPluginSettings(handler: HookHandler): any; +} diff --git a/node_modules/@vue/devtools-api/lib/esm/api/hooks.js b/node_modules/@vue/devtools-api/lib/esm/api/hooks.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/hooks.js @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/api/index.d.ts b/node_modules/@vue/devtools-api/lib/esm/api/index.d.ts new file mode 100644 index 0000000..70d09d2 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/index.d.ts @@ -0,0 +1,6 @@ +export * from './api.js'; +export * from './app.js'; +export * from './component.js'; +export * from './context.js'; +export * from './hooks.js'; +export * from './util.js'; diff --git a/node_modules/@vue/devtools-api/lib/esm/api/index.js b/node_modules/@vue/devtools-api/lib/esm/api/index.js new file mode 100644 index 0000000..70d09d2 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/index.js @@ -0,0 +1,6 @@ +export * from './api.js'; +export * from './app.js'; +export * from './component.js'; +export * from './context.js'; +export * from './hooks.js'; +export * from './util.js'; diff --git a/node_modules/@vue/devtools-api/lib/esm/api/util.d.ts b/node_modules/@vue/devtools-api/lib/esm/api/util.d.ts new file mode 100644 index 0000000..7c437e5 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/util.d.ts @@ -0,0 +1,4 @@ +export declare type ID = number | string; +export interface WithId { + id: ID; +} diff --git a/node_modules/@vue/devtools-api/lib/esm/api/util.js b/node_modules/@vue/devtools-api/lib/esm/api/util.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/api/util.js @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/const.d.ts b/node_modules/@vue/devtools-api/lib/esm/const.d.ts new file mode 100644 index 0000000..289b254 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/const.d.ts @@ -0,0 +1,2 @@ +export declare const HOOK_SETUP = "devtools-plugin:setup"; +export declare const HOOK_PLUGIN_SETTINGS_SET = "plugin:settings:set"; diff --git a/node_modules/@vue/devtools-api/lib/esm/const.js b/node_modules/@vue/devtools-api/lib/esm/const.js new file mode 100644 index 0000000..872ea3e --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/const.js @@ -0,0 +1,2 @@ +export const HOOK_SETUP = 'devtools-plugin:setup'; +export const HOOK_PLUGIN_SETTINGS_SET = 'plugin:settings:set'; diff --git a/node_modules/@vue/devtools-api/lib/esm/env.d.ts b/node_modules/@vue/devtools-api/lib/esm/env.d.ts new file mode 100644 index 0000000..16c1399 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/env.d.ts @@ -0,0 +1,15 @@ +import type { PluginDescriptor, SetupFunction } from './index.js'; +import type { ApiProxy } from './proxy.js'; +export interface PluginQueueItem { + pluginDescriptor: PluginDescriptor; + setupFn: SetupFunction; + proxy?: ApiProxy; +} +interface GlobalTarget { + __VUE_DEVTOOLS_PLUGINS__?: PluginQueueItem[]; + __VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__?: boolean; +} +export declare function getDevtoolsGlobalHook(): any; +export declare function getTarget(): GlobalTarget; +export declare const isProxyAvailable: boolean; +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/env.js b/node_modules/@vue/devtools-api/lib/esm/env.js new file mode 100644 index 0000000..6713a93 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/env.js @@ -0,0 +1,12 @@ +export function getDevtoolsGlobalHook() { + return getTarget().__VUE_DEVTOOLS_GLOBAL_HOOK__; +} +export function getTarget() { + // @ts-ignore + return (typeof navigator !== 'undefined' && typeof window !== 'undefined') + ? window + : typeof global !== 'undefined' + ? global + : {}; +} +export const isProxyAvailable = typeof Proxy === 'function'; diff --git a/node_modules/@vue/devtools-api/lib/esm/index.d.ts b/node_modules/@vue/devtools-api/lib/esm/index.d.ts new file mode 100644 index 0000000..6833324 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/index.d.ts @@ -0,0 +1,18 @@ +import type { DevtoolsPluginApi } from './api/index.js'; +import type { PluginDescriptor, ExtractSettingsTypes, PluginSettingsItem } from './plugin.js'; +export * from './api/index.js'; +export * from './plugin.js'; +export * from './time.js'; +export { PluginQueueItem } from './env.js'; +declare type Cast = A extends B ? A : B; +declare type Narrowable = string | number | bigint | boolean; +declare type Narrow = Cast; +})>; +declare type Exact = { + [K in keyof C]: K extends keyof T ? T[K] : never; +}; +export declare type SetupFunction = (api: DevtoolsPluginApi) => void; +export declare function setupDevtoolsPlugin, TSettings = ExtractSettingsTypes ? S : Record : Record>>(pluginDescriptor: Narrow, setupFn: SetupFunction): void; diff --git a/node_modules/@vue/devtools-api/lib/esm/index.js b/node_modules/@vue/devtools-api/lib/esm/index.js new file mode 100644 index 0000000..39259bc --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/index.js @@ -0,0 +1,26 @@ +import { getTarget, getDevtoolsGlobalHook, isProxyAvailable } from './env.js'; +import { HOOK_SETUP } from './const.js'; +import { ApiProxy } from './proxy.js'; +export * from './api/index.js'; +export * from './plugin.js'; +export * from './time.js'; +export function setupDevtoolsPlugin(pluginDescriptor, setupFn) { + const descriptor = pluginDescriptor; + const target = getTarget(); + const hook = getDevtoolsGlobalHook(); + const enableProxy = isProxyAvailable && descriptor.enableEarlyProxy; + if (hook && (target.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__ || !enableProxy)) { + hook.emit(HOOK_SETUP, pluginDescriptor, setupFn); + } + else { + const proxy = enableProxy ? new ApiProxy(descriptor, hook) : null; + const list = target.__VUE_DEVTOOLS_PLUGINS__ = target.__VUE_DEVTOOLS_PLUGINS__ || []; + list.push({ + pluginDescriptor: descriptor, + setupFn, + proxy, + }); + if (proxy) + setupFn(proxy.proxiedTarget); + } +} diff --git a/node_modules/@vue/devtools-api/lib/esm/plugin.d.ts b/node_modules/@vue/devtools-api/lib/esm/plugin.d.ts new file mode 100644 index 0000000..dd182ca --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/plugin.d.ts @@ -0,0 +1,47 @@ +import type { App } from './api/index.js'; +export interface PluginDescriptor { + id: string; + label: string; + app: App; + packageName?: string; + homepage?: string; + componentStateTypes?: string[]; + logo?: string; + disableAppScope?: boolean; + disablePluginScope?: boolean; + /** + * Run the plugin setup and expose the api even if the devtools is not opened yet. + * Useful to record timeline events early. + */ + enableEarlyProxy?: boolean; + settings?: Record; +} +export declare type PluginSettingsItem = { + label: string; + description?: string; +} & ({ + type: 'boolean'; + defaultValue: boolean; +} | { + type: 'choice'; + defaultValue: string | number; + options: { + value: string | number; + label: string; + }[]; + component?: 'select' | 'button-group'; +} | { + type: 'text'; + defaultValue: string; +}); +declare type InferSettingsType = [T] extends [{ + type: 'boolean'; +}] ? boolean : [T] extends [{ + type: 'choice'; +}] ? T['options'][number]['value'] : [T] extends [{ + type: 'text'; +}] ? string : unknown; +export declare type ExtractSettingsTypes> = { + [K in keyof O]: InferSettingsType; +}; +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/plugin.js b/node_modules/@vue/devtools-api/lib/esm/plugin.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/plugin.js @@ -0,0 +1 @@ +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/proxy.d.ts b/node_modules/@vue/devtools-api/lib/esm/proxy.d.ts new file mode 100644 index 0000000..38ff867 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/proxy.d.ts @@ -0,0 +1,20 @@ +import type { Context, DevtoolsPluginApi, Hookable } from './api/index.js'; +import type { PluginDescriptor } from './plugin.js'; +interface QueueItem { + method: string; + args: any[]; + resolve?: (value?: any) => void; +} +export declare class ApiProxy = DevtoolsPluginApi> { + target: TTarget | null; + targetQueue: QueueItem[]; + proxiedTarget: TTarget; + onQueue: QueueItem[]; + proxiedOn: Hookable; + plugin: PluginDescriptor; + hook: any; + fallbacks: Record; + constructor(plugin: PluginDescriptor, hook: any); + setRealTarget(target: TTarget): Promise; +} +export {}; diff --git a/node_modules/@vue/devtools-api/lib/esm/proxy.js b/node_modules/@vue/devtools-api/lib/esm/proxy.js new file mode 100644 index 0000000..639077e --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/proxy.js @@ -0,0 +1,107 @@ +import { HOOK_PLUGIN_SETTINGS_SET } from './const.js'; +import { now } from './time.js'; +export class ApiProxy { + constructor(plugin, hook) { + this.target = null; + this.targetQueue = []; + this.onQueue = []; + this.plugin = plugin; + this.hook = hook; + const defaultSettings = {}; + if (plugin.settings) { + for (const id in plugin.settings) { + const item = plugin.settings[id]; + defaultSettings[id] = item.defaultValue; + } + } + const localSettingsSaveId = `__vue-devtools-plugin-settings__${plugin.id}`; + let currentSettings = Object.assign({}, defaultSettings); + try { + const raw = localStorage.getItem(localSettingsSaveId); + const data = JSON.parse(raw); + Object.assign(currentSettings, data); + } + catch (e) { + // noop + } + this.fallbacks = { + getSettings() { + return currentSettings; + }, + setSettings(value) { + try { + localStorage.setItem(localSettingsSaveId, JSON.stringify(value)); + } + catch (e) { + // noop + } + currentSettings = value; + }, + now() { + return now(); + }, + }; + if (hook) { + hook.on(HOOK_PLUGIN_SETTINGS_SET, (pluginId, value) => { + if (pluginId === this.plugin.id) { + this.fallbacks.setSettings(value); + } + }); + } + this.proxiedOn = new Proxy({}, { + get: (_target, prop) => { + if (this.target) { + return this.target.on[prop]; + } + else { + return (...args) => { + this.onQueue.push({ + method: prop, + args, + }); + }; + } + }, + }); + this.proxiedTarget = new Proxy({}, { + get: (_target, prop) => { + if (this.target) { + return this.target[prop]; + } + else if (prop === 'on') { + return this.proxiedOn; + } + else if (Object.keys(this.fallbacks).includes(prop)) { + return (...args) => { + this.targetQueue.push({ + method: prop, + args, + resolve: () => { }, + }); + return this.fallbacks[prop](...args); + }; + } + else { + return (...args) => { + return new Promise(resolve => { + this.targetQueue.push({ + method: prop, + args, + resolve, + }); + }); + }; + } + }, + }); + } + async setRealTarget(target) { + this.target = target; + for (const item of this.onQueue) { + this.target.on[item.method](...item.args); + } + for (const item of this.targetQueue) { + item.resolve(await this.target[item.method](...item.args)); + } + } +} diff --git a/node_modules/@vue/devtools-api/lib/esm/time.d.ts b/node_modules/@vue/devtools-api/lib/esm/time.d.ts new file mode 100644 index 0000000..1aebade --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/time.d.ts @@ -0,0 +1,2 @@ +export declare function isPerformanceSupported(): boolean; +export declare function now(): number; diff --git a/node_modules/@vue/devtools-api/lib/esm/time.js b/node_modules/@vue/devtools-api/lib/esm/time.js new file mode 100644 index 0000000..99bedb5 --- /dev/null +++ b/node_modules/@vue/devtools-api/lib/esm/time.js @@ -0,0 +1,23 @@ +let supported; +let perf; +export function isPerformanceSupported() { + var _a; + if (supported !== undefined) { + return supported; + } + if (typeof window !== 'undefined' && window.performance) { + supported = true; + perf = window.performance; + } + else if (typeof global !== 'undefined' && ((_a = global.perf_hooks) === null || _a === void 0 ? void 0 : _a.performance)) { + supported = true; + perf = global.perf_hooks.performance; + } + else { + supported = false; + } + return supported; +} +export function now() { + return isPerformanceSupported() ? perf.now() : Date.now(); +} diff --git a/node_modules/@vue/devtools-api/package.json b/node_modules/@vue/devtools-api/package.json new file mode 100644 index 0000000..0fe878b --- /dev/null +++ b/node_modules/@vue/devtools-api/package.json @@ -0,0 +1,37 @@ +{ + "name": "@vue/devtools-api", + "version": "6.5.0", + "description": "Interact with the Vue devtools from the page", + "main": "lib/cjs/index.js", + "browser": "lib/esm/index.js", + "module": "lib/esm/index.js", + "types": "lib/esm/index.d.ts", + "sideEffects": false, + "author": { + "name": "Guillaume Chau" + }, + "files": [ + "lib/esm", + "lib/cjs" + ], + "license": "MIT", + "repository": { + "url": "https://github.com/vuejs/vue-devtools.git", + "type": "git", + "directory": "packages/api" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "rimraf lib && yarn build:esm && yarn build:cjs", + "build:esm": "tsc --module es2015 --outDir lib/esm -d", + "build:cjs": "tsc --module commonjs --outDir lib/cjs", + "build:watch": "yarn tsc --module es2015 --outDir lib/esm -d -w --sourceMap" + }, + "devDependencies": { + "@types/node": "^13.9.1", + "@types/webpack-env": "^1.15.1", + "typescript": "^4.5.2" + } +} \ No newline at end of file diff --git a/node_modules/pinia/LICENSE b/node_modules/pinia/LICENSE new file mode 100644 index 0000000..0c77562 --- /dev/null +++ b/node_modules/pinia/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019-present Eduardo San Martin Morote + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/pinia/README.md b/node_modules/pinia/README.md new file mode 100644 index 0000000..d73d322 --- /dev/null +++ b/node_modules/pinia/README.md @@ -0,0 +1,24 @@ +

+ + Pinia logo + +

+ +# Pinia + +> Intuitive, type safe and flexible Store for Vue + +## 👉 [Demo with Vue 3 on StackBlitz](https://stackblitz.com/github/piniajs/example-vue-3-vite) + +## Help me keep working on this project 💚 + +- [Become a Sponsor on GitHub](https://github.com/sponsors/posva) +- [One-time donation via PayPal](https://paypal.me/posva) + +## Documentation + +To learn more about Pinia, check [its documentation](https://pinia.vuejs.org). + +## License + +[MIT](http://opensource.org/licenses/MIT) diff --git a/node_modules/pinia/dist/pinia.cjs b/node_modules/pinia/dist/pinia.cjs new file mode 100644 index 0000000..859b41a --- /dev/null +++ b/node_modules/pinia/dist/pinia.cjs @@ -0,0 +1,2019 @@ +/*! + * pinia v2.1.6 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */ +'use strict'; + +var vueDemi = require('vue-demi'); +var devtoolsApi = require('@vue/devtools-api'); + +/** + * setActivePinia must be called to handle SSR at the top of functions like + * `fetch`, `setup`, `serverPrefetch` and others + */ +let activePinia; +/** + * Sets or unsets the active pinia. Used in SSR and internally when calling + * actions and getters + * + * @param pinia - Pinia instance + */ +// @ts-expect-error: cannot constrain the type of the return +const setActivePinia = (pinia) => (activePinia = pinia); +/** + * Get the currently active pinia if there is any. + */ +const getActivePinia = () => (vueDemi.hasInjectionContext() && vueDemi.inject(piniaSymbol)) || activePinia; +const piniaSymbol = ((process.env.NODE_ENV !== 'production') ? Symbol('pinia') : /* istanbul ignore next */ Symbol()); + +function isPlainObject( +// eslint-disable-next-line @typescript-eslint/no-explicit-any +o) { + return (o && + typeof o === 'object' && + Object.prototype.toString.call(o) === '[object Object]' && + typeof o.toJSON !== 'function'); +} +// type DeepReadonly = { readonly [P in keyof T]: DeepReadonly } +// TODO: can we change these to numbers? +/** + * Possible types for SubscriptionCallback + */ +exports.MutationType = void 0; +(function (MutationType) { + /** + * Direct mutation of the state: + * + * - `store.name = 'new name'` + * - `store.$state.name = 'new name'` + * - `store.list.push('new item')` + */ + MutationType["direct"] = "direct"; + /** + * Mutated the state with `$patch` and an object + * + * - `store.$patch({ name: 'newName' })` + */ + MutationType["patchObject"] = "patch object"; + /** + * Mutated the state with `$patch` and a function + * + * - `store.$patch(state => state.name = 'newName')` + */ + MutationType["patchFunction"] = "patch function"; + // maybe reset? for $state = {} and $reset +})(exports.MutationType || (exports.MutationType = {})); + +const IS_CLIENT = typeof window !== 'undefined'; +/** + * Should we add the devtools plugins. + * - only if dev mode or forced through the prod devtools flag + * - not in test + * - only if window exists (could change in the future) + */ +const USE_DEVTOOLS = ((process.env.NODE_ENV !== 'production') || false) && !(process.env.NODE_ENV === 'test') && IS_CLIENT; + +/* + * FileSaver.js A saveAs() FileSaver implementation. + * + * Originally by Eli Grey, adapted as an ESM module by Eduardo San Martin + * Morote. + * + * License : MIT + */ +// The one and only way of getting global scope in all environments +// https://stackoverflow.com/q/3277182/1008999 +const _global = /*#__PURE__*/ (() => typeof window === 'object' && window.window === window + ? window + : typeof self === 'object' && self.self === self + ? self + : typeof global === 'object' && global.global === global + ? global + : typeof globalThis === 'object' + ? globalThis + : { HTMLElement: null })(); +function bom(blob, { autoBom = false } = {}) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if (autoBom && + /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xfeff), blob], { type: blob.type }); + } + return blob; +} +function download(url, name, opts) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'blob'; + xhr.onload = function () { + saveAs(xhr.response, name, opts); + }; + xhr.onerror = function () { + console.error('could not download file'); + }; + xhr.send(); +} +function corsEnabled(url) { + const xhr = new XMLHttpRequest(); + // use sync to avoid popup blocker + xhr.open('HEAD', url, false); + try { + xhr.send(); + } + catch (e) { } + return xhr.status >= 200 && xhr.status <= 299; +} +// `a.click()` doesn't work for all browsers (#465) +function click(node) { + try { + node.dispatchEvent(new MouseEvent('click')); + } + catch (e) { + const evt = document.createEvent('MouseEvents'); + evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); + node.dispatchEvent(evt); + } +} +const _navigator = + typeof navigator === 'object' ? navigator : { userAgent: '' }; +// Detect WebView inside a native macOS app by ruling out all browsers +// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too +// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos +const isMacOSWebView = /*#__PURE__*/ (() => /Macintosh/.test(_navigator.userAgent) && + /AppleWebKit/.test(_navigator.userAgent) && + !/Safari/.test(_navigator.userAgent))(); +const saveAs = !IS_CLIENT + ? () => { } // noop + : // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView or mini program + typeof HTMLAnchorElement !== 'undefined' && + 'download' in HTMLAnchorElement.prototype && + !isMacOSWebView + ? downloadSaveAs + : // Use msSaveOrOpenBlob as a second approach + 'msSaveOrOpenBlob' in _navigator + ? msSaveAs + : // Fallback to using FileReader and a popup + fileSaverSaveAs; +function downloadSaveAs(blob, name = 'download', opts) { + const a = document.createElement('a'); + a.download = name; + a.rel = 'noopener'; // tabnabbing + // TODO: detect chrome extensions & packaged apps + // a.target = '_blank' + if (typeof blob === 'string') { + // Support regular links + a.href = blob; + if (a.origin !== location.origin) { + if (corsEnabled(a.href)) { + download(blob, name, opts); + } + else { + a.target = '_blank'; + click(a); + } + } + else { + click(a); + } + } + else { + // Support blobs + a.href = URL.createObjectURL(blob); + setTimeout(function () { + URL.revokeObjectURL(a.href); + }, 4e4); // 40s + setTimeout(function () { + click(a); + }, 0); + } +} +function msSaveAs(blob, name = 'download', opts) { + if (typeof blob === 'string') { + if (corsEnabled(blob)) { + download(blob, name, opts); + } + else { + const a = document.createElement('a'); + a.href = blob; + a.target = '_blank'; + setTimeout(function () { + click(a); + }); + } + } + else { + // @ts-ignore: works on windows + navigator.msSaveOrOpenBlob(bom(blob, opts), name); + } +} +function fileSaverSaveAs(blob, name, opts, popup) { + // Open a popup immediately do go around popup blocker + // Mostly only available on user interaction and the fileReader is async so... + popup = popup || open('', '_blank'); + if (popup) { + popup.document.title = popup.document.body.innerText = 'downloading...'; + } + if (typeof blob === 'string') + return download(blob, name, opts); + const force = blob.type === 'application/octet-stream'; + const isSafari = /constructor/i.test(String(_global.HTMLElement)) || 'safari' in _global; + const isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); + if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && + typeof FileReader !== 'undefined') { + // Safari doesn't allow downloading of blob URLs + const reader = new FileReader(); + reader.onloadend = function () { + let url = reader.result; + if (typeof url !== 'string') { + popup = null; + throw new Error('Wrong reader.result type'); + } + url = isChromeIOS + ? url + : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); + if (popup) { + popup.location.href = url; + } + else { + location.assign(url); + } + popup = null; // reverse-tabnabbing #460 + }; + reader.readAsDataURL(blob); + } + else { + const url = URL.createObjectURL(blob); + if (popup) + popup.location.assign(url); + else + location.href = url; + popup = null; // reverse-tabnabbing #460 + setTimeout(function () { + URL.revokeObjectURL(url); + }, 4e4); // 40s + } +} + +/** + * Shows a toast or console.log + * + * @param message - message to log + * @param type - different color of the tooltip + */ +function toastMessage(message, type) { + const piniaMessage = '🍍 ' + message; + if (typeof __VUE_DEVTOOLS_TOAST__ === 'function') { + // No longer available :( + __VUE_DEVTOOLS_TOAST__(piniaMessage, type); + } + else if (type === 'error') { + console.error(piniaMessage); + } + else if (type === 'warn') { + console.warn(piniaMessage); + } + else { + console.log(piniaMessage); + } +} +function isPinia(o) { + return '_a' in o && 'install' in o; +} + +/** + * This file contain devtools actions, they are not Pinia actions. + */ +// --- +function checkClipboardAccess() { + if (!('clipboard' in navigator)) { + toastMessage(`Your browser doesn't support the Clipboard API`, 'error'); + return true; + } +} +function checkNotFocusedError(error) { + if (error instanceof Error && + error.message.toLowerCase().includes('document is not focused')) { + toastMessage('You need to activate the "Emulate a focused page" setting in the "Rendering" panel of devtools.', 'warn'); + return true; + } + return false; +} +async function actionGlobalCopyState(pinia) { + if (checkClipboardAccess()) + return; + try { + await navigator.clipboard.writeText(JSON.stringify(pinia.state.value)); + toastMessage('Global state copied to clipboard.'); + } + catch (error) { + if (checkNotFocusedError(error)) + return; + toastMessage(`Failed to serialize the state. Check the console for more details.`, 'error'); + console.error(error); + } +} +async function actionGlobalPasteState(pinia) { + if (checkClipboardAccess()) + return; + try { + loadStoresState(pinia, JSON.parse(await navigator.clipboard.readText())); + toastMessage('Global state pasted from clipboard.'); + } + catch (error) { + if (checkNotFocusedError(error)) + return; + toastMessage(`Failed to deserialize the state from clipboard. Check the console for more details.`, 'error'); + console.error(error); + } +} +async function actionGlobalSaveState(pinia) { + try { + saveAs(new Blob([JSON.stringify(pinia.state.value)], { + type: 'text/plain;charset=utf-8', + }), 'pinia-state.json'); + } + catch (error) { + toastMessage(`Failed to export the state as JSON. Check the console for more details.`, 'error'); + console.error(error); + } +} +let fileInput; +function getFileOpener() { + if (!fileInput) { + fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = '.json'; + } + function openFile() { + return new Promise((resolve, reject) => { + fileInput.onchange = async () => { + const files = fileInput.files; + if (!files) + return resolve(null); + const file = files.item(0); + if (!file) + return resolve(null); + return resolve({ text: await file.text(), file }); + }; + // @ts-ignore: TODO: changed from 4.3 to 4.4 + fileInput.oncancel = () => resolve(null); + fileInput.onerror = reject; + fileInput.click(); + }); + } + return openFile; +} +async function actionGlobalOpenStateFile(pinia) { + try { + const open = getFileOpener(); + const result = await open(); + if (!result) + return; + const { text, file } = result; + loadStoresState(pinia, JSON.parse(text)); + toastMessage(`Global state imported from "${file.name}".`); + } + catch (error) { + toastMessage(`Failed to import the state from JSON. Check the console for more details.`, 'error'); + console.error(error); + } +} +function loadStoresState(pinia, state) { + for (const key in state) { + const storeState = pinia.state.value[key]; + if (storeState) { + Object.assign(storeState, state[key]); + } + } +} + +function formatDisplay(display) { + return { + _custom: { + display, + }, + }; +} +const PINIA_ROOT_LABEL = '🍍 Pinia (root)'; +const PINIA_ROOT_ID = '_root'; +function formatStoreForInspectorTree(store) { + return isPinia(store) + ? { + id: PINIA_ROOT_ID, + label: PINIA_ROOT_LABEL, + } + : { + id: store.$id, + label: store.$id, + }; +} +function formatStoreForInspectorState(store) { + if (isPinia(store)) { + const storeNames = Array.from(store._s.keys()); + const storeMap = store._s; + const state = { + state: storeNames.map((storeId) => ({ + editable: true, + key: storeId, + value: store.state.value[storeId], + })), + getters: storeNames + .filter((id) => storeMap.get(id)._getters) + .map((id) => { + const store = storeMap.get(id); + return { + editable: false, + key: id, + value: store._getters.reduce((getters, key) => { + getters[key] = store[key]; + return getters; + }, {}), + }; + }), + }; + return state; + } + const state = { + state: Object.keys(store.$state).map((key) => ({ + editable: true, + key, + value: store.$state[key], + })), + }; + // avoid adding empty getters + if (store._getters && store._getters.length) { + state.getters = store._getters.map((getterName) => ({ + editable: false, + key: getterName, + value: store[getterName], + })); + } + if (store._customProperties.size) { + state.customProperties = Array.from(store._customProperties).map((key) => ({ + editable: true, + key, + value: store[key], + })); + } + return state; +} +function formatEventData(events) { + if (!events) + return {}; + if (Array.isArray(events)) { + // TODO: handle add and delete for arrays and objects + return events.reduce((data, event) => { + data.keys.push(event.key); + data.operations.push(event.type); + data.oldValue[event.key] = event.oldValue; + data.newValue[event.key] = event.newValue; + return data; + }, { + oldValue: {}, + keys: [], + operations: [], + newValue: {}, + }); + } + else { + return { + operation: formatDisplay(events.type), + key: formatDisplay(events.key), + oldValue: events.oldValue, + newValue: events.newValue, + }; + } +} +function formatMutationType(type) { + switch (type) { + case exports.MutationType.direct: + return 'mutation'; + case exports.MutationType.patchFunction: + return '$patch'; + case exports.MutationType.patchObject: + return '$patch'; + default: + return 'unknown'; + } +} + +// timeline can be paused when directly changing the state +let isTimelineActive = true; +const componentStateTypes = []; +const MUTATIONS_LAYER_ID = 'pinia:mutations'; +const INSPECTOR_ID = 'pinia'; +const { assign: assign$1 } = Object; +/** + * Gets the displayed name of a store in devtools + * + * @param id - id of the store + * @returns a formatted string + */ +const getStoreType = (id) => '🍍 ' + id; +/** + * Add the pinia plugin without any store. Allows displaying a Pinia plugin tab + * as soon as it is added to the application. + * + * @param app - Vue application + * @param pinia - pinia instance + */ +function registerPiniaDevtools(app, pinia) { + devtoolsApi.setupDevtoolsPlugin({ + id: 'dev.esm.pinia', + label: 'Pinia 🍍', + logo: 'https://pinia.vuejs.org/logo.svg', + packageName: 'pinia', + homepage: 'https://pinia.vuejs.org', + componentStateTypes, + app, + }, (api) => { + if (typeof api.now !== 'function') { + toastMessage('You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html.'); + } + api.addTimelineLayer({ + id: MUTATIONS_LAYER_ID, + label: `Pinia 🍍`, + color: 0xe5df88, + }); + api.addInspector({ + id: INSPECTOR_ID, + label: 'Pinia 🍍', + icon: 'storage', + treeFilterPlaceholder: 'Search stores', + actions: [ + { + icon: 'content_copy', + action: () => { + actionGlobalCopyState(pinia); + }, + tooltip: 'Serialize and copy the state', + }, + { + icon: 'content_paste', + action: async () => { + await actionGlobalPasteState(pinia); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }, + tooltip: 'Replace the state with the content of your clipboard', + }, + { + icon: 'save', + action: () => { + actionGlobalSaveState(pinia); + }, + tooltip: 'Save the state as a JSON file', + }, + { + icon: 'folder_open', + action: async () => { + await actionGlobalOpenStateFile(pinia); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }, + tooltip: 'Import the state from a JSON file', + }, + ], + nodeActions: [ + { + icon: 'restore', + tooltip: 'Reset the state (with "$reset")', + action: (nodeId) => { + const store = pinia._s.get(nodeId); + if (!store) { + toastMessage(`Cannot reset "${nodeId}" store because it wasn't found.`, 'warn'); + } + else if (typeof store.$reset !== 'function') { + toastMessage(`Cannot reset "${nodeId}" store because it doesn't have a "$reset" method implemented.`, 'warn'); + } + else { + store.$reset(); + toastMessage(`Store "${nodeId}" reset.`); + } + }, + }, + ], + }); + api.on.inspectComponent((payload, ctx) => { + const proxy = (payload.componentInstance && + payload.componentInstance.proxy); + if (proxy && proxy._pStores) { + const piniaStores = payload.componentInstance.proxy._pStores; + Object.values(piniaStores).forEach((store) => { + payload.instanceData.state.push({ + type: getStoreType(store.$id), + key: 'state', + editable: true, + value: store._isOptionsAPI + ? { + _custom: { + value: vueDemi.toRaw(store.$state), + actions: [ + { + icon: 'restore', + tooltip: 'Reset the state of this store', + action: () => store.$reset(), + }, + ], + }, + } + : // NOTE: workaround to unwrap transferred refs + Object.keys(store.$state).reduce((state, key) => { + state[key] = store.$state[key]; + return state; + }, {}), + }); + if (store._getters && store._getters.length) { + payload.instanceData.state.push({ + type: getStoreType(store.$id), + key: 'getters', + editable: false, + value: store._getters.reduce((getters, key) => { + try { + getters[key] = store[key]; + } + catch (error) { + // @ts-expect-error: we just want to show it in devtools + getters[key] = error; + } + return getters; + }, {}), + }); + } + }); + } + }); + api.on.getInspectorTree((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + let stores = [pinia]; + stores = stores.concat(Array.from(pinia._s.values())); + payload.rootNodes = (payload.filter + ? stores.filter((store) => '$id' in store + ? store.$id + .toLowerCase() + .includes(payload.filter.toLowerCase()) + : PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase())) + : stores).map(formatStoreForInspectorTree); + } + }); + api.on.getInspectorState((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const inspectedStore = payload.nodeId === PINIA_ROOT_ID + ? pinia + : pinia._s.get(payload.nodeId); + if (!inspectedStore) { + // this could be the selected store restored for a different project + // so it's better not to say anything here + return; + } + if (inspectedStore) { + payload.state = formatStoreForInspectorState(inspectedStore); + } + } + }); + api.on.editInspectorState((payload, ctx) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const inspectedStore = payload.nodeId === PINIA_ROOT_ID + ? pinia + : pinia._s.get(payload.nodeId); + if (!inspectedStore) { + return toastMessage(`store "${payload.nodeId}" not found`, 'error'); + } + const { path } = payload; + if (!isPinia(inspectedStore)) { + // access only the state + if (path.length !== 1 || + !inspectedStore._customProperties.has(path[0]) || + path[0] in inspectedStore.$state) { + path.unshift('$state'); + } + } + else { + // Root access, we can omit the `.value` because the devtools API does it for us + path.unshift('state'); + } + isTimelineActive = false; + payload.set(inspectedStore, path, payload.state.value); + isTimelineActive = true; + } + }); + api.on.editComponentState((payload) => { + if (payload.type.startsWith('🍍')) { + const storeId = payload.type.replace(/^🍍\s*/, ''); + const store = pinia._s.get(storeId); + if (!store) { + return toastMessage(`store "${storeId}" not found`, 'error'); + } + const { path } = payload; + if (path[0] !== 'state') { + return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`); + } + // rewrite the first entry to be able to directly set the state as + // well as any other path + path[0] = '$state'; + isTimelineActive = false; + payload.set(store, path, payload.state.value); + isTimelineActive = true; + } + }); + }); +} +function addStoreToDevtools(app, store) { + if (!componentStateTypes.includes(getStoreType(store.$id))) { + componentStateTypes.push(getStoreType(store.$id)); + } + devtoolsApi.setupDevtoolsPlugin({ + id: 'dev.esm.pinia', + label: 'Pinia 🍍', + logo: 'https://pinia.vuejs.org/logo.svg', + packageName: 'pinia', + homepage: 'https://pinia.vuejs.org', + componentStateTypes, + app, + settings: { + logStoreChanges: { + label: 'Notify about new/deleted stores', + type: 'boolean', + defaultValue: true, + }, + // useEmojis: { + // label: 'Use emojis in messages ⚡️', + // type: 'boolean', + // defaultValue: true, + // }, + }, + }, (api) => { + // gracefully handle errors + const now = typeof api.now === 'function' ? api.now.bind(api) : Date.now; + store.$onAction(({ after, onError, name, args }) => { + const groupId = runningActionId++; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🛫 ' + name, + subtitle: 'start', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + }, + groupId, + }, + }); + after((result) => { + activeAction = undefined; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🛬 ' + name, + subtitle: 'end', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + result, + }, + groupId, + }, + }); + }); + onError((error) => { + activeAction = undefined; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + logType: 'error', + title: '💥 ' + name, + subtitle: 'end', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + error, + }, + groupId, + }, + }); + }); + }, true); + store._customProperties.forEach((name) => { + vueDemi.watch(() => vueDemi.unref(store[name]), (newValue, oldValue) => { + api.notifyComponentUpdate(); + api.sendInspectorState(INSPECTOR_ID); + if (isTimelineActive) { + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: 'Change', + subtitle: name, + data: { + newValue, + oldValue, + }, + groupId: activeAction, + }, + }); + } + }, { deep: true }); + }); + store.$subscribe(({ events, type }, state) => { + api.notifyComponentUpdate(); + api.sendInspectorState(INSPECTOR_ID); + if (!isTimelineActive) + return; + // rootStore.state[store.id] = state + const eventData = { + time: now(), + title: formatMutationType(type), + data: assign$1({ store: formatDisplay(store.$id) }, formatEventData(events)), + groupId: activeAction, + }; + if (type === exports.MutationType.patchFunction) { + eventData.subtitle = '⤵️'; + } + else if (type === exports.MutationType.patchObject) { + eventData.subtitle = '🧩'; + } + else if (events && !Array.isArray(events)) { + eventData.subtitle = events.type; + } + if (events) { + eventData.data['rawEvent(s)'] = { + _custom: { + display: 'DebuggerEvent', + type: 'object', + tooltip: 'raw DebuggerEvent[]', + value: events, + }, + }; + } + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: eventData, + }); + }, { detached: true, flush: 'sync' }); + const hotUpdate = store._hotUpdate; + store._hotUpdate = vueDemi.markRaw((newStore) => { + hotUpdate(newStore); + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🔥 ' + store.$id, + subtitle: 'HMR update', + data: { + store: formatDisplay(store.$id), + info: formatDisplay(`HMR update`), + }, + }, + }); + // update the devtools too + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }); + const { $dispose } = store; + store.$dispose = () => { + $dispose(); + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + api.getSettings().logStoreChanges && + toastMessage(`Disposed "${store.$id}" store 🗑`); + }; + // trigger an update so it can display new registered stores + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + api.getSettings().logStoreChanges && + toastMessage(`"${store.$id}" store installed 🆕`); + }); +} +let runningActionId = 0; +let activeAction; +/** + * Patches a store to enable action grouping in devtools by wrapping the store with a Proxy that is passed as the + * context of all actions, allowing us to set `runningAction` on each access and effectively associating any state + * mutation to the action. + * + * @param store - store to patch + * @param actionNames - list of actionst to patch + */ +function patchActionForGrouping(store, actionNames, wrapWithProxy) { + // original actions of the store as they are given by pinia. We are going to override them + const actions = actionNames.reduce((storeActions, actionName) => { + // use toRaw to avoid tracking #541 + storeActions[actionName] = vueDemi.toRaw(store)[actionName]; + return storeActions; + }, {}); + for (const actionName in actions) { + store[actionName] = function () { + // the running action id is incremented in a before action hook + const _actionId = runningActionId; + const trackedStore = wrapWithProxy + ? new Proxy(store, { + get(...args) { + activeAction = _actionId; + return Reflect.get(...args); + }, + set(...args) { + activeAction = _actionId; + return Reflect.set(...args); + }, + }) + : store; + // For Setup Stores we need https://github.com/tc39/proposal-async-context + activeAction = _actionId; + const retValue = actions[actionName].apply(trackedStore, arguments); + // this is safer as async actions in Setup Stores would associate mutations done outside of the action + activeAction = undefined; + return retValue; + }; + } +} +/** + * pinia.use(devtoolsPlugin) + */ +function devtoolsPlugin({ app, store, options }) { + // HMR module + if (store.$id.startsWith('__hot:')) { + return; + } + // detect option api vs setup api + store._isOptionsAPI = !!options.state; + patchActionForGrouping(store, Object.keys(options.actions), store._isOptionsAPI); + // Upgrade the HMR to also update the new actions + const originalHotUpdate = store._hotUpdate; + vueDemi.toRaw(store)._hotUpdate = function (newStore) { + originalHotUpdate.apply(this, arguments); + patchActionForGrouping(store, Object.keys(newStore._hmrPayload.actions), !!store._isOptionsAPI); + }; + addStoreToDevtools(app, + // FIXME: is there a way to allow the assignment from Store to StoreGeneric? + store); +} + +/** + * Creates a Pinia instance to be used by the application + */ +function createPinia() { + const scope = vueDemi.effectScope(true); + // NOTE: here we could check the window object for a state and directly set it + // if there is anything like it with Vue 3 SSR + const state = scope.run(() => vueDemi.ref({})); + let _p = []; + // plugins added before calling app.use(pinia) + let toBeInstalled = []; + const pinia = vueDemi.markRaw({ + install(app) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + if (!vueDemi.isVue2) { + pinia._a = app; + app.provide(piniaSymbol, pinia); + app.config.globalProperties.$pinia = pinia; + /* istanbul ignore else */ + if (USE_DEVTOOLS) { + registerPiniaDevtools(app, pinia); + } + toBeInstalled.forEach((plugin) => _p.push(plugin)); + toBeInstalled = []; + } + }, + use(plugin) { + if (!this._a && !vueDemi.isVue2) { + toBeInstalled.push(plugin); + } + else { + _p.push(plugin); + } + return this; + }, + _p, + // it's actually undefined here + // @ts-expect-error + _a: null, + _e: scope, + _s: new Map(), + state, + }); + // pinia devtools rely on dev only features so they cannot be forced unless + // the dev build of Vue is used. Avoid old browsers like IE11. + if (USE_DEVTOOLS && typeof Proxy !== 'undefined') { + pinia.use(devtoolsPlugin); + } + return pinia; +} + +/** + * Checks if a function is a `StoreDefinition`. + * + * @param fn - object to test + * @returns true if `fn` is a StoreDefinition + */ +const isUseStore = (fn) => { + return typeof fn === 'function' && typeof fn.$id === 'string'; +}; +/** + * Mutates in place `newState` with `oldState` to _hot update_ it. It will + * remove any key not existing in `newState` and recursively merge plain + * objects. + * + * @param newState - new state object to be patched + * @param oldState - old state that should be used to patch newState + * @returns - newState + */ +function patchObject(newState, oldState) { + // no need to go through symbols because they cannot be serialized anyway + for (const key in oldState) { + const subPatch = oldState[key]; + // skip the whole sub tree + if (!(key in newState)) { + continue; + } + const targetValue = newState[key]; + if (isPlainObject(targetValue) && + isPlainObject(subPatch) && + !vueDemi.isRef(subPatch) && + !vueDemi.isReactive(subPatch)) { + newState[key] = patchObject(targetValue, subPatch); + } + else { + // objects are either a bit more complex (e.g. refs) or primitives, so we + // just set the whole thing + if (vueDemi.isVue2) { + vueDemi.set(newState, key, subPatch); + } + else { + newState[key] = subPatch; + } + } + } + return newState; +} +/** + * Creates an _accept_ function to pass to `import.meta.hot` in Vite applications. + * + * @example + * ```js + * const useUser = defineStore(...) + * if (import.meta.hot) { + * import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot)) + * } + * ``` + * + * @param initialUseStore - return of the defineStore to hot update + * @param hot - `import.meta.hot` + */ +function acceptHMRUpdate(initialUseStore, hot) { + // strip as much as possible from iife.prod + if (!(process.env.NODE_ENV !== 'production')) { + return () => { }; + } + return (newModule) => { + const pinia = hot.data.pinia || initialUseStore._pinia; + if (!pinia) { + // this store is still not used + return; + } + // preserve the pinia instance across loads + hot.data.pinia = pinia; + // console.log('got data', newStore) + for (const exportName in newModule) { + const useStore = newModule[exportName]; + // console.log('checking for', exportName) + if (isUseStore(useStore) && pinia._s.has(useStore.$id)) { + // console.log('Accepting update for', useStore.$id) + const id = useStore.$id; + if (id !== initialUseStore.$id) { + console.warn(`The id of the store changed from "${initialUseStore.$id}" to "${id}". Reloading.`); + // return import.meta.hot.invalidate() + return hot.invalidate(); + } + const existingStore = pinia._s.get(id); + if (!existingStore) { + console.log(`[Pinia]: skipping hmr because store doesn't exist yet`); + return; + } + useStore(pinia, existingStore); + } + } + }; +} + +const noop = () => { }; +function addSubscription(subscriptions, callback, detached, onCleanup = noop) { + subscriptions.push(callback); + const removeSubscription = () => { + const idx = subscriptions.indexOf(callback); + if (idx > -1) { + subscriptions.splice(idx, 1); + onCleanup(); + } + }; + if (!detached && vueDemi.getCurrentScope()) { + vueDemi.onScopeDispose(removeSubscription); + } + return removeSubscription; +} +function triggerSubscriptions(subscriptions, ...args) { + subscriptions.slice().forEach((callback) => { + callback(...args); + }); +} + +const fallbackRunWithContext = (fn) => fn(); +function mergeReactiveObjects(target, patchToApply) { + // Handle Map instances + if (target instanceof Map && patchToApply instanceof Map) { + patchToApply.forEach((value, key) => target.set(key, value)); + } + // Handle Set instances + if (target instanceof Set && patchToApply instanceof Set) { + patchToApply.forEach(target.add, target); + } + // no need to go through symbols because they cannot be serialized anyway + for (const key in patchToApply) { + if (!patchToApply.hasOwnProperty(key)) + continue; + const subPatch = patchToApply[key]; + const targetValue = target[key]; + if (isPlainObject(targetValue) && + isPlainObject(subPatch) && + target.hasOwnProperty(key) && + !vueDemi.isRef(subPatch) && + !vueDemi.isReactive(subPatch)) { + // NOTE: here I wanted to warn about inconsistent types but it's not possible because in setup stores one might + // start the value of a property as a certain type e.g. a Map, and then for some reason, during SSR, change that + // to `undefined`. When trying to hydrate, we want to override the Map with `undefined`. + target[key] = mergeReactiveObjects(targetValue, subPatch); + } + else { + // @ts-expect-error: subPatch is a valid value + target[key] = subPatch; + } + } + return target; +} +const skipHydrateSymbol = (process.env.NODE_ENV !== 'production') + ? Symbol('pinia:skipHydration') + : /* istanbul ignore next */ Symbol(); +const skipHydrateMap = /*#__PURE__*/ new WeakMap(); +/** + * Tells Pinia to skip the hydration process of a given object. This is useful in setup stores (only) when you return a + * stateful object in the store but it isn't really state. e.g. returning a router instance in a setup store. + * + * @param obj - target object + * @returns obj + */ +function skipHydrate(obj) { + return vueDemi.isVue2 + ? // in @vue/composition-api, the refs are sealed so defineProperty doesn't work... + /* istanbul ignore next */ skipHydrateMap.set(obj, 1) && obj + : Object.defineProperty(obj, skipHydrateSymbol, {}); +} +/** + * Returns whether a value should be hydrated + * + * @param obj - target variable + * @returns true if `obj` should be hydrated + */ +function shouldHydrate(obj) { + return vueDemi.isVue2 + ? /* istanbul ignore next */ !skipHydrateMap.has(obj) + : !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol); +} +const { assign } = Object; +function isComputed(o) { + return !!(vueDemi.isRef(o) && o.effect); +} +function createOptionsStore(id, options, pinia, hot) { + const { state, actions, getters } = options; + const initialState = pinia.state.value[id]; + let store; + function setup() { + if (!initialState && (!(process.env.NODE_ENV !== 'production') || !hot)) { + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(pinia.state.value, id, state ? state() : {}); + } + else { + pinia.state.value[id] = state ? state() : {}; + } + } + // avoid creating a state in pinia.state.value + const localState = (process.env.NODE_ENV !== 'production') && hot + ? // use ref() to unwrap refs inside state TODO: check if this is still necessary + vueDemi.toRefs(vueDemi.ref(state ? state() : {}).value) + : vueDemi.toRefs(pinia.state.value[id]); + return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => { + if ((process.env.NODE_ENV !== 'production') && name in localState) { + console.warn(`[🍍]: A getter cannot have the same name as another state property. Rename one of them. Found with "${name}" in store "${id}".`); + } + computedGetters[name] = vueDemi.markRaw(vueDemi.computed(() => { + setActivePinia(pinia); + // it was created just before + const store = pinia._s.get(id); + // allow cross using stores + /* istanbul ignore next */ + if (vueDemi.isVue2 && !store._r) + return; + // @ts-expect-error + // return getters![name].call(context, context) + // TODO: avoid reading the getter while assigning with a global variable + return getters[name].call(store, store); + })); + return computedGetters; + }, {})); + } + store = createSetupStore(id, setup, options, pinia, hot, true); + return store; +} +function createSetupStore($id, setup, options = {}, pinia, hot, isOptionsStore) { + let scope; + const optionsForPlugin = assign({ actions: {} }, options); + /* istanbul ignore if */ + if ((process.env.NODE_ENV !== 'production') && !pinia._e.active) { + throw new Error('Pinia destroyed'); + } + // watcher options for $subscribe + const $subscribeOptions = { + deep: true, + // flush: 'post', + }; + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production') && !vueDemi.isVue2) { + $subscribeOptions.onTrigger = (event) => { + /* istanbul ignore else */ + if (isListening) { + debuggerEvents = event; + // avoid triggering this while the store is being built and the state is being set in pinia + } + else if (isListening == false && !store._hotUpdating) { + // let patch send all the events together later + /* istanbul ignore else */ + if (Array.isArray(debuggerEvents)) { + debuggerEvents.push(event); + } + else { + console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.'); + } + } + }; + } + // internal state + let isListening; // set to true at the end + let isSyncListening; // set to true at the end + let subscriptions = []; + let actionSubscriptions = []; + let debuggerEvents; + const initialState = pinia.state.value[$id]; + // avoid setting the state for option stores if it is set + // by the setup + if (!isOptionsStore && !initialState && (!(process.env.NODE_ENV !== 'production') || !hot)) { + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(pinia.state.value, $id, {}); + } + else { + pinia.state.value[$id] = {}; + } + } + const hotState = vueDemi.ref({}); + // avoid triggering too many listeners + // https://github.com/vuejs/pinia/issues/1129 + let activeListener; + function $patch(partialStateOrMutator) { + let subscriptionMutation; + isListening = isSyncListening = false; + // reset the debugger events since patches are sync + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + debuggerEvents = []; + } + if (typeof partialStateOrMutator === 'function') { + partialStateOrMutator(pinia.state.value[$id]); + subscriptionMutation = { + type: exports.MutationType.patchFunction, + storeId: $id, + events: debuggerEvents, + }; + } + else { + mergeReactiveObjects(pinia.state.value[$id], partialStateOrMutator); + subscriptionMutation = { + type: exports.MutationType.patchObject, + payload: partialStateOrMutator, + storeId: $id, + events: debuggerEvents, + }; + } + const myListenerId = (activeListener = Symbol()); + vueDemi.nextTick().then(() => { + if (activeListener === myListenerId) { + isListening = true; + } + }); + isSyncListening = true; + // because we paused the watcher, we need to manually call the subscriptions + triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]); + } + const $reset = isOptionsStore + ? function $reset() { + const { state } = options; + const newState = state ? state() : {}; + // we use a patch to group all changes into one single subscription + this.$patch(($state) => { + assign($state, newState); + }); + } + : /* istanbul ignore next */ + (process.env.NODE_ENV !== 'production') + ? () => { + throw new Error(`🍍: Store "${$id}" is built using the setup syntax and does not implement $reset().`); + } + : noop; + function $dispose() { + scope.stop(); + subscriptions = []; + actionSubscriptions = []; + pinia._s.delete($id); + } + /** + * Wraps an action to handle subscriptions. + * + * @param name - name of the action + * @param action - action to wrap + * @returns a wrapped action to handle subscriptions + */ + function wrapAction(name, action) { + return function () { + setActivePinia(pinia); + const args = Array.from(arguments); + const afterCallbackList = []; + const onErrorCallbackList = []; + function after(callback) { + afterCallbackList.push(callback); + } + function onError(callback) { + onErrorCallbackList.push(callback); + } + // @ts-expect-error + triggerSubscriptions(actionSubscriptions, { + args, + name, + store, + after, + onError, + }); + let ret; + try { + ret = action.apply(this && this.$id === $id ? this : store, args); + // handle sync errors + } + catch (error) { + triggerSubscriptions(onErrorCallbackList, error); + throw error; + } + if (ret instanceof Promise) { + return ret + .then((value) => { + triggerSubscriptions(afterCallbackList, value); + return value; + }) + .catch((error) => { + triggerSubscriptions(onErrorCallbackList, error); + return Promise.reject(error); + }); + } + // trigger after callbacks + triggerSubscriptions(afterCallbackList, ret); + return ret; + }; + } + const _hmrPayload = /*#__PURE__*/ vueDemi.markRaw({ + actions: {}, + getters: {}, + state: [], + hotState, + }); + const partialStore = { + _p: pinia, + // _s: scope, + $id, + $onAction: addSubscription.bind(null, actionSubscriptions), + $patch, + $reset, + $subscribe(callback, options = {}) { + const removeSubscription = addSubscription(subscriptions, callback, options.detached, () => stopWatcher()); + const stopWatcher = scope.run(() => vueDemi.watch(() => pinia.state.value[$id], (state) => { + if (options.flush === 'sync' ? isSyncListening : isListening) { + callback({ + storeId: $id, + type: exports.MutationType.direct, + events: debuggerEvents, + }, state); + } + }, assign({}, $subscribeOptions, options))); + return removeSubscription; + }, + $dispose, + }; + /* istanbul ignore if */ + if (vueDemi.isVue2) { + // start as non ready + partialStore._r = false; + } + const store = vueDemi.reactive((process.env.NODE_ENV !== 'production') || USE_DEVTOOLS + ? assign({ + _hmrPayload, + _customProperties: vueDemi.markRaw(new Set()), // devtools custom properties + }, partialStore + // must be added later + // setupStore + ) + : partialStore); + // store the partial store now so the setup of stores can instantiate each other before they are finished without + // creating infinite loops. + pinia._s.set($id, store); + const runWithContext = (pinia._a && pinia._a.runWithContext) || fallbackRunWithContext; + // TODO: idea create skipSerialize that marks properties as non serializable and they are skipped + const setupStore = pinia._e.run(() => { + scope = vueDemi.effectScope(); + return runWithContext(() => scope.run(setup)); + }); + // overwrite existing actions to support $onAction + for (const key in setupStore) { + const prop = setupStore[key]; + if ((vueDemi.isRef(prop) && !isComputed(prop)) || vueDemi.isReactive(prop)) { + // mark it as a piece of state to be serialized + if ((process.env.NODE_ENV !== 'production') && hot) { + vueDemi.set(hotState.value, key, vueDemi.toRef(setupStore, key)); + // createOptionStore directly sets the state in pinia.state.value so we + // can just skip that + } + else if (!isOptionsStore) { + // in setup stores we must hydrate the state and sync pinia state tree with the refs the user just created + if (initialState && shouldHydrate(prop)) { + if (vueDemi.isRef(prop)) { + prop.value = initialState[key]; + } + else { + // probably a reactive object, lets recursively assign + // @ts-expect-error: prop is unknown + mergeReactiveObjects(prop, initialState[key]); + } + } + // transfer the ref to the pinia state to keep everything in sync + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(pinia.state.value[$id], key, prop); + } + else { + pinia.state.value[$id][key] = prop; + } + } + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + _hmrPayload.state.push(key); + } + // action + } + else if (typeof prop === 'function') { + // @ts-expect-error: we are overriding the function we avoid wrapping if + const actionValue = (process.env.NODE_ENV !== 'production') && hot ? prop : wrapAction(key, prop); + // this a hot module replacement store because the hotUpdate method needs + // to do it with the right context + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(setupStore, key, actionValue); + } + else { + // @ts-expect-error + setupStore[key] = actionValue; + } + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + _hmrPayload.actions[key] = prop; + } + // list actions so they can be used in plugins + // @ts-expect-error + optionsForPlugin.actions[key] = prop; + } + else if ((process.env.NODE_ENV !== 'production')) { + // add getters for devtools + if (isComputed(prop)) { + _hmrPayload.getters[key] = isOptionsStore + ? // @ts-expect-error + options.getters[key] + : prop; + if (IS_CLIENT) { + const getters = setupStore._getters || + // @ts-expect-error: same + (setupStore._getters = vueDemi.markRaw([])); + getters.push(key); + } + } + } + } + // add the state, getters, and action properties + /* istanbul ignore if */ + if (vueDemi.isVue2) { + Object.keys(setupStore).forEach((key) => { + vueDemi.set(store, key, setupStore[key]); + }); + } + else { + assign(store, setupStore); + // allows retrieving reactive objects with `storeToRefs()`. Must be called after assigning to the reactive object. + // Make `storeToRefs()` work with `reactive()` #799 + assign(vueDemi.toRaw(store), setupStore); + } + // use this instead of a computed with setter to be able to create it anywhere + // without linking the computed lifespan to wherever the store is first + // created. + Object.defineProperty(store, '$state', { + get: () => ((process.env.NODE_ENV !== 'production') && hot ? hotState.value : pinia.state.value[$id]), + set: (state) => { + /* istanbul ignore if */ + if ((process.env.NODE_ENV !== 'production') && hot) { + throw new Error('cannot set hotState'); + } + $patch(($state) => { + assign($state, state); + }); + }, + }); + // add the hotUpdate before plugins to allow them to override it + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + store._hotUpdate = vueDemi.markRaw((newStore) => { + store._hotUpdating = true; + newStore._hmrPayload.state.forEach((stateKey) => { + if (stateKey in store.$state) { + const newStateTarget = newStore.$state[stateKey]; + const oldStateSource = store.$state[stateKey]; + if (typeof newStateTarget === 'object' && + isPlainObject(newStateTarget) && + isPlainObject(oldStateSource)) { + patchObject(newStateTarget, oldStateSource); + } + else { + // transfer the ref + newStore.$state[stateKey] = oldStateSource; + } + } + // patch direct access properties to allow store.stateProperty to work as + // store.$state.stateProperty + vueDemi.set(store, stateKey, vueDemi.toRef(newStore.$state, stateKey)); + }); + // remove deleted state properties + Object.keys(store.$state).forEach((stateKey) => { + if (!(stateKey in newStore.$state)) { + vueDemi.del(store, stateKey); + } + }); + // avoid devtools logging this as a mutation + isListening = false; + isSyncListening = false; + pinia.state.value[$id] = vueDemi.toRef(newStore._hmrPayload, 'hotState'); + isSyncListening = true; + vueDemi.nextTick().then(() => { + isListening = true; + }); + for (const actionName in newStore._hmrPayload.actions) { + const action = newStore[actionName]; + vueDemi.set(store, actionName, wrapAction(actionName, action)); + } + // TODO: does this work in both setup and option store? + for (const getterName in newStore._hmrPayload.getters) { + const getter = newStore._hmrPayload.getters[getterName]; + const getterValue = isOptionsStore + ? // special handling of options api + vueDemi.computed(() => { + setActivePinia(pinia); + return getter.call(store, store); + }) + : getter; + vueDemi.set(store, getterName, getterValue); + } + // remove deleted getters + Object.keys(store._hmrPayload.getters).forEach((key) => { + if (!(key in newStore._hmrPayload.getters)) { + vueDemi.del(store, key); + } + }); + // remove old actions + Object.keys(store._hmrPayload.actions).forEach((key) => { + if (!(key in newStore._hmrPayload.actions)) { + vueDemi.del(store, key); + } + }); + // update the values used in devtools and to allow deleting new properties later on + store._hmrPayload = newStore._hmrPayload; + store._getters = newStore._getters; + store._hotUpdating = false; + }); + } + if (USE_DEVTOOLS) { + const nonEnumerable = { + writable: true, + configurable: true, + // avoid warning on devtools trying to display this property + enumerable: false, + }; + ['_p', '_hmrPayload', '_getters', '_customProperties'].forEach((p) => { + Object.defineProperty(store, p, assign({ value: store[p] }, nonEnumerable)); + }); + } + /* istanbul ignore if */ + if (vueDemi.isVue2) { + // mark the store as ready before plugins + store._r = true; + } + // apply all plugins + pinia._p.forEach((extender) => { + /* istanbul ignore else */ + if (USE_DEVTOOLS) { + const extensions = scope.run(() => extender({ + store, + app: pinia._a, + pinia, + options: optionsForPlugin, + })); + Object.keys(extensions || {}).forEach((key) => store._customProperties.add(key)); + assign(store, extensions); + } + else { + assign(store, scope.run(() => extender({ + store, + app: pinia._a, + pinia, + options: optionsForPlugin, + }))); + } + }); + if ((process.env.NODE_ENV !== 'production') && + store.$state && + typeof store.$state === 'object' && + typeof store.$state.constructor === 'function' && + !store.$state.constructor.toString().includes('[native code]')) { + console.warn(`[🍍]: The "state" must be a plain object. It cannot be\n` + + `\tstate: () => new MyClass()\n` + + `Found in store "${store.$id}".`); + } + // only apply hydrate to option stores with an initial state in pinia + if (initialState && + isOptionsStore && + options.hydrate) { + options.hydrate(store.$state, initialState); + } + isListening = true; + isSyncListening = true; + return store; +} +function defineStore( +// TODO: add proper types from above +idOrOptions, setup, setupOptions) { + let id; + let options; + const isSetupStore = typeof setup === 'function'; + if (typeof idOrOptions === 'string') { + id = idOrOptions; + // the option store setup will contain the actual options in this case + options = isSetupStore ? setupOptions : setup; + } + else { + options = idOrOptions; + id = idOrOptions.id; + if ((process.env.NODE_ENV !== 'production') && typeof id !== 'string') { + throw new Error(`[🍍]: "defineStore()" must be passed a store id as its first argument.`); + } + } + function useStore(pinia, hot) { + const hasContext = vueDemi.hasInjectionContext(); + pinia = + // in test mode, ignore the argument provided as we can always retrieve a + // pinia instance with getActivePinia() + ((process.env.NODE_ENV === 'test') && activePinia && activePinia._testing ? null : pinia) || + (hasContext ? vueDemi.inject(piniaSymbol, null) : null); + if (pinia) + setActivePinia(pinia); + if ((process.env.NODE_ENV !== 'production') && !activePinia) { + throw new Error(`[🍍]: "getActivePinia()" was called but there was no active Pinia. Did you forget to install pinia?\n` + + `\tconst pinia = createPinia()\n` + + `\tapp.use(pinia)\n` + + `This will fail in production.`); + } + pinia = activePinia; + if (!pinia._s.has(id)) { + // creating the store registers it in `pinia._s` + if (isSetupStore) { + createSetupStore(id, setup, options, pinia); + } + else { + createOptionsStore(id, options, pinia); + } + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + // @ts-expect-error: not the right inferred type + useStore._pinia = pinia; + } + } + const store = pinia._s.get(id); + if ((process.env.NODE_ENV !== 'production') && hot) { + const hotId = '__hot:' + id; + const newStore = isSetupStore + ? createSetupStore(hotId, setup, options, pinia, true) + : createOptionsStore(hotId, assign({}, options), pinia, true); + hot._hotUpdate(newStore); + // cleanup the state properties and the store from the cache + delete pinia.state.value[hotId]; + pinia._s.delete(hotId); + } + if ((process.env.NODE_ENV !== 'production') && IS_CLIENT) { + const currentInstance = vueDemi.getCurrentInstance(); + // save stores in instances to access them devtools + if (currentInstance && + currentInstance.proxy && + // avoid adding stores that are just built for hot module replacement + !hot) { + const vm = currentInstance.proxy; + const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {}); + cache[id] = store; + } + } + // StoreGeneric cannot be casted towards Store + return store; + } + useStore.$id = id; + return useStore; +} + +let mapStoreSuffix = 'Store'; +/** + * Changes the suffix added by `mapStores()`. Can be set to an empty string. + * Defaults to `"Store"`. Make sure to extend the MapStoresCustomization + * interface if you are using TypeScript. + * + * @param suffix - new suffix + */ +function setMapStoreSuffix(suffix // could be 'Store' but that would be annoying for JS +) { + mapStoreSuffix = suffix; +} +/** + * Allows using stores without the composition API (`setup()`) by generating an + * object to be spread in the `computed` field of a component. It accepts a list + * of store definitions. + * + * @example + * ```js + * export default { + * computed: { + * // other computed properties + * ...mapStores(useUserStore, useCartStore) + * }, + * + * created() { + * this.userStore // store with id "user" + * this.cartStore // store with id "cart" + * } + * } + * ``` + * + * @param stores - list of stores to map to an object + */ +function mapStores(...stores) { + if ((process.env.NODE_ENV !== 'production') && Array.isArray(stores[0])) { + console.warn(`[🍍]: Directly pass all stores to "mapStores()" without putting them in an array:\n` + + `Replace\n` + + `\tmapStores([useAuthStore, useCartStore])\n` + + `with\n` + + `\tmapStores(useAuthStore, useCartStore)\n` + + `This will fail in production if not fixed.`); + stores = stores[0]; + } + return stores.reduce((reduced, useStore) => { + // @ts-expect-error: $id is added by defineStore + reduced[useStore.$id + mapStoreSuffix] = function () { + return useStore(this.$pinia); + }; + return reduced; + }, {}); +} +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + reduced[key] = function () { + return useStore(this.$pinia)[key]; + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function () { + const store = useStore(this.$pinia); + const storeKey = keysOrMapper[key]; + // for some reason TS is unable to infer the type of storeKey to be a + // function + return typeof storeKey === 'function' + ? storeKey.call(this, store) + : store[storeKey]; + }; + return reduced; + }, {}); +} +/** + * Alias for `mapState()`. You should use `mapState()` instead. + * @deprecated use `mapState()` instead. + */ +const mapGetters = mapState; +/** + * Allows directly using actions from your store without using the composition + * API (`setup()`) by generating an object to be spread in the `methods` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapActions(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[key](...args); + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[keysOrMapper[key]](...args); + }; + return reduced; + }, {}); +} +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapWritableState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[key]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[key] = value); + }, + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[keysOrMapper[key]]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[keysOrMapper[key]] = value); + }, + }; + return reduced; + }, {}); +} + +/** + * Creates an object of references with all the state, getters, and plugin-added + * state properties of the store. Similar to `toRefs()` but specifically + * designed for Pinia stores so methods and non reactive properties are + * completely ignored. + * + * @param store - store to extract the refs from + */ +function storeToRefs(store) { + // See https://github.com/vuejs/pinia/issues/852 + // It's easier to just use toRefs() even if it includes more stuff + if (vueDemi.isVue2) { + // @ts-expect-error: toRefs include methods and others + return vueDemi.toRefs(store); + } + else { + store = vueDemi.toRaw(store); + const refs = {}; + for (const key in store) { + const value = store[key]; + if (vueDemi.isRef(value) || vueDemi.isReactive(value)) { + // @ts-expect-error: the key is state or getter + refs[key] = + // --- + vueDemi.toRef(store, key); + } + } + return refs; + } +} + +/** + * Vue 2 Plugin that must be installed for pinia to work. Note **you don't need + * this plugin if you are using Nuxt.js**. Use the `buildModule` instead: + * https://pinia.vuejs.org/ssr/nuxt.html. + * + * @example + * ```js + * import Vue from 'vue' + * import { PiniaVuePlugin, createPinia } from 'pinia' + * + * Vue.use(PiniaVuePlugin) + * const pinia = createPinia() + * + * new Vue({ + * el: '#app', + * // ... + * pinia, + * }) + * ``` + * + * @param _Vue - `Vue` imported from 'vue'. + */ +const PiniaVuePlugin = function (_Vue) { + // Equivalent of + // app.config.globalProperties.$pinia = pinia + _Vue.mixin({ + beforeCreate() { + const options = this.$options; + if (options.pinia) { + const pinia = options.pinia; + // HACK: taken from provide(): https://github.com/vuejs/composition-api/blob/main/src/apis/inject.ts#L31 + /* istanbul ignore else */ + if (!this._provided) { + const provideCache = {}; + Object.defineProperty(this, '_provided', { + get: () => provideCache, + set: (v) => Object.assign(provideCache, v), + }); + } + this._provided[piniaSymbol] = pinia; + // propagate the pinia instance in an SSR friendly way + // avoid adding it to nuxt twice + /* istanbul ignore else */ + if (!this.$pinia) { + this.$pinia = pinia; + } + pinia._a = this; + if (IS_CLIENT) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + } + if (USE_DEVTOOLS) { + registerPiniaDevtools(pinia._a, pinia); + } + } + else if (!this.$pinia && options.parent && options.parent.$pinia) { + this.$pinia = options.parent.$pinia; + } + }, + destroyed() { + delete this._pStores; + }, + }); +}; + +exports.PiniaVuePlugin = PiniaVuePlugin; +exports.acceptHMRUpdate = acceptHMRUpdate; +exports.createPinia = createPinia; +exports.defineStore = defineStore; +exports.getActivePinia = getActivePinia; +exports.mapActions = mapActions; +exports.mapGetters = mapGetters; +exports.mapState = mapState; +exports.mapStores = mapStores; +exports.mapWritableState = mapWritableState; +exports.setActivePinia = setActivePinia; +exports.setMapStoreSuffix = setMapStoreSuffix; +exports.skipHydrate = skipHydrate; +exports.storeToRefs = storeToRefs; diff --git a/node_modules/pinia/dist/pinia.d.ts b/node_modules/pinia/dist/pinia.d.ts new file mode 100644 index 0000000..0b3851f --- /dev/null +++ b/node_modules/pinia/dist/pinia.d.ts @@ -0,0 +1,986 @@ +import { App } from 'vue-demi'; +import { ComputedRef } from 'vue-demi'; +import type { DebuggerEvent } from 'vue-demi'; +import { EffectScope } from 'vue-demi'; +import type { Plugin as Plugin_2 } from 'vue-demi'; +import { Ref } from 'vue-demi'; +import { ToRef } from 'vue-demi'; +import { ToRefs } from 'vue-demi'; +import { UnwrapRef } from 'vue-demi'; +import type { WatchOptions } from 'vue-demi'; + +/** + * Creates an _accept_ function to pass to `import.meta.hot` in Vite applications. + * + * @example + * ```js + * const useUser = defineStore(...) + * if (import.meta.hot) { + * import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot)) + * } + * ``` + * + * @param initialUseStore - return of the defineStore to hot update + * @param hot - `import.meta.hot` + */ +export declare function acceptHMRUpdate = _GettersTree, A = _ActionsTree>(initialUseStore: StoreDefinition, hot: any): (newModule: any) => any; + +/** + * Type of an object of Actions. For internal usage only. + * For internal use **only** + */ +export declare type _ActionsTree = Record; + +export declare type _Awaited = T extends null | undefined ? T : T extends object & { + then(onfulfilled: infer F): any; +} ? F extends (value: infer V, ...args: any) => any ? _Awaited : never : T; + +/** + * Creates a Pinia instance to be used by the application + */ +export declare function createPinia(): Pinia; + +/** + * Recursive `Partial`. Used by {@link Store['$patch']}. + * + * For internal use **only** + */ +export declare type _DeepPartial = { + [K in keyof T]?: _DeepPartial; +}; + +/** + * Options parameter of `defineStore()` for setup stores. Can be extended to + * augment stores with the plugin API. @see {@link DefineStoreOptionsBase}. + */ +export declare interface DefineSetupStoreOptions extends DefineStoreOptionsBase> { + /** + * Extracted actions. Added by useStore(). SHOULD NOT be added by the user when + * creating the store. Can be used in plugins to get the list of actions in a + * store defined with a setup function. Note this is always defined + */ + actions?: A; +} + +/** + * Creates a `useStore` function that retrieves the store instance + * + * @param id - id of the store (must be unique) + * @param options - options to define the store + */ +export declare function defineStore = {}, A = {}>(id: Id, options: Omit, 'id'>): StoreDefinition; + +/** + * Creates a `useStore` function that retrieves the store instance + * + * @param options - options to define the store + */ +export declare function defineStore = {}, A = {}>(options: DefineStoreOptions): StoreDefinition; + +/** + * Creates a `useStore` function that retrieves the store instance + * + * @param id - id of the store (must be unique) + * @param storeSetup - function that defines the store + * @param options - extra options + */ +export declare function defineStore(id: Id, storeSetup: () => SS, options?: DefineSetupStoreOptions, _ExtractGettersFromSetupStore, _ExtractActionsFromSetupStore>): StoreDefinition, _ExtractGettersFromSetupStore, _ExtractActionsFromSetupStore>; + +/** + * Options parameter of `defineStore()` for option stores. Can be extended to + * augment stores with the plugin API. @see {@link DefineStoreOptionsBase}. + */ +export declare interface DefineStoreOptions extends DefineStoreOptionsBase> { + /** + * Unique string key to identify the store across the application. + */ + id: Id; + /** + * Function to create a fresh state. **Must be an arrow function** to ensure + * correct typings! + */ + state?: () => S; + /** + * Optional object of getters. + */ + getters?: G & ThisType & _StoreWithGetters & PiniaCustomProperties> & _GettersTree; + /** + * Optional object of actions. + */ + actions?: A & ThisType & _StoreWithState & _StoreWithGetters & PiniaCustomProperties>; + /** + * Allows hydrating the store during SSR when complex state (like client side only refs) are used in the store + * definition and copying the value from `pinia.state` isn't enough. + * + * @example + * If in your `state`, you use any `customRef`s, any `computed`s, or any `ref`s that have a different value on + * Server and Client, you need to manually hydrate them. e.g., a custom ref that is stored in the local + * storage: + * + * ```ts + * const useStore = defineStore('main', { + * state: () => ({ + * n: useLocalStorage('key', 0) + * }), + * hydrate(storeState, initialState) { + * // @ts-expect-error: https://github.com/microsoft/TypeScript/issues/43826 + * storeState.n = useLocalStorage('key', 0) + * } + * }) + * ``` + * + * @param storeState - the current state in the store + * @param initialState - initialState + */ + hydrate?(storeState: UnwrapRef, initialState: UnwrapRef): void; +} + +/** + * Options passed to `defineStore()` that are common between option and setup + * stores. Extend this interface if you want to add custom options to both kinds + * of stores. + */ +export declare interface DefineStoreOptionsBase { +} + +/** + * Available `options` when creating a pinia plugin. + */ +export declare interface DefineStoreOptionsInPlugin extends Omit, 'id' | 'actions'> { + /** + * Extracted object of actions. Added by useStore() when the store is built + * using the setup API, otherwise uses the one passed to `defineStore()`. + * Defaults to an empty object if no actions are defined. + */ + actions: A; +} + +/** + * For internal use **only** + */ +export declare type _ExtractActionsFromSetupStore = SS extends undefined | void ? {} : _ExtractActionsFromSetupStore_Keys extends keyof SS ? Pick> : never; + +/** + * Type that enables refactoring through IDE. + * For internal use **only** + */ +export declare type _ExtractActionsFromSetupStore_Keys = keyof { + [K in keyof SS as SS[K] extends _Method ? K : never]: any; +}; + +/** + * For internal use **only** + */ +export declare type _ExtractGettersFromSetupStore = SS extends undefined | void ? {} : _ExtractGettersFromSetupStore_Keys extends keyof SS ? Pick> : never; + +/** + * Type that enables refactoring through IDE. + * For internal use **only** + */ +export declare type _ExtractGettersFromSetupStore_Keys = keyof { + [K in keyof SS as SS[K] extends ComputedRef ? K : never]: any; +}; + +/** + * For internal use **only** + */ +export declare type _ExtractStateFromSetupStore = SS extends undefined | void ? {} : _ExtractStateFromSetupStore_Keys extends keyof SS ? _UnwrapAll>> : never; + +/** + * Type that enables refactoring through IDE. + * For internal use **only** + */ +export declare type _ExtractStateFromSetupStore_Keys = keyof { + [K in keyof SS as SS[K] extends _Method | ComputedRef ? never : K]: any; +}; + +/** + * Get the currently active pinia if there is any. + */ +export declare const getActivePinia: () => Pinia | undefined; + +/** + * Type of an object of Getters that infers the argument. For internal usage only. + * For internal use **only** + */ +export declare type _GettersTree = Record & UnwrapRef>) => any) | (() => any)>; + +/** + * Allows directly using actions from your store without using the composition + * API (`setup()`) by generating an object to be spread in the `methods` field + * of a component. The values of the object are the actions while the keys are + * the names of the resulting methods. + * + * @example + * ```js + * export default { + * methods: { + * // other methods properties + * // useCounterStore has two actions named `increment` and `setCount` + * ...mapActions(useCounterStore, { moar: 'increment', setIt: 'setCount' }) + * }, + * + * created() { + * this.moar() + * this.setIt(2) + * } + * } + * ``` + * + * @param useStore - store to map from + * @param keyMapper - object to define new names for the actions + */ +export declare function mapActions, A, KeyMapper extends Record>(useStore: StoreDefinition, keyMapper: KeyMapper): _MapActionsObjectReturn; + +/** + * Allows directly using actions from your store without using the composition + * API (`setup()`) by generating an object to be spread in the `methods` field + * of a component. + * + * @example + * ```js + * export default { + * methods: { + * // other methods properties + * ...mapActions(useCounterStore, ['increment', 'setCount']) + * }, + * + * created() { + * this.increment() + * this.setCount(2) // pass arguments as usual + * } + * } + * ``` + * + * @param useStore - store to map from + * @param keys - array of action names to map + */ +export declare function mapActions, A>(useStore: StoreDefinition, keys: Array): _MapActionsReturn; + +/** + * For internal use **only** + */ +export declare type _MapActionsObjectReturn> = { + [key in keyof T]: A[T[key]]; +}; + +/** + * For internal use **only** + */ +export declare type _MapActionsReturn = { + [key in keyof A]: A[key]; +}; + +/** + * Alias for `mapState()`. You should use `mapState()` instead. + * @deprecated use `mapState()` instead. + */ +export declare const mapGetters: typeof mapState; + +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. The values of the object are the state properties/getters + * while the keys are the names of the resulting computed properties. + * Optionally, you can also pass a custom function that will receive the store + * as its first argument. Note that while it has access to the component + * instance via `this`, it won't be typed. + * + * @example + * ```js + * export default { + * computed: { + * // other computed properties + * // useCounterStore has a state property named `count` and a getter `double` + * ...mapState(useCounterStore, { + * n: 'count', + * triple: store => store.n * 3, + * // note we can't use an arrow function if we want to use `this` + * custom(store) { + * return this.someComponentValue + store.n + * }, + * doubleN: 'double' + * }) + * }, + * + * created() { + * this.n // 2 + * this.doubleN // 4 + * } + * } + * ``` + * + * @param useStore - store to map from + * @param keyMapper - object of state properties or getters + */ +export declare function mapState, A, KeyMapper extends Record) => any)>>(useStore: StoreDefinition, keyMapper: KeyMapper): _MapStateObjectReturn; + +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @example + * ```js + * export default { + * computed: { + * // other computed properties + * ...mapState(useCounterStore, ['count', 'double']) + * }, + * + * created() { + * this.count // 2 + * this.double // 4 + * } + * } + * ``` + * + * @param useStore - store to map from + * @param keys - array of state properties or getters + */ +export declare function mapState, A, Keys extends keyof S | keyof G>(useStore: StoreDefinition, keys: readonly Keys[]): _MapStateReturn; + +/** + * For internal use **only** + */ +export declare type _MapStateObjectReturn, A, T extends Record) => any)> = {}> = { + [key in keyof T]: () => T[key] extends (store: any) => infer R ? R : T[key] extends keyof Store ? Store[T[key]] : never; +}; + +/** + * For internal use **only** + */ +export declare type _MapStateReturn, Keys extends keyof S | keyof G = keyof S | keyof G> = { + [key in Keys]: () => Store[key]; +}; + +/** + * Allows using stores without the composition API (`setup()`) by generating an + * object to be spread in the `computed` field of a component. It accepts a list + * of store definitions. + * + * @example + * ```js + * export default { + * computed: { + * // other computed properties + * ...mapStores(useUserStore, useCartStore) + * }, + * + * created() { + * this.userStore // store with id "user" + * this.cartStore // store with id "cart" + * } + * } + * ``` + * + * @param stores - list of stores to map to an object + */ +export declare function mapStores(...stores: [...Stores]): _Spread; + +/** + * Interface to allow customizing map helpers. Extend this interface with the + * following properties: + * + * - `suffix`: string. Affects the suffix of `mapStores()`, defaults to `Store`. + */ +export declare interface MapStoresCustomization { +} + +/** + * Same as `mapState()` but creates computed setters as well so the state can be + * modified. Differently from `mapState()`, only `state` properties can be + * added. + * + * @param useStore - store to map from + * @param keyMapper - object of state properties + */ +export declare function mapWritableState, A, KeyMapper extends Record>(useStore: StoreDefinition, keyMapper: KeyMapper): _MapWritableStateObjectReturn; + +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keys - array of state properties + */ +export declare function mapWritableState, A, Keys extends keyof S>(useStore: StoreDefinition, keys: readonly Keys[]): { + [K in Keys]: { + get: () => S[K]; + set: (value: S[K]) => any; + }; +}; + +/** + * For internal use **only** + */ +export declare type _MapWritableStateObjectReturn> = { + [key in keyof T]: { + get: () => S[T[key]]; + set: (value: S[T[key]]) => any; + }; +}; + +/** + * For internal use **only** + */ +export declare type _MapWritableStateReturn = { + [key in keyof S]: { + get: () => S[key]; + set: (value: S[key]) => any; + }; +}; + +/** + * Generic type for a function that can infer arguments and return type + * + * For internal use **only** + */ +export declare type _Method = (...args: any[]) => any; + +/** + * Possible types for SubscriptionCallback + */ +export declare enum MutationType { + /** + * Direct mutation of the state: + * + * - `store.name = 'new name'` + * - `store.$state.name = 'new name'` + * - `store.list.push('new item')` + */ + direct = "direct", + /** + * Mutated the state with `$patch` and an object + * + * - `store.$patch({ name: 'newName' })` + */ + patchObject = "patch object", + /** + * Mutated the state with `$patch` and a function + * + * - `store.$patch(state => state.name = 'newName')` + */ + patchFunction = "patch function" +} + +/** + * Every application must own its own pinia to be able to create stores + */ +export declare interface Pinia { + install: (app: App) => void; + /** + * root state + */ + state: Ref>; + /** + * Adds a store plugin to extend every store + * + * @param plugin - store plugin to add + */ + use(plugin: PiniaPlugin): Pinia; + /* Excluded from this release type: _p */ + /* Excluded from this release type: _a */ + /* Excluded from this release type: _e */ + /* Excluded from this release type: _s */ + /* Excluded from this release type: _testing */ +} + +/** + * Interface to be extended by the user when they add properties through plugins. + */ +export declare interface PiniaCustomProperties, A = _ActionsTree> { +} + +/** + * Properties that are added to every `store.$state` by `pinia.use()`. + */ +export declare interface PiniaCustomStateProperties { +} + +/** + * Plugin to extend every store. + */ +export declare interface PiniaPlugin { + /** + * Plugin to extend every store. Returns an object to extend the store or + * nothing. + * + * @param context - Context + */ + (context: PiniaPluginContext): Partial | void; +} + +/** + * Context argument passed to Pinia plugins. + */ +export declare interface PiniaPluginContext, A = _ActionsTree> { + /** + * pinia instance. + */ + pinia: Pinia; + /** + * Current app created with `Vue.createApp()`. + */ + app: App; + /** + * Current store being extended. + */ + store: Store; + /** + * Initial options defining the store when calling `defineStore()`. + */ + options: DefineStoreOptionsInPlugin; +} + +/** + * Plugin to extend every store. + * @deprecated use PiniaPlugin instead + */ +export declare type PiniaStorePlugin = PiniaPlugin; + +/** + * Vue 2 Plugin that must be installed for pinia to work. Note **you don't need + * this plugin if you are using Nuxt.js**. Use the `buildModule` instead: + * https://pinia.vuejs.org/ssr/nuxt.html. + * + * @example + * ```js + * import Vue from 'vue' + * import { PiniaVuePlugin, createPinia } from 'pinia' + * + * Vue.use(PiniaVuePlugin) + * const pinia = createPinia() + * + * new Vue({ + * el: '#app', + * // ... + * pinia, + * }) + * ``` + * + * @param _Vue - `Vue` imported from 'vue'. + */ +export declare const PiniaVuePlugin: Plugin_2; + +declare interface _SetActivePinia { + (pinia: Pinia): Pinia; + (pinia: undefined): undefined; + (pinia: Pinia | undefined): Pinia | undefined; +} + +/** + * Sets or unsets the active pinia. Used in SSR and internally when calling + * actions and getters + * + * @param pinia - Pinia instance + */ +export declare const setActivePinia: _SetActivePinia; + +/** + * Changes the suffix added by `mapStores()`. Can be set to an empty string. + * Defaults to `"Store"`. Make sure to extend the MapStoresCustomization + * interface if you are using TypeScript. + * + * @param suffix - new suffix + */ +export declare function setMapStoreSuffix(suffix: MapStoresCustomization extends Record<'suffix', infer Suffix> ? Suffix : string): void; + +/** + * Tells Pinia to skip the hydration process of a given object. This is useful in setup stores (only) when you return a + * stateful object in the store but it isn't really state. e.g. returning a router instance in a setup store. + * + * @param obj - target object + * @returns obj + */ +export declare function skipHydrate(obj: T): T; + +/** + * For internal use **only**. + */ +export declare type _Spread = A extends [infer L, ...infer R] ? _StoreObject & _Spread : unknown; + +/** + * Generic state of a Store + */ +export declare type StateTree = Record; + +/** + * Store type to build a store. + */ +export declare type Store = _StoreWithState & UnwrapRef & _StoreWithGetters & (_ActionsTree extends A ? {} : A) & PiniaCustomProperties & PiniaCustomStateProperties; + +/** + * Extract the actions of a store type. Works with both a Setup Store or an + * Options Store. + */ +export declare type StoreActions = SS extends Store, infer A> ? A : _ExtractActionsFromSetupStore; + +/** + * Return type of `defineStore()`. Function that allows instantiating a store. + */ +export declare interface StoreDefinition, A = _ActionsTree> { + /** + * Returns a store, creates it if necessary. + * + * @param pinia - Pinia instance to retrieve the store + * @param hot - dev only hot module replacement + */ + (pinia?: Pinia | null | undefined, hot?: StoreGeneric): Store; + /** + * Id of the store. Used by map helpers. + */ + $id: Id; + /* Excluded from this release type: _pinia */ +} + +/** + * Generic and type-unsafe version of Store. Doesn't fail on access with + * strings, making it much easier to write generic functions that do not care + * about the kind of store that is passed. + */ +export declare type StoreGeneric = Store, _ActionsTree>; + +/** + * Extract the getters of a store type. Works with both a Setup Store or an + * Options Store. + */ +export declare type StoreGetters = SS extends Store ? _StoreWithGetters : _ExtractGettersFromSetupStore; + +/** + * For internal use **only**. + */ +export declare type _StoreObject = S extends StoreDefinition ? { + [Id in `${Ids}${MapStoresCustomization extends Record<'suffix', infer Suffix> ? Suffix : 'Store'}`]: () => Store ? Suffix : 'Store'}` ? RealId : string, State, Getters, Actions>; +} : {}; + +/** + * Argument of `store.$onAction()` + */ +export declare type StoreOnActionListener = (context: StoreOnActionListenerContext) => void; + +/** + * Context object passed to callbacks of `store.$onAction(context => {})` + * TODO: should have only the Id, the Store and Actions to generate the proper object + */ +export declare type StoreOnActionListenerContext = _ActionsTree extends A ? _StoreOnActionListenerContext : { + [Name in keyof A]: Name extends string ? _StoreOnActionListenerContext, Name, A> : never; +}[keyof A]; + +/** + * Actual type for {@link StoreOnActionListenerContext}. Exists for refactoring + * purposes. For internal use only. + * For internal use **only** + */ +export declare interface _StoreOnActionListenerContext { + /** + * Name of the action + */ + name: ActionName; + /** + * Store that is invoking the action + */ + store: Store; + /** + * Parameters passed to the action + */ + args: A extends Record ? Parameters : unknown[]; + /** + * Sets up a hook once the action is finished. It receives the return value + * of the action, if it's a Promise, it will be unwrapped. + */ + after: (callback: A extends Record ? (resolvedReturn: _Awaited>) => void : () => void) => void; + /** + * Sets up a hook if the action fails. Return `false` to catch the error and + * stop it from propagating. + */ + onError: (callback: (error: unknown) => void) => void; +} + +/** + * Properties of a store. + */ +export declare interface StoreProperties { + /** + * Unique identifier of the store + */ + $id: Id; + /* Excluded from this release type: _p */ + /* Excluded from this release type: _getters */ + /* Excluded from this release type: _isOptionsAPI */ + /** + * Used by devtools plugin to retrieve properties added with plugins. Removed + * in production. Can be used by the user to add property keys of the store + * that should be displayed in devtools. + */ + _customProperties: Set; + /* Excluded from this release type: _hotUpdate */ + /* Excluded from this release type: _hotUpdating */ + /* Excluded from this release type: _hmrPayload */ +} + +/** + * Extract the state of a store type. Works with both a Setup Store or an + * Options Store. Note this unwraps refs. + */ +export declare type StoreState = SS extends Store, _ActionsTree> ? UnwrapRef : _ExtractStateFromSetupStore; + +/** + * Extracts the return type for `storeToRefs`. + * Will convert any `getters` into `ComputedRef`. + */ +declare type StoreToRefs = ToRefs & PiniaCustomStateProperties>> & ToComputedRefs>; + +/** + * Creates an object of references with all the state, getters, and plugin-added + * state properties of the store. Similar to `toRefs()` but specifically + * designed for Pinia stores so methods and non reactive properties are + * completely ignored. + * + * @param store - store to extract the refs from + */ +export declare function storeToRefs(store: SS): StoreToRefs; + +/** + * Store augmented for actions. For internal usage only. + * For internal use **only** + */ +export declare type _StoreWithActions = { + [k in keyof A]: A[k] extends (...args: infer P) => infer R ? (...args: P) => R : never; +}; + +/** + * Store augmented with getters. For internal usage only. + * For internal use **only** + */ +export declare type _StoreWithGetters = { + readonly [k in keyof G]: G[k] extends (...args: any[]) => infer R ? R : UnwrapRef; +}; + +/** + * Base store with state and functions. Should not be used directly. + */ +export declare interface _StoreWithState extends StoreProperties { + /** + * State of the Store. Setting it will internally call `$patch()` to update the state. + */ + $state: UnwrapRef & PiniaCustomStateProperties; + /** + * Applies a state patch to current state. Allows passing nested values + * + * @param partialState - patch to apply to the state + */ + $patch(partialState: _DeepPartial>): void; + /** + * Group multiple changes into one function. Useful when mutating objects like + * Sets or arrays and applying an object patch isn't practical, e.g. appending + * to an array. The function passed to `$patch()` **must be synchronous**. + * + * @param stateMutator - function that mutates `state`, cannot be asynchronous + */ + $patch) => any>(stateMutator: ReturnType extends Promise ? never : F): void; + /** + * Resets the store to its initial state by building a new state object. + * TODO: make this options only + */ + $reset(): void; + /** + * Setups a callback to be called whenever the state changes. It also returns a function to remove the callback. Note + * that when calling `store.$subscribe()` inside of a component, it will be automatically cleaned up when the + * component gets unmounted unless `detached` is set to true. + * + * @param callback - callback passed to the watcher + * @param options - `watch` options + `detached` to detach the subscription from the context (usually a component) + * this is called from. Note that the `flush` option does not affect calls to `store.$patch()`. + * @returns function that removes the watcher + */ + $subscribe(callback: SubscriptionCallback, options?: { + detached?: boolean; + } & WatchOptions): () => void; + /** + * Setups a callback to be called every time an action is about to get + * invoked. The callback receives an object with all the relevant information + * of the invoked action: + * - `store`: the store it is invoked on + * - `name`: The name of the action + * - `args`: The parameters passed to the action + * + * On top of these, it receives two functions that allow setting up a callback + * once the action finishes or when it fails. + * + * It also returns a function to remove the callback. Note than when calling + * `store.$onAction()` inside of a component, it will be automatically cleaned + * up when the component gets unmounted unless `detached` is set to true. + * + * @example + * + *```js + *store.$onAction(({ after, onError }) => { + * // Here you could share variables between all of the hooks as well as + * // setting up watchers and clean them up + * after((resolvedValue) => { + * // can be used to cleanup side effects + * . // `resolvedValue` is the value returned by the action, if it's a + * . // Promise, it will be the resolved value instead of the Promise + * }) + * onError((error) => { + * // can be used to pass up errors + * }) + *}) + *``` + * + * @param callback - callback called before every action + * @param detached - detach the subscription from the context this is called from + * @returns function that removes the watcher + */ + $onAction(callback: StoreOnActionListener, detached?: boolean): () => void; + /** + * Stops the associated effect scope of the store and remove it from the store + * registry. Plugins can override this method to cleanup any added effects. + * e.g. devtools plugin stops displaying disposed stores from devtools. + * Note this doesn't delete the state of the store, you have to do it manually with + * `delete pinia.state.value[store.$id]` if you want to. If you don't and the + * store is used again, it will reuse the previous state. + */ + $dispose(): void; + /* Excluded from this release type: _r */ +} + +/** + * Callback of a subscription + */ +export declare type SubscriptionCallback = ( +/** + * Object with information relative to the store mutation that triggered the + * subscription. + */ +mutation: SubscriptionCallbackMutation, +/** + * State of the store when the subscription is triggered. Same as + * `store.$state`. + */ +state: UnwrapRef) => void; + +/** + * Context object passed to a subscription callback. + */ +export declare type SubscriptionCallbackMutation = SubscriptionCallbackMutationDirect | SubscriptionCallbackMutationPatchObject | SubscriptionCallbackMutationPatchFunction; + +/** + * Base type for the context passed to a subscription callback. Internal type. + */ +export declare interface _SubscriptionCallbackMutationBase { + /** + * Type of the mutation. + */ + type: MutationType; + /** + * `id` of the store doing the mutation. + */ + storeId: string; + /** + * 🔴 DEV ONLY, DO NOT use for production code. Different mutation calls. Comes from + * https://vuejs.org/guide/extras/reactivity-in-depth.html#reactivity-debugging and allows to track mutations in + * devtools and plugins **during development only**. + */ + events?: DebuggerEvent[] | DebuggerEvent; +} + +/** + * Context passed to a subscription callback when directly mutating the state of + * a store with `store.someState = newValue` or `store.$state.someState = + * newValue`. + */ +export declare interface SubscriptionCallbackMutationDirect extends _SubscriptionCallbackMutationBase { + type: MutationType.direct; + events: DebuggerEvent; +} + +/** + * Context passed to a subscription callback when `store.$patch()` is called + * with a function. + */ +export declare interface SubscriptionCallbackMutationPatchFunction extends _SubscriptionCallbackMutationBase { + type: MutationType.patchFunction; + events: DebuggerEvent[]; +} + +/** + * Context passed to a subscription callback when `store.$patch()` is called + * with an object. + */ +export declare interface SubscriptionCallbackMutationPatchObject extends _SubscriptionCallbackMutationBase { + type: MutationType.patchObject; + events: DebuggerEvent[]; + /** + * Object passed to `store.$patch()`. + */ + payload: _DeepPartial; +} + +declare type ToComputedRefs = { + [K in keyof T]: ToRef extends Ref ? ComputedRef : ToRef; +}; + +/** + * Type that enables refactoring through IDE. + * For internal use **only** + */ +export declare type _UnwrapAll = { + [K in keyof SS]: UnwrapRef; +}; + +export { } + +// Extensions of Vue types to be appended manually +// https://github.com/microsoft/rushstack/issues/2090 +// https://github.com/microsoft/rushstack/issues/1709 + +// @ts-ignore: works on Vue 2, fails in Vue 3 +declare module 'vue/types/vue' { + interface Vue { + /** + * Currently installed pinia instance. + */ + $pinia: Pinia + + /** + * Cache of stores instantiated by the current instance. Used by map + * helpers. Used internally by Pinia. + * + * @internal + */ + _pStores?: Record + } +} + +// @ts-ignore: works on Vue 2, fails in Vue 3 +declare module 'vue/types/options' { + interface ComponentOptions { + /** + * Pinia instance to install in your application. Should be passed to the + * root Vue. + */ + pinia?: Pinia + } +} + +// TODO: figure out why it cannot be 'vue' +// @ts-ignore: works on Vue 3, fails in Vue 2 +declare module '@vue/runtime-core' { + export interface ComponentCustomProperties { + /** + * Access to the application's Pinia + */ + $pinia: Pinia + + /** + * Cache of stores instantiated by the current instance. Used by devtools to + * list currently used stores. Used internally by Pinia. + * + * @internal + */ + _pStores?: Record + } +} diff --git a/node_modules/pinia/dist/pinia.esm-browser.js b/node_modules/pinia/dist/pinia.esm-browser.js new file mode 100644 index 0000000..5e50d7d --- /dev/null +++ b/node_modules/pinia/dist/pinia.esm-browser.js @@ -0,0 +1,1996 @@ +/*! + * pinia v2.1.6 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */ +import { hasInjectionContext, inject, toRaw, watch, unref, markRaw, effectScope, ref, isVue2, isRef, isReactive, set, getCurrentScope, onScopeDispose, getCurrentInstance, reactive, toRef, del, nextTick, computed, toRefs } from 'vue-demi'; +import { setupDevtoolsPlugin } from '@vue/devtools-api'; + +/** + * setActivePinia must be called to handle SSR at the top of functions like + * `fetch`, `setup`, `serverPrefetch` and others + */ +let activePinia; +/** + * Sets or unsets the active pinia. Used in SSR and internally when calling + * actions and getters + * + * @param pinia - Pinia instance + */ +// @ts-expect-error: cannot constrain the type of the return +const setActivePinia = (pinia) => (activePinia = pinia); +/** + * Get the currently active pinia if there is any. + */ +const getActivePinia = () => (hasInjectionContext() && inject(piniaSymbol)) || activePinia; +const piniaSymbol = (Symbol('pinia') ); + +function isPlainObject( +// eslint-disable-next-line @typescript-eslint/no-explicit-any +o) { + return (o && + typeof o === 'object' && + Object.prototype.toString.call(o) === '[object Object]' && + typeof o.toJSON !== 'function'); +} +// type DeepReadonly = { readonly [P in keyof T]: DeepReadonly } +// TODO: can we change these to numbers? +/** + * Possible types for SubscriptionCallback + */ +var MutationType; +(function (MutationType) { + /** + * Direct mutation of the state: + * + * - `store.name = 'new name'` + * - `store.$state.name = 'new name'` + * - `store.list.push('new item')` + */ + MutationType["direct"] = "direct"; + /** + * Mutated the state with `$patch` and an object + * + * - `store.$patch({ name: 'newName' })` + */ + MutationType["patchObject"] = "patch object"; + /** + * Mutated the state with `$patch` and a function + * + * - `store.$patch(state => state.name = 'newName')` + */ + MutationType["patchFunction"] = "patch function"; + // maybe reset? for $state = {} and $reset +})(MutationType || (MutationType = {})); + +const IS_CLIENT = typeof window !== 'undefined'; +/** + * Should we add the devtools plugins. + * - only if dev mode or forced through the prod devtools flag + * - not in test + * - only if window exists (could change in the future) + */ +const USE_DEVTOOLS = IS_CLIENT; + +/* + * FileSaver.js A saveAs() FileSaver implementation. + * + * Originally by Eli Grey, adapted as an ESM module by Eduardo San Martin + * Morote. + * + * License : MIT + */ +// The one and only way of getting global scope in all environments +// https://stackoverflow.com/q/3277182/1008999 +const _global = /*#__PURE__*/ (() => typeof window === 'object' && window.window === window + ? window + : typeof self === 'object' && self.self === self + ? self + : typeof global === 'object' && global.global === global + ? global + : typeof globalThis === 'object' + ? globalThis + : { HTMLElement: null })(); +function bom(blob, { autoBom = false } = {}) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if (autoBom && + /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xfeff), blob], { type: blob.type }); + } + return blob; +} +function download(url, name, opts) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'blob'; + xhr.onload = function () { + saveAs(xhr.response, name, opts); + }; + xhr.onerror = function () { + console.error('could not download file'); + }; + xhr.send(); +} +function corsEnabled(url) { + const xhr = new XMLHttpRequest(); + // use sync to avoid popup blocker + xhr.open('HEAD', url, false); + try { + xhr.send(); + } + catch (e) { } + return xhr.status >= 200 && xhr.status <= 299; +} +// `a.click()` doesn't work for all browsers (#465) +function click(node) { + try { + node.dispatchEvent(new MouseEvent('click')); + } + catch (e) { + const evt = document.createEvent('MouseEvents'); + evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); + node.dispatchEvent(evt); + } +} +const _navigator = + typeof navigator === 'object' ? navigator : { userAgent: '' }; +// Detect WebView inside a native macOS app by ruling out all browsers +// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too +// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos +const isMacOSWebView = /*#__PURE__*/ (() => /Macintosh/.test(_navigator.userAgent) && + /AppleWebKit/.test(_navigator.userAgent) && + !/Safari/.test(_navigator.userAgent))(); +const saveAs = !IS_CLIENT + ? () => { } // noop + : // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView or mini program + typeof HTMLAnchorElement !== 'undefined' && + 'download' in HTMLAnchorElement.prototype && + !isMacOSWebView + ? downloadSaveAs + : // Use msSaveOrOpenBlob as a second approach + 'msSaveOrOpenBlob' in _navigator + ? msSaveAs + : // Fallback to using FileReader and a popup + fileSaverSaveAs; +function downloadSaveAs(blob, name = 'download', opts) { + const a = document.createElement('a'); + a.download = name; + a.rel = 'noopener'; // tabnabbing + // TODO: detect chrome extensions & packaged apps + // a.target = '_blank' + if (typeof blob === 'string') { + // Support regular links + a.href = blob; + if (a.origin !== location.origin) { + if (corsEnabled(a.href)) { + download(blob, name, opts); + } + else { + a.target = '_blank'; + click(a); + } + } + else { + click(a); + } + } + else { + // Support blobs + a.href = URL.createObjectURL(blob); + setTimeout(function () { + URL.revokeObjectURL(a.href); + }, 4e4); // 40s + setTimeout(function () { + click(a); + }, 0); + } +} +function msSaveAs(blob, name = 'download', opts) { + if (typeof blob === 'string') { + if (corsEnabled(blob)) { + download(blob, name, opts); + } + else { + const a = document.createElement('a'); + a.href = blob; + a.target = '_blank'; + setTimeout(function () { + click(a); + }); + } + } + else { + // @ts-ignore: works on windows + navigator.msSaveOrOpenBlob(bom(blob, opts), name); + } +} +function fileSaverSaveAs(blob, name, opts, popup) { + // Open a popup immediately do go around popup blocker + // Mostly only available on user interaction and the fileReader is async so... + popup = popup || open('', '_blank'); + if (popup) { + popup.document.title = popup.document.body.innerText = 'downloading...'; + } + if (typeof blob === 'string') + return download(blob, name, opts); + const force = blob.type === 'application/octet-stream'; + const isSafari = /constructor/i.test(String(_global.HTMLElement)) || 'safari' in _global; + const isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); + if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && + typeof FileReader !== 'undefined') { + // Safari doesn't allow downloading of blob URLs + const reader = new FileReader(); + reader.onloadend = function () { + let url = reader.result; + if (typeof url !== 'string') { + popup = null; + throw new Error('Wrong reader.result type'); + } + url = isChromeIOS + ? url + : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); + if (popup) { + popup.location.href = url; + } + else { + location.assign(url); + } + popup = null; // reverse-tabnabbing #460 + }; + reader.readAsDataURL(blob); + } + else { + const url = URL.createObjectURL(blob); + if (popup) + popup.location.assign(url); + else + location.href = url; + popup = null; // reverse-tabnabbing #460 + setTimeout(function () { + URL.revokeObjectURL(url); + }, 4e4); // 40s + } +} + +/** + * Shows a toast or console.log + * + * @param message - message to log + * @param type - different color of the tooltip + */ +function toastMessage(message, type) { + const piniaMessage = '🍍 ' + message; + if (typeof __VUE_DEVTOOLS_TOAST__ === 'function') { + // No longer available :( + __VUE_DEVTOOLS_TOAST__(piniaMessage, type); + } + else if (type === 'error') { + console.error(piniaMessage); + } + else if (type === 'warn') { + console.warn(piniaMessage); + } + else { + console.log(piniaMessage); + } +} +function isPinia(o) { + return '_a' in o && 'install' in o; +} + +/** + * This file contain devtools actions, they are not Pinia actions. + */ +// --- +function checkClipboardAccess() { + if (!('clipboard' in navigator)) { + toastMessage(`Your browser doesn't support the Clipboard API`, 'error'); + return true; + } +} +function checkNotFocusedError(error) { + if (error instanceof Error && + error.message.toLowerCase().includes('document is not focused')) { + toastMessage('You need to activate the "Emulate a focused page" setting in the "Rendering" panel of devtools.', 'warn'); + return true; + } + return false; +} +async function actionGlobalCopyState(pinia) { + if (checkClipboardAccess()) + return; + try { + await navigator.clipboard.writeText(JSON.stringify(pinia.state.value)); + toastMessage('Global state copied to clipboard.'); + } + catch (error) { + if (checkNotFocusedError(error)) + return; + toastMessage(`Failed to serialize the state. Check the console for more details.`, 'error'); + console.error(error); + } +} +async function actionGlobalPasteState(pinia) { + if (checkClipboardAccess()) + return; + try { + loadStoresState(pinia, JSON.parse(await navigator.clipboard.readText())); + toastMessage('Global state pasted from clipboard.'); + } + catch (error) { + if (checkNotFocusedError(error)) + return; + toastMessage(`Failed to deserialize the state from clipboard. Check the console for more details.`, 'error'); + console.error(error); + } +} +async function actionGlobalSaveState(pinia) { + try { + saveAs(new Blob([JSON.stringify(pinia.state.value)], { + type: 'text/plain;charset=utf-8', + }), 'pinia-state.json'); + } + catch (error) { + toastMessage(`Failed to export the state as JSON. Check the console for more details.`, 'error'); + console.error(error); + } +} +let fileInput; +function getFileOpener() { + if (!fileInput) { + fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = '.json'; + } + function openFile() { + return new Promise((resolve, reject) => { + fileInput.onchange = async () => { + const files = fileInput.files; + if (!files) + return resolve(null); + const file = files.item(0); + if (!file) + return resolve(null); + return resolve({ text: await file.text(), file }); + }; + // @ts-ignore: TODO: changed from 4.3 to 4.4 + fileInput.oncancel = () => resolve(null); + fileInput.onerror = reject; + fileInput.click(); + }); + } + return openFile; +} +async function actionGlobalOpenStateFile(pinia) { + try { + const open = getFileOpener(); + const result = await open(); + if (!result) + return; + const { text, file } = result; + loadStoresState(pinia, JSON.parse(text)); + toastMessage(`Global state imported from "${file.name}".`); + } + catch (error) { + toastMessage(`Failed to import the state from JSON. Check the console for more details.`, 'error'); + console.error(error); + } +} +function loadStoresState(pinia, state) { + for (const key in state) { + const storeState = pinia.state.value[key]; + if (storeState) { + Object.assign(storeState, state[key]); + } + } +} + +function formatDisplay(display) { + return { + _custom: { + display, + }, + }; +} +const PINIA_ROOT_LABEL = '🍍 Pinia (root)'; +const PINIA_ROOT_ID = '_root'; +function formatStoreForInspectorTree(store) { + return isPinia(store) + ? { + id: PINIA_ROOT_ID, + label: PINIA_ROOT_LABEL, + } + : { + id: store.$id, + label: store.$id, + }; +} +function formatStoreForInspectorState(store) { + if (isPinia(store)) { + const storeNames = Array.from(store._s.keys()); + const storeMap = store._s; + const state = { + state: storeNames.map((storeId) => ({ + editable: true, + key: storeId, + value: store.state.value[storeId], + })), + getters: storeNames + .filter((id) => storeMap.get(id)._getters) + .map((id) => { + const store = storeMap.get(id); + return { + editable: false, + key: id, + value: store._getters.reduce((getters, key) => { + getters[key] = store[key]; + return getters; + }, {}), + }; + }), + }; + return state; + } + const state = { + state: Object.keys(store.$state).map((key) => ({ + editable: true, + key, + value: store.$state[key], + })), + }; + // avoid adding empty getters + if (store._getters && store._getters.length) { + state.getters = store._getters.map((getterName) => ({ + editable: false, + key: getterName, + value: store[getterName], + })); + } + if (store._customProperties.size) { + state.customProperties = Array.from(store._customProperties).map((key) => ({ + editable: true, + key, + value: store[key], + })); + } + return state; +} +function formatEventData(events) { + if (!events) + return {}; + if (Array.isArray(events)) { + // TODO: handle add and delete for arrays and objects + return events.reduce((data, event) => { + data.keys.push(event.key); + data.operations.push(event.type); + data.oldValue[event.key] = event.oldValue; + data.newValue[event.key] = event.newValue; + return data; + }, { + oldValue: {}, + keys: [], + operations: [], + newValue: {}, + }); + } + else { + return { + operation: formatDisplay(events.type), + key: formatDisplay(events.key), + oldValue: events.oldValue, + newValue: events.newValue, + }; + } +} +function formatMutationType(type) { + switch (type) { + case MutationType.direct: + return 'mutation'; + case MutationType.patchFunction: + return '$patch'; + case MutationType.patchObject: + return '$patch'; + default: + return 'unknown'; + } +} + +// timeline can be paused when directly changing the state +let isTimelineActive = true; +const componentStateTypes = []; +const MUTATIONS_LAYER_ID = 'pinia:mutations'; +const INSPECTOR_ID = 'pinia'; +const { assign: assign$1 } = Object; +/** + * Gets the displayed name of a store in devtools + * + * @param id - id of the store + * @returns a formatted string + */ +const getStoreType = (id) => '🍍 ' + id; +/** + * Add the pinia plugin without any store. Allows displaying a Pinia plugin tab + * as soon as it is added to the application. + * + * @param app - Vue application + * @param pinia - pinia instance + */ +function registerPiniaDevtools(app, pinia) { + setupDevtoolsPlugin({ + id: 'dev.esm.pinia', + label: 'Pinia 🍍', + logo: 'https://pinia.vuejs.org/logo.svg', + packageName: 'pinia', + homepage: 'https://pinia.vuejs.org', + componentStateTypes, + app, + }, (api) => { + if (typeof api.now !== 'function') { + toastMessage('You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html.'); + } + api.addTimelineLayer({ + id: MUTATIONS_LAYER_ID, + label: `Pinia 🍍`, + color: 0xe5df88, + }); + api.addInspector({ + id: INSPECTOR_ID, + label: 'Pinia 🍍', + icon: 'storage', + treeFilterPlaceholder: 'Search stores', + actions: [ + { + icon: 'content_copy', + action: () => { + actionGlobalCopyState(pinia); + }, + tooltip: 'Serialize and copy the state', + }, + { + icon: 'content_paste', + action: async () => { + await actionGlobalPasteState(pinia); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }, + tooltip: 'Replace the state with the content of your clipboard', + }, + { + icon: 'save', + action: () => { + actionGlobalSaveState(pinia); + }, + tooltip: 'Save the state as a JSON file', + }, + { + icon: 'folder_open', + action: async () => { + await actionGlobalOpenStateFile(pinia); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }, + tooltip: 'Import the state from a JSON file', + }, + ], + nodeActions: [ + { + icon: 'restore', + tooltip: 'Reset the state (with "$reset")', + action: (nodeId) => { + const store = pinia._s.get(nodeId); + if (!store) { + toastMessage(`Cannot reset "${nodeId}" store because it wasn't found.`, 'warn'); + } + else if (typeof store.$reset !== 'function') { + toastMessage(`Cannot reset "${nodeId}" store because it doesn't have a "$reset" method implemented.`, 'warn'); + } + else { + store.$reset(); + toastMessage(`Store "${nodeId}" reset.`); + } + }, + }, + ], + }); + api.on.inspectComponent((payload, ctx) => { + const proxy = (payload.componentInstance && + payload.componentInstance.proxy); + if (proxy && proxy._pStores) { + const piniaStores = payload.componentInstance.proxy._pStores; + Object.values(piniaStores).forEach((store) => { + payload.instanceData.state.push({ + type: getStoreType(store.$id), + key: 'state', + editable: true, + value: store._isOptionsAPI + ? { + _custom: { + value: toRaw(store.$state), + actions: [ + { + icon: 'restore', + tooltip: 'Reset the state of this store', + action: () => store.$reset(), + }, + ], + }, + } + : // NOTE: workaround to unwrap transferred refs + Object.keys(store.$state).reduce((state, key) => { + state[key] = store.$state[key]; + return state; + }, {}), + }); + if (store._getters && store._getters.length) { + payload.instanceData.state.push({ + type: getStoreType(store.$id), + key: 'getters', + editable: false, + value: store._getters.reduce((getters, key) => { + try { + getters[key] = store[key]; + } + catch (error) { + // @ts-expect-error: we just want to show it in devtools + getters[key] = error; + } + return getters; + }, {}), + }); + } + }); + } + }); + api.on.getInspectorTree((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + let stores = [pinia]; + stores = stores.concat(Array.from(pinia._s.values())); + payload.rootNodes = (payload.filter + ? stores.filter((store) => '$id' in store + ? store.$id + .toLowerCase() + .includes(payload.filter.toLowerCase()) + : PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase())) + : stores).map(formatStoreForInspectorTree); + } + }); + api.on.getInspectorState((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const inspectedStore = payload.nodeId === PINIA_ROOT_ID + ? pinia + : pinia._s.get(payload.nodeId); + if (!inspectedStore) { + // this could be the selected store restored for a different project + // so it's better not to say anything here + return; + } + if (inspectedStore) { + payload.state = formatStoreForInspectorState(inspectedStore); + } + } + }); + api.on.editInspectorState((payload, ctx) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const inspectedStore = payload.nodeId === PINIA_ROOT_ID + ? pinia + : pinia._s.get(payload.nodeId); + if (!inspectedStore) { + return toastMessage(`store "${payload.nodeId}" not found`, 'error'); + } + const { path } = payload; + if (!isPinia(inspectedStore)) { + // access only the state + if (path.length !== 1 || + !inspectedStore._customProperties.has(path[0]) || + path[0] in inspectedStore.$state) { + path.unshift('$state'); + } + } + else { + // Root access, we can omit the `.value` because the devtools API does it for us + path.unshift('state'); + } + isTimelineActive = false; + payload.set(inspectedStore, path, payload.state.value); + isTimelineActive = true; + } + }); + api.on.editComponentState((payload) => { + if (payload.type.startsWith('🍍')) { + const storeId = payload.type.replace(/^🍍\s*/, ''); + const store = pinia._s.get(storeId); + if (!store) { + return toastMessage(`store "${storeId}" not found`, 'error'); + } + const { path } = payload; + if (path[0] !== 'state') { + return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`); + } + // rewrite the first entry to be able to directly set the state as + // well as any other path + path[0] = '$state'; + isTimelineActive = false; + payload.set(store, path, payload.state.value); + isTimelineActive = true; + } + }); + }); +} +function addStoreToDevtools(app, store) { + if (!componentStateTypes.includes(getStoreType(store.$id))) { + componentStateTypes.push(getStoreType(store.$id)); + } + setupDevtoolsPlugin({ + id: 'dev.esm.pinia', + label: 'Pinia 🍍', + logo: 'https://pinia.vuejs.org/logo.svg', + packageName: 'pinia', + homepage: 'https://pinia.vuejs.org', + componentStateTypes, + app, + settings: { + logStoreChanges: { + label: 'Notify about new/deleted stores', + type: 'boolean', + defaultValue: true, + }, + // useEmojis: { + // label: 'Use emojis in messages ⚡️', + // type: 'boolean', + // defaultValue: true, + // }, + }, + }, (api) => { + // gracefully handle errors + const now = typeof api.now === 'function' ? api.now.bind(api) : Date.now; + store.$onAction(({ after, onError, name, args }) => { + const groupId = runningActionId++; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🛫 ' + name, + subtitle: 'start', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + }, + groupId, + }, + }); + after((result) => { + activeAction = undefined; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🛬 ' + name, + subtitle: 'end', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + result, + }, + groupId, + }, + }); + }); + onError((error) => { + activeAction = undefined; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + logType: 'error', + title: '💥 ' + name, + subtitle: 'end', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + error, + }, + groupId, + }, + }); + }); + }, true); + store._customProperties.forEach((name) => { + watch(() => unref(store[name]), (newValue, oldValue) => { + api.notifyComponentUpdate(); + api.sendInspectorState(INSPECTOR_ID); + if (isTimelineActive) { + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: 'Change', + subtitle: name, + data: { + newValue, + oldValue, + }, + groupId: activeAction, + }, + }); + } + }, { deep: true }); + }); + store.$subscribe(({ events, type }, state) => { + api.notifyComponentUpdate(); + api.sendInspectorState(INSPECTOR_ID); + if (!isTimelineActive) + return; + // rootStore.state[store.id] = state + const eventData = { + time: now(), + title: formatMutationType(type), + data: assign$1({ store: formatDisplay(store.$id) }, formatEventData(events)), + groupId: activeAction, + }; + if (type === MutationType.patchFunction) { + eventData.subtitle = '⤵️'; + } + else if (type === MutationType.patchObject) { + eventData.subtitle = '🧩'; + } + else if (events && !Array.isArray(events)) { + eventData.subtitle = events.type; + } + if (events) { + eventData.data['rawEvent(s)'] = { + _custom: { + display: 'DebuggerEvent', + type: 'object', + tooltip: 'raw DebuggerEvent[]', + value: events, + }, + }; + } + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: eventData, + }); + }, { detached: true, flush: 'sync' }); + const hotUpdate = store._hotUpdate; + store._hotUpdate = markRaw((newStore) => { + hotUpdate(newStore); + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🔥 ' + store.$id, + subtitle: 'HMR update', + data: { + store: formatDisplay(store.$id), + info: formatDisplay(`HMR update`), + }, + }, + }); + // update the devtools too + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }); + const { $dispose } = store; + store.$dispose = () => { + $dispose(); + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + api.getSettings().logStoreChanges && + toastMessage(`Disposed "${store.$id}" store 🗑`); + }; + // trigger an update so it can display new registered stores + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + api.getSettings().logStoreChanges && + toastMessage(`"${store.$id}" store installed 🆕`); + }); +} +let runningActionId = 0; +let activeAction; +/** + * Patches a store to enable action grouping in devtools by wrapping the store with a Proxy that is passed as the + * context of all actions, allowing us to set `runningAction` on each access and effectively associating any state + * mutation to the action. + * + * @param store - store to patch + * @param actionNames - list of actionst to patch + */ +function patchActionForGrouping(store, actionNames, wrapWithProxy) { + // original actions of the store as they are given by pinia. We are going to override them + const actions = actionNames.reduce((storeActions, actionName) => { + // use toRaw to avoid tracking #541 + storeActions[actionName] = toRaw(store)[actionName]; + return storeActions; + }, {}); + for (const actionName in actions) { + store[actionName] = function () { + // the running action id is incremented in a before action hook + const _actionId = runningActionId; + const trackedStore = wrapWithProxy + ? new Proxy(store, { + get(...args) { + activeAction = _actionId; + return Reflect.get(...args); + }, + set(...args) { + activeAction = _actionId; + return Reflect.set(...args); + }, + }) + : store; + // For Setup Stores we need https://github.com/tc39/proposal-async-context + activeAction = _actionId; + const retValue = actions[actionName].apply(trackedStore, arguments); + // this is safer as async actions in Setup Stores would associate mutations done outside of the action + activeAction = undefined; + return retValue; + }; + } +} +/** + * pinia.use(devtoolsPlugin) + */ +function devtoolsPlugin({ app, store, options }) { + // HMR module + if (store.$id.startsWith('__hot:')) { + return; + } + // detect option api vs setup api + store._isOptionsAPI = !!options.state; + patchActionForGrouping(store, Object.keys(options.actions), store._isOptionsAPI); + // Upgrade the HMR to also update the new actions + const originalHotUpdate = store._hotUpdate; + toRaw(store)._hotUpdate = function (newStore) { + originalHotUpdate.apply(this, arguments); + patchActionForGrouping(store, Object.keys(newStore._hmrPayload.actions), !!store._isOptionsAPI); + }; + addStoreToDevtools(app, + // FIXME: is there a way to allow the assignment from Store to StoreGeneric? + store); +} + +/** + * Creates a Pinia instance to be used by the application + */ +function createPinia() { + const scope = effectScope(true); + // NOTE: here we could check the window object for a state and directly set it + // if there is anything like it with Vue 3 SSR + const state = scope.run(() => ref({})); + let _p = []; + // plugins added before calling app.use(pinia) + let toBeInstalled = []; + const pinia = markRaw({ + install(app) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + if (!isVue2) { + pinia._a = app; + app.provide(piniaSymbol, pinia); + app.config.globalProperties.$pinia = pinia; + /* istanbul ignore else */ + if (USE_DEVTOOLS) { + registerPiniaDevtools(app, pinia); + } + toBeInstalled.forEach((plugin) => _p.push(plugin)); + toBeInstalled = []; + } + }, + use(plugin) { + if (!this._a && !isVue2) { + toBeInstalled.push(plugin); + } + else { + _p.push(plugin); + } + return this; + }, + _p, + // it's actually undefined here + // @ts-expect-error + _a: null, + _e: scope, + _s: new Map(), + state, + }); + // pinia devtools rely on dev only features so they cannot be forced unless + // the dev build of Vue is used. Avoid old browsers like IE11. + if (USE_DEVTOOLS && typeof Proxy !== 'undefined') { + pinia.use(devtoolsPlugin); + } + return pinia; +} + +/** + * Checks if a function is a `StoreDefinition`. + * + * @param fn - object to test + * @returns true if `fn` is a StoreDefinition + */ +const isUseStore = (fn) => { + return typeof fn === 'function' && typeof fn.$id === 'string'; +}; +/** + * Mutates in place `newState` with `oldState` to _hot update_ it. It will + * remove any key not existing in `newState` and recursively merge plain + * objects. + * + * @param newState - new state object to be patched + * @param oldState - old state that should be used to patch newState + * @returns - newState + */ +function patchObject(newState, oldState) { + // no need to go through symbols because they cannot be serialized anyway + for (const key in oldState) { + const subPatch = oldState[key]; + // skip the whole sub tree + if (!(key in newState)) { + continue; + } + const targetValue = newState[key]; + if (isPlainObject(targetValue) && + isPlainObject(subPatch) && + !isRef(subPatch) && + !isReactive(subPatch)) { + newState[key] = patchObject(targetValue, subPatch); + } + else { + // objects are either a bit more complex (e.g. refs) or primitives, so we + // just set the whole thing + if (isVue2) { + set(newState, key, subPatch); + } + else { + newState[key] = subPatch; + } + } + } + return newState; +} +/** + * Creates an _accept_ function to pass to `import.meta.hot` in Vite applications. + * + * @example + * ```js + * const useUser = defineStore(...) + * if (import.meta.hot) { + * import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot)) + * } + * ``` + * + * @param initialUseStore - return of the defineStore to hot update + * @param hot - `import.meta.hot` + */ +function acceptHMRUpdate(initialUseStore, hot) { + return (newModule) => { + const pinia = hot.data.pinia || initialUseStore._pinia; + if (!pinia) { + // this store is still not used + return; + } + // preserve the pinia instance across loads + hot.data.pinia = pinia; + // console.log('got data', newStore) + for (const exportName in newModule) { + const useStore = newModule[exportName]; + // console.log('checking for', exportName) + if (isUseStore(useStore) && pinia._s.has(useStore.$id)) { + // console.log('Accepting update for', useStore.$id) + const id = useStore.$id; + if (id !== initialUseStore.$id) { + console.warn(`The id of the store changed from "${initialUseStore.$id}" to "${id}". Reloading.`); + // return import.meta.hot.invalidate() + return hot.invalidate(); + } + const existingStore = pinia._s.get(id); + if (!existingStore) { + console.log(`[Pinia]: skipping hmr because store doesn't exist yet`); + return; + } + useStore(pinia, existingStore); + } + } + }; +} + +const noop = () => { }; +function addSubscription(subscriptions, callback, detached, onCleanup = noop) { + subscriptions.push(callback); + const removeSubscription = () => { + const idx = subscriptions.indexOf(callback); + if (idx > -1) { + subscriptions.splice(idx, 1); + onCleanup(); + } + }; + if (!detached && getCurrentScope()) { + onScopeDispose(removeSubscription); + } + return removeSubscription; +} +function triggerSubscriptions(subscriptions, ...args) { + subscriptions.slice().forEach((callback) => { + callback(...args); + }); +} + +const fallbackRunWithContext = (fn) => fn(); +function mergeReactiveObjects(target, patchToApply) { + // Handle Map instances + if (target instanceof Map && patchToApply instanceof Map) { + patchToApply.forEach((value, key) => target.set(key, value)); + } + // Handle Set instances + if (target instanceof Set && patchToApply instanceof Set) { + patchToApply.forEach(target.add, target); + } + // no need to go through symbols because they cannot be serialized anyway + for (const key in patchToApply) { + if (!patchToApply.hasOwnProperty(key)) + continue; + const subPatch = patchToApply[key]; + const targetValue = target[key]; + if (isPlainObject(targetValue) && + isPlainObject(subPatch) && + target.hasOwnProperty(key) && + !isRef(subPatch) && + !isReactive(subPatch)) { + // NOTE: here I wanted to warn about inconsistent types but it's not possible because in setup stores one might + // start the value of a property as a certain type e.g. a Map, and then for some reason, during SSR, change that + // to `undefined`. When trying to hydrate, we want to override the Map with `undefined`. + target[key] = mergeReactiveObjects(targetValue, subPatch); + } + else { + // @ts-expect-error: subPatch is a valid value + target[key] = subPatch; + } + } + return target; +} +const skipHydrateSymbol = Symbol('pinia:skipHydration') + ; +const skipHydrateMap = /*#__PURE__*/ new WeakMap(); +/** + * Tells Pinia to skip the hydration process of a given object. This is useful in setup stores (only) when you return a + * stateful object in the store but it isn't really state. e.g. returning a router instance in a setup store. + * + * @param obj - target object + * @returns obj + */ +function skipHydrate(obj) { + return isVue2 + ? // in @vue/composition-api, the refs are sealed so defineProperty doesn't work... + /* istanbul ignore next */ skipHydrateMap.set(obj, 1) && obj + : Object.defineProperty(obj, skipHydrateSymbol, {}); +} +/** + * Returns whether a value should be hydrated + * + * @param obj - target variable + * @returns true if `obj` should be hydrated + */ +function shouldHydrate(obj) { + return isVue2 + ? /* istanbul ignore next */ !skipHydrateMap.has(obj) + : !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol); +} +const { assign } = Object; +function isComputed(o) { + return !!(isRef(o) && o.effect); +} +function createOptionsStore(id, options, pinia, hot) { + const { state, actions, getters } = options; + const initialState = pinia.state.value[id]; + let store; + function setup() { + if (!initialState && (!hot)) { + /* istanbul ignore if */ + if (isVue2) { + set(pinia.state.value, id, state ? state() : {}); + } + else { + pinia.state.value[id] = state ? state() : {}; + } + } + // avoid creating a state in pinia.state.value + const localState = hot + ? // use ref() to unwrap refs inside state TODO: check if this is still necessary + toRefs(ref(state ? state() : {}).value) + : toRefs(pinia.state.value[id]); + return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => { + if (name in localState) { + console.warn(`[🍍]: A getter cannot have the same name as another state property. Rename one of them. Found with "${name}" in store "${id}".`); + } + computedGetters[name] = markRaw(computed(() => { + setActivePinia(pinia); + // it was created just before + const store = pinia._s.get(id); + // allow cross using stores + /* istanbul ignore next */ + if (isVue2 && !store._r) + return; + // @ts-expect-error + // return getters![name].call(context, context) + // TODO: avoid reading the getter while assigning with a global variable + return getters[name].call(store, store); + })); + return computedGetters; + }, {})); + } + store = createSetupStore(id, setup, options, pinia, hot, true); + return store; +} +function createSetupStore($id, setup, options = {}, pinia, hot, isOptionsStore) { + let scope; + const optionsForPlugin = assign({ actions: {} }, options); + /* istanbul ignore if */ + if (!pinia._e.active) { + throw new Error('Pinia destroyed'); + } + // watcher options for $subscribe + const $subscribeOptions = { + deep: true, + // flush: 'post', + }; + /* istanbul ignore else */ + if (!isVue2) { + $subscribeOptions.onTrigger = (event) => { + /* istanbul ignore else */ + if (isListening) { + debuggerEvents = event; + // avoid triggering this while the store is being built and the state is being set in pinia + } + else if (isListening == false && !store._hotUpdating) { + // let patch send all the events together later + /* istanbul ignore else */ + if (Array.isArray(debuggerEvents)) { + debuggerEvents.push(event); + } + else { + console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.'); + } + } + }; + } + // internal state + let isListening; // set to true at the end + let isSyncListening; // set to true at the end + let subscriptions = []; + let actionSubscriptions = []; + let debuggerEvents; + const initialState = pinia.state.value[$id]; + // avoid setting the state for option stores if it is set + // by the setup + if (!isOptionsStore && !initialState && (!hot)) { + /* istanbul ignore if */ + if (isVue2) { + set(pinia.state.value, $id, {}); + } + else { + pinia.state.value[$id] = {}; + } + } + const hotState = ref({}); + // avoid triggering too many listeners + // https://github.com/vuejs/pinia/issues/1129 + let activeListener; + function $patch(partialStateOrMutator) { + let subscriptionMutation; + isListening = isSyncListening = false; + // reset the debugger events since patches are sync + /* istanbul ignore else */ + { + debuggerEvents = []; + } + if (typeof partialStateOrMutator === 'function') { + partialStateOrMutator(pinia.state.value[$id]); + subscriptionMutation = { + type: MutationType.patchFunction, + storeId: $id, + events: debuggerEvents, + }; + } + else { + mergeReactiveObjects(pinia.state.value[$id], partialStateOrMutator); + subscriptionMutation = { + type: MutationType.patchObject, + payload: partialStateOrMutator, + storeId: $id, + events: debuggerEvents, + }; + } + const myListenerId = (activeListener = Symbol()); + nextTick().then(() => { + if (activeListener === myListenerId) { + isListening = true; + } + }); + isSyncListening = true; + // because we paused the watcher, we need to manually call the subscriptions + triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]); + } + const $reset = isOptionsStore + ? function $reset() { + const { state } = options; + const newState = state ? state() : {}; + // we use a patch to group all changes into one single subscription + this.$patch(($state) => { + assign($state, newState); + }); + } + : /* istanbul ignore next */ + () => { + throw new Error(`🍍: Store "${$id}" is built using the setup syntax and does not implement $reset().`); + } + ; + function $dispose() { + scope.stop(); + subscriptions = []; + actionSubscriptions = []; + pinia._s.delete($id); + } + /** + * Wraps an action to handle subscriptions. + * + * @param name - name of the action + * @param action - action to wrap + * @returns a wrapped action to handle subscriptions + */ + function wrapAction(name, action) { + return function () { + setActivePinia(pinia); + const args = Array.from(arguments); + const afterCallbackList = []; + const onErrorCallbackList = []; + function after(callback) { + afterCallbackList.push(callback); + } + function onError(callback) { + onErrorCallbackList.push(callback); + } + // @ts-expect-error + triggerSubscriptions(actionSubscriptions, { + args, + name, + store, + after, + onError, + }); + let ret; + try { + ret = action.apply(this && this.$id === $id ? this : store, args); + // handle sync errors + } + catch (error) { + triggerSubscriptions(onErrorCallbackList, error); + throw error; + } + if (ret instanceof Promise) { + return ret + .then((value) => { + triggerSubscriptions(afterCallbackList, value); + return value; + }) + .catch((error) => { + triggerSubscriptions(onErrorCallbackList, error); + return Promise.reject(error); + }); + } + // trigger after callbacks + triggerSubscriptions(afterCallbackList, ret); + return ret; + }; + } + const _hmrPayload = /*#__PURE__*/ markRaw({ + actions: {}, + getters: {}, + state: [], + hotState, + }); + const partialStore = { + _p: pinia, + // _s: scope, + $id, + $onAction: addSubscription.bind(null, actionSubscriptions), + $patch, + $reset, + $subscribe(callback, options = {}) { + const removeSubscription = addSubscription(subscriptions, callback, options.detached, () => stopWatcher()); + const stopWatcher = scope.run(() => watch(() => pinia.state.value[$id], (state) => { + if (options.flush === 'sync' ? isSyncListening : isListening) { + callback({ + storeId: $id, + type: MutationType.direct, + events: debuggerEvents, + }, state); + } + }, assign({}, $subscribeOptions, options))); + return removeSubscription; + }, + $dispose, + }; + /* istanbul ignore if */ + if (isVue2) { + // start as non ready + partialStore._r = false; + } + const store = reactive(assign({ + _hmrPayload, + _customProperties: markRaw(new Set()), // devtools custom properties + }, partialStore + // must be added later + // setupStore + ) + ); + // store the partial store now so the setup of stores can instantiate each other before they are finished without + // creating infinite loops. + pinia._s.set($id, store); + const runWithContext = (pinia._a && pinia._a.runWithContext) || fallbackRunWithContext; + // TODO: idea create skipSerialize that marks properties as non serializable and they are skipped + const setupStore = pinia._e.run(() => { + scope = effectScope(); + return runWithContext(() => scope.run(setup)); + }); + // overwrite existing actions to support $onAction + for (const key in setupStore) { + const prop = setupStore[key]; + if ((isRef(prop) && !isComputed(prop)) || isReactive(prop)) { + // mark it as a piece of state to be serialized + if (hot) { + set(hotState.value, key, toRef(setupStore, key)); + // createOptionStore directly sets the state in pinia.state.value so we + // can just skip that + } + else if (!isOptionsStore) { + // in setup stores we must hydrate the state and sync pinia state tree with the refs the user just created + if (initialState && shouldHydrate(prop)) { + if (isRef(prop)) { + prop.value = initialState[key]; + } + else { + // probably a reactive object, lets recursively assign + // @ts-expect-error: prop is unknown + mergeReactiveObjects(prop, initialState[key]); + } + } + // transfer the ref to the pinia state to keep everything in sync + /* istanbul ignore if */ + if (isVue2) { + set(pinia.state.value[$id], key, prop); + } + else { + pinia.state.value[$id][key] = prop; + } + } + /* istanbul ignore else */ + { + _hmrPayload.state.push(key); + } + // action + } + else if (typeof prop === 'function') { + // @ts-expect-error: we are overriding the function we avoid wrapping if + const actionValue = hot ? prop : wrapAction(key, prop); + // this a hot module replacement store because the hotUpdate method needs + // to do it with the right context + /* istanbul ignore if */ + if (isVue2) { + set(setupStore, key, actionValue); + } + else { + // @ts-expect-error + setupStore[key] = actionValue; + } + /* istanbul ignore else */ + { + _hmrPayload.actions[key] = prop; + } + // list actions so they can be used in plugins + // @ts-expect-error + optionsForPlugin.actions[key] = prop; + } + else { + // add getters for devtools + if (isComputed(prop)) { + _hmrPayload.getters[key] = isOptionsStore + ? // @ts-expect-error + options.getters[key] + : prop; + if (IS_CLIENT) { + const getters = setupStore._getters || + // @ts-expect-error: same + (setupStore._getters = markRaw([])); + getters.push(key); + } + } + } + } + // add the state, getters, and action properties + /* istanbul ignore if */ + if (isVue2) { + Object.keys(setupStore).forEach((key) => { + set(store, key, setupStore[key]); + }); + } + else { + assign(store, setupStore); + // allows retrieving reactive objects with `storeToRefs()`. Must be called after assigning to the reactive object. + // Make `storeToRefs()` work with `reactive()` #799 + assign(toRaw(store), setupStore); + } + // use this instead of a computed with setter to be able to create it anywhere + // without linking the computed lifespan to wherever the store is first + // created. + Object.defineProperty(store, '$state', { + get: () => (hot ? hotState.value : pinia.state.value[$id]), + set: (state) => { + /* istanbul ignore if */ + if (hot) { + throw new Error('cannot set hotState'); + } + $patch(($state) => { + assign($state, state); + }); + }, + }); + // add the hotUpdate before plugins to allow them to override it + /* istanbul ignore else */ + { + store._hotUpdate = markRaw((newStore) => { + store._hotUpdating = true; + newStore._hmrPayload.state.forEach((stateKey) => { + if (stateKey in store.$state) { + const newStateTarget = newStore.$state[stateKey]; + const oldStateSource = store.$state[stateKey]; + if (typeof newStateTarget === 'object' && + isPlainObject(newStateTarget) && + isPlainObject(oldStateSource)) { + patchObject(newStateTarget, oldStateSource); + } + else { + // transfer the ref + newStore.$state[stateKey] = oldStateSource; + } + } + // patch direct access properties to allow store.stateProperty to work as + // store.$state.stateProperty + set(store, stateKey, toRef(newStore.$state, stateKey)); + }); + // remove deleted state properties + Object.keys(store.$state).forEach((stateKey) => { + if (!(stateKey in newStore.$state)) { + del(store, stateKey); + } + }); + // avoid devtools logging this as a mutation + isListening = false; + isSyncListening = false; + pinia.state.value[$id] = toRef(newStore._hmrPayload, 'hotState'); + isSyncListening = true; + nextTick().then(() => { + isListening = true; + }); + for (const actionName in newStore._hmrPayload.actions) { + const action = newStore[actionName]; + set(store, actionName, wrapAction(actionName, action)); + } + // TODO: does this work in both setup and option store? + for (const getterName in newStore._hmrPayload.getters) { + const getter = newStore._hmrPayload.getters[getterName]; + const getterValue = isOptionsStore + ? // special handling of options api + computed(() => { + setActivePinia(pinia); + return getter.call(store, store); + }) + : getter; + set(store, getterName, getterValue); + } + // remove deleted getters + Object.keys(store._hmrPayload.getters).forEach((key) => { + if (!(key in newStore._hmrPayload.getters)) { + del(store, key); + } + }); + // remove old actions + Object.keys(store._hmrPayload.actions).forEach((key) => { + if (!(key in newStore._hmrPayload.actions)) { + del(store, key); + } + }); + // update the values used in devtools and to allow deleting new properties later on + store._hmrPayload = newStore._hmrPayload; + store._getters = newStore._getters; + store._hotUpdating = false; + }); + } + if (USE_DEVTOOLS) { + const nonEnumerable = { + writable: true, + configurable: true, + // avoid warning on devtools trying to display this property + enumerable: false, + }; + ['_p', '_hmrPayload', '_getters', '_customProperties'].forEach((p) => { + Object.defineProperty(store, p, assign({ value: store[p] }, nonEnumerable)); + }); + } + /* istanbul ignore if */ + if (isVue2) { + // mark the store as ready before plugins + store._r = true; + } + // apply all plugins + pinia._p.forEach((extender) => { + /* istanbul ignore else */ + if (USE_DEVTOOLS) { + const extensions = scope.run(() => extender({ + store, + app: pinia._a, + pinia, + options: optionsForPlugin, + })); + Object.keys(extensions || {}).forEach((key) => store._customProperties.add(key)); + assign(store, extensions); + } + else { + assign(store, scope.run(() => extender({ + store, + app: pinia._a, + pinia, + options: optionsForPlugin, + }))); + } + }); + if (store.$state && + typeof store.$state === 'object' && + typeof store.$state.constructor === 'function' && + !store.$state.constructor.toString().includes('[native code]')) { + console.warn(`[🍍]: The "state" must be a plain object. It cannot be\n` + + `\tstate: () => new MyClass()\n` + + `Found in store "${store.$id}".`); + } + // only apply hydrate to option stores with an initial state in pinia + if (initialState && + isOptionsStore && + options.hydrate) { + options.hydrate(store.$state, initialState); + } + isListening = true; + isSyncListening = true; + return store; +} +function defineStore( +// TODO: add proper types from above +idOrOptions, setup, setupOptions) { + let id; + let options; + const isSetupStore = typeof setup === 'function'; + if (typeof idOrOptions === 'string') { + id = idOrOptions; + // the option store setup will contain the actual options in this case + options = isSetupStore ? setupOptions : setup; + } + else { + options = idOrOptions; + id = idOrOptions.id; + if (typeof id !== 'string') { + throw new Error(`[🍍]: "defineStore()" must be passed a store id as its first argument.`); + } + } + function useStore(pinia, hot) { + const hasContext = hasInjectionContext(); + pinia = + // in test mode, ignore the argument provided as we can always retrieve a + // pinia instance with getActivePinia() + (pinia) || + (hasContext ? inject(piniaSymbol, null) : null); + if (pinia) + setActivePinia(pinia); + if (!activePinia) { + throw new Error(`[🍍]: "getActivePinia()" was called but there was no active Pinia. Did you forget to install pinia?\n` + + `\tconst pinia = createPinia()\n` + + `\tapp.use(pinia)\n` + + `This will fail in production.`); + } + pinia = activePinia; + if (!pinia._s.has(id)) { + // creating the store registers it in `pinia._s` + if (isSetupStore) { + createSetupStore(id, setup, options, pinia); + } + else { + createOptionsStore(id, options, pinia); + } + /* istanbul ignore else */ + { + // @ts-expect-error: not the right inferred type + useStore._pinia = pinia; + } + } + const store = pinia._s.get(id); + if (hot) { + const hotId = '__hot:' + id; + const newStore = isSetupStore + ? createSetupStore(hotId, setup, options, pinia, true) + : createOptionsStore(hotId, assign({}, options), pinia, true); + hot._hotUpdate(newStore); + // cleanup the state properties and the store from the cache + delete pinia.state.value[hotId]; + pinia._s.delete(hotId); + } + if (IS_CLIENT) { + const currentInstance = getCurrentInstance(); + // save stores in instances to access them devtools + if (currentInstance && + currentInstance.proxy && + // avoid adding stores that are just built for hot module replacement + !hot) { + const vm = currentInstance.proxy; + const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {}); + cache[id] = store; + } + } + // StoreGeneric cannot be casted towards Store + return store; + } + useStore.$id = id; + return useStore; +} + +let mapStoreSuffix = 'Store'; +/** + * Changes the suffix added by `mapStores()`. Can be set to an empty string. + * Defaults to `"Store"`. Make sure to extend the MapStoresCustomization + * interface if you are using TypeScript. + * + * @param suffix - new suffix + */ +function setMapStoreSuffix(suffix // could be 'Store' but that would be annoying for JS +) { + mapStoreSuffix = suffix; +} +/** + * Allows using stores without the composition API (`setup()`) by generating an + * object to be spread in the `computed` field of a component. It accepts a list + * of store definitions. + * + * @example + * ```js + * export default { + * computed: { + * // other computed properties + * ...mapStores(useUserStore, useCartStore) + * }, + * + * created() { + * this.userStore // store with id "user" + * this.cartStore // store with id "cart" + * } + * } + * ``` + * + * @param stores - list of stores to map to an object + */ +function mapStores(...stores) { + if (Array.isArray(stores[0])) { + console.warn(`[🍍]: Directly pass all stores to "mapStores()" without putting them in an array:\n` + + `Replace\n` + + `\tmapStores([useAuthStore, useCartStore])\n` + + `with\n` + + `\tmapStores(useAuthStore, useCartStore)\n` + + `This will fail in production if not fixed.`); + stores = stores[0]; + } + return stores.reduce((reduced, useStore) => { + // @ts-expect-error: $id is added by defineStore + reduced[useStore.$id + mapStoreSuffix] = function () { + return useStore(this.$pinia); + }; + return reduced; + }, {}); +} +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + reduced[key] = function () { + return useStore(this.$pinia)[key]; + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function () { + const store = useStore(this.$pinia); + const storeKey = keysOrMapper[key]; + // for some reason TS is unable to infer the type of storeKey to be a + // function + return typeof storeKey === 'function' + ? storeKey.call(this, store) + : store[storeKey]; + }; + return reduced; + }, {}); +} +/** + * Alias for `mapState()`. You should use `mapState()` instead. + * @deprecated use `mapState()` instead. + */ +const mapGetters = mapState; +/** + * Allows directly using actions from your store without using the composition + * API (`setup()`) by generating an object to be spread in the `methods` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapActions(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[key](...args); + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[keysOrMapper[key]](...args); + }; + return reduced; + }, {}); +} +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapWritableState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[key]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[key] = value); + }, + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[keysOrMapper[key]]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[keysOrMapper[key]] = value); + }, + }; + return reduced; + }, {}); +} + +/** + * Creates an object of references with all the state, getters, and plugin-added + * state properties of the store. Similar to `toRefs()` but specifically + * designed for Pinia stores so methods and non reactive properties are + * completely ignored. + * + * @param store - store to extract the refs from + */ +function storeToRefs(store) { + // See https://github.com/vuejs/pinia/issues/852 + // It's easier to just use toRefs() even if it includes more stuff + if (isVue2) { + // @ts-expect-error: toRefs include methods and others + return toRefs(store); + } + else { + store = toRaw(store); + const refs = {}; + for (const key in store) { + const value = store[key]; + if (isRef(value) || isReactive(value)) { + // @ts-expect-error: the key is state or getter + refs[key] = + // --- + toRef(store, key); + } + } + return refs; + } +} + +/** + * Vue 2 Plugin that must be installed for pinia to work. Note **you don't need + * this plugin if you are using Nuxt.js**. Use the `buildModule` instead: + * https://pinia.vuejs.org/ssr/nuxt.html. + * + * @example + * ```js + * import Vue from 'vue' + * import { PiniaVuePlugin, createPinia } from 'pinia' + * + * Vue.use(PiniaVuePlugin) + * const pinia = createPinia() + * + * new Vue({ + * el: '#app', + * // ... + * pinia, + * }) + * ``` + * + * @param _Vue - `Vue` imported from 'vue'. + */ +const PiniaVuePlugin = function (_Vue) { + // Equivalent of + // app.config.globalProperties.$pinia = pinia + _Vue.mixin({ + beforeCreate() { + const options = this.$options; + if (options.pinia) { + const pinia = options.pinia; + // HACK: taken from provide(): https://github.com/vuejs/composition-api/blob/main/src/apis/inject.ts#L31 + /* istanbul ignore else */ + if (!this._provided) { + const provideCache = {}; + Object.defineProperty(this, '_provided', { + get: () => provideCache, + set: (v) => Object.assign(provideCache, v), + }); + } + this._provided[piniaSymbol] = pinia; + // propagate the pinia instance in an SSR friendly way + // avoid adding it to nuxt twice + /* istanbul ignore else */ + if (!this.$pinia) { + this.$pinia = pinia; + } + pinia._a = this; + if (IS_CLIENT) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + } + if (USE_DEVTOOLS) { + registerPiniaDevtools(pinia._a, pinia); + } + } + else if (!this.$pinia && options.parent && options.parent.$pinia) { + this.$pinia = options.parent.$pinia; + } + }, + destroyed() { + delete this._pStores; + }, + }); +}; + +export { MutationType, PiniaVuePlugin, acceptHMRUpdate, createPinia, defineStore, getActivePinia, mapActions, mapGetters, mapState, mapStores, mapWritableState, setActivePinia, setMapStoreSuffix, skipHydrate, storeToRefs }; diff --git a/node_modules/pinia/dist/pinia.iife.js b/node_modules/pinia/dist/pinia.iife.js new file mode 100644 index 0000000..64f1c55 --- /dev/null +++ b/node_modules/pinia/dist/pinia.iife.js @@ -0,0 +1,2180 @@ +/*! + * pinia v2.1.6 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */ +var Pinia = (function (exports, vueDemi) { + 'use strict'; + + /** + * setActivePinia must be called to handle SSR at the top of functions like + * `fetch`, `setup`, `serverPrefetch` and others + */ + let activePinia; + /** + * Sets or unsets the active pinia. Used in SSR and internally when calling + * actions and getters + * + * @param pinia - Pinia instance + */ + // @ts-expect-error: cannot constrain the type of the return + const setActivePinia = (pinia) => (activePinia = pinia); + /** + * Get the currently active pinia if there is any. + */ + const getActivePinia = () => (vueDemi.hasInjectionContext() && vueDemi.inject(piniaSymbol)) || activePinia; + const piniaSymbol = (Symbol('pinia') ); + + function getDevtoolsGlobalHook() { + return getTarget().__VUE_DEVTOOLS_GLOBAL_HOOK__; + } + function getTarget() { + // @ts-ignore + return (typeof navigator !== 'undefined' && typeof window !== 'undefined') + ? window + : typeof global !== 'undefined' + ? global + : {}; + } + const isProxyAvailable = typeof Proxy === 'function'; + + const HOOK_SETUP = 'devtools-plugin:setup'; + const HOOK_PLUGIN_SETTINGS_SET = 'plugin:settings:set'; + + let supported; + let perf; + function isPerformanceSupported() { + var _a; + if (supported !== undefined) { + return supported; + } + if (typeof window !== 'undefined' && window.performance) { + supported = true; + perf = window.performance; + } + else if (typeof global !== 'undefined' && ((_a = global.perf_hooks) === null || _a === void 0 ? void 0 : _a.performance)) { + supported = true; + perf = global.perf_hooks.performance; + } + else { + supported = false; + } + return supported; + } + function now() { + return isPerformanceSupported() ? perf.now() : Date.now(); + } + + class ApiProxy { + constructor(plugin, hook) { + this.target = null; + this.targetQueue = []; + this.onQueue = []; + this.plugin = plugin; + this.hook = hook; + const defaultSettings = {}; + if (plugin.settings) { + for (const id in plugin.settings) { + const item = plugin.settings[id]; + defaultSettings[id] = item.defaultValue; + } + } + const localSettingsSaveId = `__vue-devtools-plugin-settings__${plugin.id}`; + let currentSettings = Object.assign({}, defaultSettings); + try { + const raw = localStorage.getItem(localSettingsSaveId); + const data = JSON.parse(raw); + Object.assign(currentSettings, data); + } + catch (e) { + // noop + } + this.fallbacks = { + getSettings() { + return currentSettings; + }, + setSettings(value) { + try { + localStorage.setItem(localSettingsSaveId, JSON.stringify(value)); + } + catch (e) { + // noop + } + currentSettings = value; + }, + now() { + return now(); + }, + }; + if (hook) { + hook.on(HOOK_PLUGIN_SETTINGS_SET, (pluginId, value) => { + if (pluginId === this.plugin.id) { + this.fallbacks.setSettings(value); + } + }); + } + this.proxiedOn = new Proxy({}, { + get: (_target, prop) => { + if (this.target) { + return this.target.on[prop]; + } + else { + return (...args) => { + this.onQueue.push({ + method: prop, + args, + }); + }; + } + }, + }); + this.proxiedTarget = new Proxy({}, { + get: (_target, prop) => { + if (this.target) { + return this.target[prop]; + } + else if (prop === 'on') { + return this.proxiedOn; + } + else if (Object.keys(this.fallbacks).includes(prop)) { + return (...args) => { + this.targetQueue.push({ + method: prop, + args, + resolve: () => { }, + }); + return this.fallbacks[prop](...args); + }; + } + else { + return (...args) => { + return new Promise(resolve => { + this.targetQueue.push({ + method: prop, + args, + resolve, + }); + }); + }; + } + }, + }); + } + async setRealTarget(target) { + this.target = target; + for (const item of this.onQueue) { + this.target.on[item.method](...item.args); + } + for (const item of this.targetQueue) { + item.resolve(await this.target[item.method](...item.args)); + } + } + } + + function setupDevtoolsPlugin(pluginDescriptor, setupFn) { + const descriptor = pluginDescriptor; + const target = getTarget(); + const hook = getDevtoolsGlobalHook(); + const enableProxy = isProxyAvailable && descriptor.enableEarlyProxy; + if (hook && (target.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__ || !enableProxy)) { + hook.emit(HOOK_SETUP, pluginDescriptor, setupFn); + } + else { + const proxy = enableProxy ? new ApiProxy(descriptor, hook) : null; + const list = target.__VUE_DEVTOOLS_PLUGINS__ = target.__VUE_DEVTOOLS_PLUGINS__ || []; + list.push({ + pluginDescriptor: descriptor, + setupFn, + proxy, + }); + if (proxy) + setupFn(proxy.proxiedTarget); + } + } + + function isPlainObject( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + o) { + return (o && + typeof o === 'object' && + Object.prototype.toString.call(o) === '[object Object]' && + typeof o.toJSON !== 'function'); + } + // type DeepReadonly = { readonly [P in keyof T]: DeepReadonly } + // TODO: can we change these to numbers? + /** + * Possible types for SubscriptionCallback + */ + exports.MutationType = void 0; + (function (MutationType) { + /** + * Direct mutation of the state: + * + * - `store.name = 'new name'` + * - `store.$state.name = 'new name'` + * - `store.list.push('new item')` + */ + MutationType["direct"] = "direct"; + /** + * Mutated the state with `$patch` and an object + * + * - `store.$patch({ name: 'newName' })` + */ + MutationType["patchObject"] = "patch object"; + /** + * Mutated the state with `$patch` and a function + * + * - `store.$patch(state => state.name = 'newName')` + */ + MutationType["patchFunction"] = "patch function"; + // maybe reset? for $state = {} and $reset + })(exports.MutationType || (exports.MutationType = {})); + + const IS_CLIENT = typeof window !== 'undefined'; + /** + * Should we add the devtools plugins. + * - only if dev mode or forced through the prod devtools flag + * - not in test + * - only if window exists (could change in the future) + */ + const USE_DEVTOOLS = IS_CLIENT; + + /* + * FileSaver.js A saveAs() FileSaver implementation. + * + * Originally by Eli Grey, adapted as an ESM module by Eduardo San Martin + * Morote. + * + * License : MIT + */ + // The one and only way of getting global scope in all environments + // https://stackoverflow.com/q/3277182/1008999 + const _global = /*#__PURE__*/ (() => typeof window === 'object' && window.window === window + ? window + : typeof self === 'object' && self.self === self + ? self + : typeof global === 'object' && global.global === global + ? global + : typeof globalThis === 'object' + ? globalThis + : { HTMLElement: null })(); + function bom(blob, { autoBom = false } = {}) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if (autoBom && + /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xfeff), blob], { type: blob.type }); + } + return blob; + } + function download(url, name, opts) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'blob'; + xhr.onload = function () { + saveAs(xhr.response, name, opts); + }; + xhr.onerror = function () { + console.error('could not download file'); + }; + xhr.send(); + } + function corsEnabled(url) { + const xhr = new XMLHttpRequest(); + // use sync to avoid popup blocker + xhr.open('HEAD', url, false); + try { + xhr.send(); + } + catch (e) { } + return xhr.status >= 200 && xhr.status <= 299; + } + // `a.click()` doesn't work for all browsers (#465) + function click(node) { + try { + node.dispatchEvent(new MouseEvent('click')); + } + catch (e) { + const evt = document.createEvent('MouseEvents'); + evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); + node.dispatchEvent(evt); + } + } + const _navigator = + typeof navigator === 'object' ? navigator : { userAgent: '' }; + // Detect WebView inside a native macOS app by ruling out all browsers + // We just need to check for 'Safari' because all other browsers (besides Firefox) include that too + // https://www.whatismybrowser.com/guides/the-latest-user-agent/macos + const isMacOSWebView = /*#__PURE__*/ (() => /Macintosh/.test(_navigator.userAgent) && + /AppleWebKit/.test(_navigator.userAgent) && + !/Safari/.test(_navigator.userAgent))(); + const saveAs = !IS_CLIENT + ? () => { } // noop + : // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView or mini program + typeof HTMLAnchorElement !== 'undefined' && + 'download' in HTMLAnchorElement.prototype && + !isMacOSWebView + ? downloadSaveAs + : // Use msSaveOrOpenBlob as a second approach + 'msSaveOrOpenBlob' in _navigator + ? msSaveAs + : // Fallback to using FileReader and a popup + fileSaverSaveAs; + function downloadSaveAs(blob, name = 'download', opts) { + const a = document.createElement('a'); + a.download = name; + a.rel = 'noopener'; // tabnabbing + // TODO: detect chrome extensions & packaged apps + // a.target = '_blank' + if (typeof blob === 'string') { + // Support regular links + a.href = blob; + if (a.origin !== location.origin) { + if (corsEnabled(a.href)) { + download(blob, name, opts); + } + else { + a.target = '_blank'; + click(a); + } + } + else { + click(a); + } + } + else { + // Support blobs + a.href = URL.createObjectURL(blob); + setTimeout(function () { + URL.revokeObjectURL(a.href); + }, 4e4); // 40s + setTimeout(function () { + click(a); + }, 0); + } + } + function msSaveAs(blob, name = 'download', opts) { + if (typeof blob === 'string') { + if (corsEnabled(blob)) { + download(blob, name, opts); + } + else { + const a = document.createElement('a'); + a.href = blob; + a.target = '_blank'; + setTimeout(function () { + click(a); + }); + } + } + else { + // @ts-ignore: works on windows + navigator.msSaveOrOpenBlob(bom(blob, opts), name); + } + } + function fileSaverSaveAs(blob, name, opts, popup) { + // Open a popup immediately do go around popup blocker + // Mostly only available on user interaction and the fileReader is async so... + popup = popup || open('', '_blank'); + if (popup) { + popup.document.title = popup.document.body.innerText = 'downloading...'; + } + if (typeof blob === 'string') + return download(blob, name, opts); + const force = blob.type === 'application/octet-stream'; + const isSafari = /constructor/i.test(String(_global.HTMLElement)) || 'safari' in _global; + const isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); + if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && + typeof FileReader !== 'undefined') { + // Safari doesn't allow downloading of blob URLs + const reader = new FileReader(); + reader.onloadend = function () { + let url = reader.result; + if (typeof url !== 'string') { + popup = null; + throw new Error('Wrong reader.result type'); + } + url = isChromeIOS + ? url + : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); + if (popup) { + popup.location.href = url; + } + else { + location.assign(url); + } + popup = null; // reverse-tabnabbing #460 + }; + reader.readAsDataURL(blob); + } + else { + const url = URL.createObjectURL(blob); + if (popup) + popup.location.assign(url); + else + location.href = url; + popup = null; // reverse-tabnabbing #460 + setTimeout(function () { + URL.revokeObjectURL(url); + }, 4e4); // 40s + } + } + + /** + * Shows a toast or console.log + * + * @param message - message to log + * @param type - different color of the tooltip + */ + function toastMessage(message, type) { + const piniaMessage = '🍍 ' + message; + if (typeof __VUE_DEVTOOLS_TOAST__ === 'function') { + // No longer available :( + __VUE_DEVTOOLS_TOAST__(piniaMessage, type); + } + else if (type === 'error') { + console.error(piniaMessage); + } + else if (type === 'warn') { + console.warn(piniaMessage); + } + else { + console.log(piniaMessage); + } + } + function isPinia(o) { + return '_a' in o && 'install' in o; + } + + /** + * This file contain devtools actions, they are not Pinia actions. + */ + // --- + function checkClipboardAccess() { + if (!('clipboard' in navigator)) { + toastMessage(`Your browser doesn't support the Clipboard API`, 'error'); + return true; + } + } + function checkNotFocusedError(error) { + if (error instanceof Error && + error.message.toLowerCase().includes('document is not focused')) { + toastMessage('You need to activate the "Emulate a focused page" setting in the "Rendering" panel of devtools.', 'warn'); + return true; + } + return false; + } + async function actionGlobalCopyState(pinia) { + if (checkClipboardAccess()) + return; + try { + await navigator.clipboard.writeText(JSON.stringify(pinia.state.value)); + toastMessage('Global state copied to clipboard.'); + } + catch (error) { + if (checkNotFocusedError(error)) + return; + toastMessage(`Failed to serialize the state. Check the console for more details.`, 'error'); + console.error(error); + } + } + async function actionGlobalPasteState(pinia) { + if (checkClipboardAccess()) + return; + try { + loadStoresState(pinia, JSON.parse(await navigator.clipboard.readText())); + toastMessage('Global state pasted from clipboard.'); + } + catch (error) { + if (checkNotFocusedError(error)) + return; + toastMessage(`Failed to deserialize the state from clipboard. Check the console for more details.`, 'error'); + console.error(error); + } + } + async function actionGlobalSaveState(pinia) { + try { + saveAs(new Blob([JSON.stringify(pinia.state.value)], { + type: 'text/plain;charset=utf-8', + }), 'pinia-state.json'); + } + catch (error) { + toastMessage(`Failed to export the state as JSON. Check the console for more details.`, 'error'); + console.error(error); + } + } + let fileInput; + function getFileOpener() { + if (!fileInput) { + fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = '.json'; + } + function openFile() { + return new Promise((resolve, reject) => { + fileInput.onchange = async () => { + const files = fileInput.files; + if (!files) + return resolve(null); + const file = files.item(0); + if (!file) + return resolve(null); + return resolve({ text: await file.text(), file }); + }; + // @ts-ignore: TODO: changed from 4.3 to 4.4 + fileInput.oncancel = () => resolve(null); + fileInput.onerror = reject; + fileInput.click(); + }); + } + return openFile; + } + async function actionGlobalOpenStateFile(pinia) { + try { + const open = getFileOpener(); + const result = await open(); + if (!result) + return; + const { text, file } = result; + loadStoresState(pinia, JSON.parse(text)); + toastMessage(`Global state imported from "${file.name}".`); + } + catch (error) { + toastMessage(`Failed to import the state from JSON. Check the console for more details.`, 'error'); + console.error(error); + } + } + function loadStoresState(pinia, state) { + for (const key in state) { + const storeState = pinia.state.value[key]; + if (storeState) { + Object.assign(storeState, state[key]); + } + } + } + + function formatDisplay(display) { + return { + _custom: { + display, + }, + }; + } + const PINIA_ROOT_LABEL = '🍍 Pinia (root)'; + const PINIA_ROOT_ID = '_root'; + function formatStoreForInspectorTree(store) { + return isPinia(store) + ? { + id: PINIA_ROOT_ID, + label: PINIA_ROOT_LABEL, + } + : { + id: store.$id, + label: store.$id, + }; + } + function formatStoreForInspectorState(store) { + if (isPinia(store)) { + const storeNames = Array.from(store._s.keys()); + const storeMap = store._s; + const state = { + state: storeNames.map((storeId) => ({ + editable: true, + key: storeId, + value: store.state.value[storeId], + })), + getters: storeNames + .filter((id) => storeMap.get(id)._getters) + .map((id) => { + const store = storeMap.get(id); + return { + editable: false, + key: id, + value: store._getters.reduce((getters, key) => { + getters[key] = store[key]; + return getters; + }, {}), + }; + }), + }; + return state; + } + const state = { + state: Object.keys(store.$state).map((key) => ({ + editable: true, + key, + value: store.$state[key], + })), + }; + // avoid adding empty getters + if (store._getters && store._getters.length) { + state.getters = store._getters.map((getterName) => ({ + editable: false, + key: getterName, + value: store[getterName], + })); + } + if (store._customProperties.size) { + state.customProperties = Array.from(store._customProperties).map((key) => ({ + editable: true, + key, + value: store[key], + })); + } + return state; + } + function formatEventData(events) { + if (!events) + return {}; + if (Array.isArray(events)) { + // TODO: handle add and delete for arrays and objects + return events.reduce((data, event) => { + data.keys.push(event.key); + data.operations.push(event.type); + data.oldValue[event.key] = event.oldValue; + data.newValue[event.key] = event.newValue; + return data; + }, { + oldValue: {}, + keys: [], + operations: [], + newValue: {}, + }); + } + else { + return { + operation: formatDisplay(events.type), + key: formatDisplay(events.key), + oldValue: events.oldValue, + newValue: events.newValue, + }; + } + } + function formatMutationType(type) { + switch (type) { + case exports.MutationType.direct: + return 'mutation'; + case exports.MutationType.patchFunction: + return '$patch'; + case exports.MutationType.patchObject: + return '$patch'; + default: + return 'unknown'; + } + } + + // timeline can be paused when directly changing the state + let isTimelineActive = true; + const componentStateTypes = []; + const MUTATIONS_LAYER_ID = 'pinia:mutations'; + const INSPECTOR_ID = 'pinia'; + const { assign: assign$1 } = Object; + /** + * Gets the displayed name of a store in devtools + * + * @param id - id of the store + * @returns a formatted string + */ + const getStoreType = (id) => '🍍 ' + id; + /** + * Add the pinia plugin without any store. Allows displaying a Pinia plugin tab + * as soon as it is added to the application. + * + * @param app - Vue application + * @param pinia - pinia instance + */ + function registerPiniaDevtools(app, pinia) { + setupDevtoolsPlugin({ + id: 'dev.esm.pinia', + label: 'Pinia 🍍', + logo: 'https://pinia.vuejs.org/logo.svg', + packageName: 'pinia', + homepage: 'https://pinia.vuejs.org', + componentStateTypes, + app, + }, (api) => { + if (typeof api.now !== 'function') { + toastMessage('You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html.'); + } + api.addTimelineLayer({ + id: MUTATIONS_LAYER_ID, + label: `Pinia 🍍`, + color: 0xe5df88, + }); + api.addInspector({ + id: INSPECTOR_ID, + label: 'Pinia 🍍', + icon: 'storage', + treeFilterPlaceholder: 'Search stores', + actions: [ + { + icon: 'content_copy', + action: () => { + actionGlobalCopyState(pinia); + }, + tooltip: 'Serialize and copy the state', + }, + { + icon: 'content_paste', + action: async () => { + await actionGlobalPasteState(pinia); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }, + tooltip: 'Replace the state with the content of your clipboard', + }, + { + icon: 'save', + action: () => { + actionGlobalSaveState(pinia); + }, + tooltip: 'Save the state as a JSON file', + }, + { + icon: 'folder_open', + action: async () => { + await actionGlobalOpenStateFile(pinia); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }, + tooltip: 'Import the state from a JSON file', + }, + ], + nodeActions: [ + { + icon: 'restore', + tooltip: 'Reset the state (with "$reset")', + action: (nodeId) => { + const store = pinia._s.get(nodeId); + if (!store) { + toastMessage(`Cannot reset "${nodeId}" store because it wasn't found.`, 'warn'); + } + else if (typeof store.$reset !== 'function') { + toastMessage(`Cannot reset "${nodeId}" store because it doesn't have a "$reset" method implemented.`, 'warn'); + } + else { + store.$reset(); + toastMessage(`Store "${nodeId}" reset.`); + } + }, + }, + ], + }); + api.on.inspectComponent((payload, ctx) => { + const proxy = (payload.componentInstance && + payload.componentInstance.proxy); + if (proxy && proxy._pStores) { + const piniaStores = payload.componentInstance.proxy._pStores; + Object.values(piniaStores).forEach((store) => { + payload.instanceData.state.push({ + type: getStoreType(store.$id), + key: 'state', + editable: true, + value: store._isOptionsAPI + ? { + _custom: { + value: vueDemi.toRaw(store.$state), + actions: [ + { + icon: 'restore', + tooltip: 'Reset the state of this store', + action: () => store.$reset(), + }, + ], + }, + } + : // NOTE: workaround to unwrap transferred refs + Object.keys(store.$state).reduce((state, key) => { + state[key] = store.$state[key]; + return state; + }, {}), + }); + if (store._getters && store._getters.length) { + payload.instanceData.state.push({ + type: getStoreType(store.$id), + key: 'getters', + editable: false, + value: store._getters.reduce((getters, key) => { + try { + getters[key] = store[key]; + } + catch (error) { + // @ts-expect-error: we just want to show it in devtools + getters[key] = error; + } + return getters; + }, {}), + }); + } + }); + } + }); + api.on.getInspectorTree((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + let stores = [pinia]; + stores = stores.concat(Array.from(pinia._s.values())); + payload.rootNodes = (payload.filter + ? stores.filter((store) => '$id' in store + ? store.$id + .toLowerCase() + .includes(payload.filter.toLowerCase()) + : PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase())) + : stores).map(formatStoreForInspectorTree); + } + }); + api.on.getInspectorState((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const inspectedStore = payload.nodeId === PINIA_ROOT_ID + ? pinia + : pinia._s.get(payload.nodeId); + if (!inspectedStore) { + // this could be the selected store restored for a different project + // so it's better not to say anything here + return; + } + if (inspectedStore) { + payload.state = formatStoreForInspectorState(inspectedStore); + } + } + }); + api.on.editInspectorState((payload, ctx) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const inspectedStore = payload.nodeId === PINIA_ROOT_ID + ? pinia + : pinia._s.get(payload.nodeId); + if (!inspectedStore) { + return toastMessage(`store "${payload.nodeId}" not found`, 'error'); + } + const { path } = payload; + if (!isPinia(inspectedStore)) { + // access only the state + if (path.length !== 1 || + !inspectedStore._customProperties.has(path[0]) || + path[0] in inspectedStore.$state) { + path.unshift('$state'); + } + } + else { + // Root access, we can omit the `.value` because the devtools API does it for us + path.unshift('state'); + } + isTimelineActive = false; + payload.set(inspectedStore, path, payload.state.value); + isTimelineActive = true; + } + }); + api.on.editComponentState((payload) => { + if (payload.type.startsWith('🍍')) { + const storeId = payload.type.replace(/^🍍\s*/, ''); + const store = pinia._s.get(storeId); + if (!store) { + return toastMessage(`store "${storeId}" not found`, 'error'); + } + const { path } = payload; + if (path[0] !== 'state') { + return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`); + } + // rewrite the first entry to be able to directly set the state as + // well as any other path + path[0] = '$state'; + isTimelineActive = false; + payload.set(store, path, payload.state.value); + isTimelineActive = true; + } + }); + }); + } + function addStoreToDevtools(app, store) { + if (!componentStateTypes.includes(getStoreType(store.$id))) { + componentStateTypes.push(getStoreType(store.$id)); + } + setupDevtoolsPlugin({ + id: 'dev.esm.pinia', + label: 'Pinia 🍍', + logo: 'https://pinia.vuejs.org/logo.svg', + packageName: 'pinia', + homepage: 'https://pinia.vuejs.org', + componentStateTypes, + app, + settings: { + logStoreChanges: { + label: 'Notify about new/deleted stores', + type: 'boolean', + defaultValue: true, + }, + // useEmojis: { + // label: 'Use emojis in messages ⚡️', + // type: 'boolean', + // defaultValue: true, + // }, + }, + }, (api) => { + // gracefully handle errors + const now = typeof api.now === 'function' ? api.now.bind(api) : Date.now; + store.$onAction(({ after, onError, name, args }) => { + const groupId = runningActionId++; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🛫 ' + name, + subtitle: 'start', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + }, + groupId, + }, + }); + after((result) => { + activeAction = undefined; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🛬 ' + name, + subtitle: 'end', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + result, + }, + groupId, + }, + }); + }); + onError((error) => { + activeAction = undefined; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + logType: 'error', + title: '💥 ' + name, + subtitle: 'end', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + error, + }, + groupId, + }, + }); + }); + }, true); + store._customProperties.forEach((name) => { + vueDemi.watch(() => vueDemi.unref(store[name]), (newValue, oldValue) => { + api.notifyComponentUpdate(); + api.sendInspectorState(INSPECTOR_ID); + if (isTimelineActive) { + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: 'Change', + subtitle: name, + data: { + newValue, + oldValue, + }, + groupId: activeAction, + }, + }); + } + }, { deep: true }); + }); + store.$subscribe(({ events, type }, state) => { + api.notifyComponentUpdate(); + api.sendInspectorState(INSPECTOR_ID); + if (!isTimelineActive) + return; + // rootStore.state[store.id] = state + const eventData = { + time: now(), + title: formatMutationType(type), + data: assign$1({ store: formatDisplay(store.$id) }, formatEventData(events)), + groupId: activeAction, + }; + if (type === exports.MutationType.patchFunction) { + eventData.subtitle = '⤵️'; + } + else if (type === exports.MutationType.patchObject) { + eventData.subtitle = '🧩'; + } + else if (events && !Array.isArray(events)) { + eventData.subtitle = events.type; + } + if (events) { + eventData.data['rawEvent(s)'] = { + _custom: { + display: 'DebuggerEvent', + type: 'object', + tooltip: 'raw DebuggerEvent[]', + value: events, + }, + }; + } + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: eventData, + }); + }, { detached: true, flush: 'sync' }); + const hotUpdate = store._hotUpdate; + store._hotUpdate = vueDemi.markRaw((newStore) => { + hotUpdate(newStore); + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🔥 ' + store.$id, + subtitle: 'HMR update', + data: { + store: formatDisplay(store.$id), + info: formatDisplay(`HMR update`), + }, + }, + }); + // update the devtools too + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }); + const { $dispose } = store; + store.$dispose = () => { + $dispose(); + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + api.getSettings().logStoreChanges && + toastMessage(`Disposed "${store.$id}" store 🗑`); + }; + // trigger an update so it can display new registered stores + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + api.getSettings().logStoreChanges && + toastMessage(`"${store.$id}" store installed 🆕`); + }); + } + let runningActionId = 0; + let activeAction; + /** + * Patches a store to enable action grouping in devtools by wrapping the store with a Proxy that is passed as the + * context of all actions, allowing us to set `runningAction` on each access and effectively associating any state + * mutation to the action. + * + * @param store - store to patch + * @param actionNames - list of actionst to patch + */ + function patchActionForGrouping(store, actionNames, wrapWithProxy) { + // original actions of the store as they are given by pinia. We are going to override them + const actions = actionNames.reduce((storeActions, actionName) => { + // use toRaw to avoid tracking #541 + storeActions[actionName] = vueDemi.toRaw(store)[actionName]; + return storeActions; + }, {}); + for (const actionName in actions) { + store[actionName] = function () { + // the running action id is incremented in a before action hook + const _actionId = runningActionId; + const trackedStore = wrapWithProxy + ? new Proxy(store, { + get(...args) { + activeAction = _actionId; + return Reflect.get(...args); + }, + set(...args) { + activeAction = _actionId; + return Reflect.set(...args); + }, + }) + : store; + // For Setup Stores we need https://github.com/tc39/proposal-async-context + activeAction = _actionId; + const retValue = actions[actionName].apply(trackedStore, arguments); + // this is safer as async actions in Setup Stores would associate mutations done outside of the action + activeAction = undefined; + return retValue; + }; + } + } + /** + * pinia.use(devtoolsPlugin) + */ + function devtoolsPlugin({ app, store, options }) { + // HMR module + if (store.$id.startsWith('__hot:')) { + return; + } + // detect option api vs setup api + store._isOptionsAPI = !!options.state; + patchActionForGrouping(store, Object.keys(options.actions), store._isOptionsAPI); + // Upgrade the HMR to also update the new actions + const originalHotUpdate = store._hotUpdate; + vueDemi.toRaw(store)._hotUpdate = function (newStore) { + originalHotUpdate.apply(this, arguments); + patchActionForGrouping(store, Object.keys(newStore._hmrPayload.actions), !!store._isOptionsAPI); + }; + addStoreToDevtools(app, + // FIXME: is there a way to allow the assignment from Store to StoreGeneric? + store); + } + + /** + * Creates a Pinia instance to be used by the application + */ + function createPinia() { + const scope = vueDemi.effectScope(true); + // NOTE: here we could check the window object for a state and directly set it + // if there is anything like it with Vue 3 SSR + const state = scope.run(() => vueDemi.ref({})); + let _p = []; + // plugins added before calling app.use(pinia) + let toBeInstalled = []; + const pinia = vueDemi.markRaw({ + install(app) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + if (!vueDemi.isVue2) { + pinia._a = app; + app.provide(piniaSymbol, pinia); + app.config.globalProperties.$pinia = pinia; + /* istanbul ignore else */ + if (USE_DEVTOOLS) { + registerPiniaDevtools(app, pinia); + } + toBeInstalled.forEach((plugin) => _p.push(plugin)); + toBeInstalled = []; + } + }, + use(plugin) { + if (!this._a && !vueDemi.isVue2) { + toBeInstalled.push(plugin); + } + else { + _p.push(plugin); + } + return this; + }, + _p, + // it's actually undefined here + // @ts-expect-error + _a: null, + _e: scope, + _s: new Map(), + state, + }); + // pinia devtools rely on dev only features so they cannot be forced unless + // the dev build of Vue is used. Avoid old browsers like IE11. + if (USE_DEVTOOLS && typeof Proxy !== 'undefined') { + pinia.use(devtoolsPlugin); + } + return pinia; + } + + /** + * Checks if a function is a `StoreDefinition`. + * + * @param fn - object to test + * @returns true if `fn` is a StoreDefinition + */ + const isUseStore = (fn) => { + return typeof fn === 'function' && typeof fn.$id === 'string'; + }; + /** + * Mutates in place `newState` with `oldState` to _hot update_ it. It will + * remove any key not existing in `newState` and recursively merge plain + * objects. + * + * @param newState - new state object to be patched + * @param oldState - old state that should be used to patch newState + * @returns - newState + */ + function patchObject(newState, oldState) { + // no need to go through symbols because they cannot be serialized anyway + for (const key in oldState) { + const subPatch = oldState[key]; + // skip the whole sub tree + if (!(key in newState)) { + continue; + } + const targetValue = newState[key]; + if (isPlainObject(targetValue) && + isPlainObject(subPatch) && + !vueDemi.isRef(subPatch) && + !vueDemi.isReactive(subPatch)) { + newState[key] = patchObject(targetValue, subPatch); + } + else { + // objects are either a bit more complex (e.g. refs) or primitives, so we + // just set the whole thing + if (vueDemi.isVue2) { + vueDemi.set(newState, key, subPatch); + } + else { + newState[key] = subPatch; + } + } + } + return newState; + } + /** + * Creates an _accept_ function to pass to `import.meta.hot` in Vite applications. + * + * @example + * ```js + * const useUser = defineStore(...) + * if (import.meta.hot) { + * import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot)) + * } + * ``` + * + * @param initialUseStore - return of the defineStore to hot update + * @param hot - `import.meta.hot` + */ + function acceptHMRUpdate(initialUseStore, hot) { + return (newModule) => { + const pinia = hot.data.pinia || initialUseStore._pinia; + if (!pinia) { + // this store is still not used + return; + } + // preserve the pinia instance across loads + hot.data.pinia = pinia; + // console.log('got data', newStore) + for (const exportName in newModule) { + const useStore = newModule[exportName]; + // console.log('checking for', exportName) + if (isUseStore(useStore) && pinia._s.has(useStore.$id)) { + // console.log('Accepting update for', useStore.$id) + const id = useStore.$id; + if (id !== initialUseStore.$id) { + console.warn(`The id of the store changed from "${initialUseStore.$id}" to "${id}". Reloading.`); + // return import.meta.hot.invalidate() + return hot.invalidate(); + } + const existingStore = pinia._s.get(id); + if (!existingStore) { + console.log(`[Pinia]: skipping hmr because store doesn't exist yet`); + return; + } + useStore(pinia, existingStore); + } + } + }; + } + + const noop = () => { }; + function addSubscription(subscriptions, callback, detached, onCleanup = noop) { + subscriptions.push(callback); + const removeSubscription = () => { + const idx = subscriptions.indexOf(callback); + if (idx > -1) { + subscriptions.splice(idx, 1); + onCleanup(); + } + }; + if (!detached && vueDemi.getCurrentScope()) { + vueDemi.onScopeDispose(removeSubscription); + } + return removeSubscription; + } + function triggerSubscriptions(subscriptions, ...args) { + subscriptions.slice().forEach((callback) => { + callback(...args); + }); + } + + const fallbackRunWithContext = (fn) => fn(); + function mergeReactiveObjects(target, patchToApply) { + // Handle Map instances + if (target instanceof Map && patchToApply instanceof Map) { + patchToApply.forEach((value, key) => target.set(key, value)); + } + // Handle Set instances + if (target instanceof Set && patchToApply instanceof Set) { + patchToApply.forEach(target.add, target); + } + // no need to go through symbols because they cannot be serialized anyway + for (const key in patchToApply) { + if (!patchToApply.hasOwnProperty(key)) + continue; + const subPatch = patchToApply[key]; + const targetValue = target[key]; + if (isPlainObject(targetValue) && + isPlainObject(subPatch) && + target.hasOwnProperty(key) && + !vueDemi.isRef(subPatch) && + !vueDemi.isReactive(subPatch)) { + // NOTE: here I wanted to warn about inconsistent types but it's not possible because in setup stores one might + // start the value of a property as a certain type e.g. a Map, and then for some reason, during SSR, change that + // to `undefined`. When trying to hydrate, we want to override the Map with `undefined`. + target[key] = mergeReactiveObjects(targetValue, subPatch); + } + else { + // @ts-expect-error: subPatch is a valid value + target[key] = subPatch; + } + } + return target; + } + const skipHydrateSymbol = Symbol('pinia:skipHydration') + ; + const skipHydrateMap = /*#__PURE__*/ new WeakMap(); + /** + * Tells Pinia to skip the hydration process of a given object. This is useful in setup stores (only) when you return a + * stateful object in the store but it isn't really state. e.g. returning a router instance in a setup store. + * + * @param obj - target object + * @returns obj + */ + function skipHydrate(obj) { + return vueDemi.isVue2 + ? // in @vue/composition-api, the refs are sealed so defineProperty doesn't work... + /* istanbul ignore next */ skipHydrateMap.set(obj, 1) && obj + : Object.defineProperty(obj, skipHydrateSymbol, {}); + } + /** + * Returns whether a value should be hydrated + * + * @param obj - target variable + * @returns true if `obj` should be hydrated + */ + function shouldHydrate(obj) { + return vueDemi.isVue2 + ? /* istanbul ignore next */ !skipHydrateMap.has(obj) + : !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol); + } + const { assign } = Object; + function isComputed(o) { + return !!(vueDemi.isRef(o) && o.effect); + } + function createOptionsStore(id, options, pinia, hot) { + const { state, actions, getters } = options; + const initialState = pinia.state.value[id]; + let store; + function setup() { + if (!initialState && (!hot)) { + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(pinia.state.value, id, state ? state() : {}); + } + else { + pinia.state.value[id] = state ? state() : {}; + } + } + // avoid creating a state in pinia.state.value + const localState = hot + ? // use ref() to unwrap refs inside state TODO: check if this is still necessary + vueDemi.toRefs(vueDemi.ref(state ? state() : {}).value) + : vueDemi.toRefs(pinia.state.value[id]); + return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => { + if (name in localState) { + console.warn(`[🍍]: A getter cannot have the same name as another state property. Rename one of them. Found with "${name}" in store "${id}".`); + } + computedGetters[name] = vueDemi.markRaw(vueDemi.computed(() => { + setActivePinia(pinia); + // it was created just before + const store = pinia._s.get(id); + // allow cross using stores + /* istanbul ignore next */ + if (vueDemi.isVue2 && !store._r) + return; + // @ts-expect-error + // return getters![name].call(context, context) + // TODO: avoid reading the getter while assigning with a global variable + return getters[name].call(store, store); + })); + return computedGetters; + }, {})); + } + store = createSetupStore(id, setup, options, pinia, hot, true); + return store; + } + function createSetupStore($id, setup, options = {}, pinia, hot, isOptionsStore) { + let scope; + const optionsForPlugin = assign({ actions: {} }, options); + /* istanbul ignore if */ + if (!pinia._e.active) { + throw new Error('Pinia destroyed'); + } + // watcher options for $subscribe + const $subscribeOptions = { + deep: true, + // flush: 'post', + }; + /* istanbul ignore else */ + if (!vueDemi.isVue2) { + $subscribeOptions.onTrigger = (event) => { + /* istanbul ignore else */ + if (isListening) { + debuggerEvents = event; + // avoid triggering this while the store is being built and the state is being set in pinia + } + else if (isListening == false && !store._hotUpdating) { + // let patch send all the events together later + /* istanbul ignore else */ + if (Array.isArray(debuggerEvents)) { + debuggerEvents.push(event); + } + else { + console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.'); + } + } + }; + } + // internal state + let isListening; // set to true at the end + let isSyncListening; // set to true at the end + let subscriptions = []; + let actionSubscriptions = []; + let debuggerEvents; + const initialState = pinia.state.value[$id]; + // avoid setting the state for option stores if it is set + // by the setup + if (!isOptionsStore && !initialState && (!hot)) { + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(pinia.state.value, $id, {}); + } + else { + pinia.state.value[$id] = {}; + } + } + const hotState = vueDemi.ref({}); + // avoid triggering too many listeners + // https://github.com/vuejs/pinia/issues/1129 + let activeListener; + function $patch(partialStateOrMutator) { + let subscriptionMutation; + isListening = isSyncListening = false; + // reset the debugger events since patches are sync + /* istanbul ignore else */ + { + debuggerEvents = []; + } + if (typeof partialStateOrMutator === 'function') { + partialStateOrMutator(pinia.state.value[$id]); + subscriptionMutation = { + type: exports.MutationType.patchFunction, + storeId: $id, + events: debuggerEvents, + }; + } + else { + mergeReactiveObjects(pinia.state.value[$id], partialStateOrMutator); + subscriptionMutation = { + type: exports.MutationType.patchObject, + payload: partialStateOrMutator, + storeId: $id, + events: debuggerEvents, + }; + } + const myListenerId = (activeListener = Symbol()); + vueDemi.nextTick().then(() => { + if (activeListener === myListenerId) { + isListening = true; + } + }); + isSyncListening = true; + // because we paused the watcher, we need to manually call the subscriptions + triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]); + } + const $reset = isOptionsStore + ? function $reset() { + const { state } = options; + const newState = state ? state() : {}; + // we use a patch to group all changes into one single subscription + this.$patch(($state) => { + assign($state, newState); + }); + } + : /* istanbul ignore next */ + () => { + throw new Error(`🍍: Store "${$id}" is built using the setup syntax and does not implement $reset().`); + } + ; + function $dispose() { + scope.stop(); + subscriptions = []; + actionSubscriptions = []; + pinia._s.delete($id); + } + /** + * Wraps an action to handle subscriptions. + * + * @param name - name of the action + * @param action - action to wrap + * @returns a wrapped action to handle subscriptions + */ + function wrapAction(name, action) { + return function () { + setActivePinia(pinia); + const args = Array.from(arguments); + const afterCallbackList = []; + const onErrorCallbackList = []; + function after(callback) { + afterCallbackList.push(callback); + } + function onError(callback) { + onErrorCallbackList.push(callback); + } + // @ts-expect-error + triggerSubscriptions(actionSubscriptions, { + args, + name, + store, + after, + onError, + }); + let ret; + try { + ret = action.apply(this && this.$id === $id ? this : store, args); + // handle sync errors + } + catch (error) { + triggerSubscriptions(onErrorCallbackList, error); + throw error; + } + if (ret instanceof Promise) { + return ret + .then((value) => { + triggerSubscriptions(afterCallbackList, value); + return value; + }) + .catch((error) => { + triggerSubscriptions(onErrorCallbackList, error); + return Promise.reject(error); + }); + } + // trigger after callbacks + triggerSubscriptions(afterCallbackList, ret); + return ret; + }; + } + const _hmrPayload = /*#__PURE__*/ vueDemi.markRaw({ + actions: {}, + getters: {}, + state: [], + hotState, + }); + const partialStore = { + _p: pinia, + // _s: scope, + $id, + $onAction: addSubscription.bind(null, actionSubscriptions), + $patch, + $reset, + $subscribe(callback, options = {}) { + const removeSubscription = addSubscription(subscriptions, callback, options.detached, () => stopWatcher()); + const stopWatcher = scope.run(() => vueDemi.watch(() => pinia.state.value[$id], (state) => { + if (options.flush === 'sync' ? isSyncListening : isListening) { + callback({ + storeId: $id, + type: exports.MutationType.direct, + events: debuggerEvents, + }, state); + } + }, assign({}, $subscribeOptions, options))); + return removeSubscription; + }, + $dispose, + }; + /* istanbul ignore if */ + if (vueDemi.isVue2) { + // start as non ready + partialStore._r = false; + } + const store = vueDemi.reactive(assign({ + _hmrPayload, + _customProperties: vueDemi.markRaw(new Set()), // devtools custom properties + }, partialStore + // must be added later + // setupStore + ) + ); + // store the partial store now so the setup of stores can instantiate each other before they are finished without + // creating infinite loops. + pinia._s.set($id, store); + const runWithContext = (pinia._a && pinia._a.runWithContext) || fallbackRunWithContext; + // TODO: idea create skipSerialize that marks properties as non serializable and they are skipped + const setupStore = pinia._e.run(() => { + scope = vueDemi.effectScope(); + return runWithContext(() => scope.run(setup)); + }); + // overwrite existing actions to support $onAction + for (const key in setupStore) { + const prop = setupStore[key]; + if ((vueDemi.isRef(prop) && !isComputed(prop)) || vueDemi.isReactive(prop)) { + // mark it as a piece of state to be serialized + if (hot) { + vueDemi.set(hotState.value, key, vueDemi.toRef(setupStore, key)); + // createOptionStore directly sets the state in pinia.state.value so we + // can just skip that + } + else if (!isOptionsStore) { + // in setup stores we must hydrate the state and sync pinia state tree with the refs the user just created + if (initialState && shouldHydrate(prop)) { + if (vueDemi.isRef(prop)) { + prop.value = initialState[key]; + } + else { + // probably a reactive object, lets recursively assign + // @ts-expect-error: prop is unknown + mergeReactiveObjects(prop, initialState[key]); + } + } + // transfer the ref to the pinia state to keep everything in sync + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(pinia.state.value[$id], key, prop); + } + else { + pinia.state.value[$id][key] = prop; + } + } + /* istanbul ignore else */ + { + _hmrPayload.state.push(key); + } + // action + } + else if (typeof prop === 'function') { + // @ts-expect-error: we are overriding the function we avoid wrapping if + const actionValue = hot ? prop : wrapAction(key, prop); + // this a hot module replacement store because the hotUpdate method needs + // to do it with the right context + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(setupStore, key, actionValue); + } + else { + // @ts-expect-error + setupStore[key] = actionValue; + } + /* istanbul ignore else */ + { + _hmrPayload.actions[key] = prop; + } + // list actions so they can be used in plugins + // @ts-expect-error + optionsForPlugin.actions[key] = prop; + } + else { + // add getters for devtools + if (isComputed(prop)) { + _hmrPayload.getters[key] = isOptionsStore + ? // @ts-expect-error + options.getters[key] + : prop; + if (IS_CLIENT) { + const getters = setupStore._getters || + // @ts-expect-error: same + (setupStore._getters = vueDemi.markRaw([])); + getters.push(key); + } + } + } + } + // add the state, getters, and action properties + /* istanbul ignore if */ + if (vueDemi.isVue2) { + Object.keys(setupStore).forEach((key) => { + vueDemi.set(store, key, setupStore[key]); + }); + } + else { + assign(store, setupStore); + // allows retrieving reactive objects with `storeToRefs()`. Must be called after assigning to the reactive object. + // Make `storeToRefs()` work with `reactive()` #799 + assign(vueDemi.toRaw(store), setupStore); + } + // use this instead of a computed with setter to be able to create it anywhere + // without linking the computed lifespan to wherever the store is first + // created. + Object.defineProperty(store, '$state', { + get: () => (hot ? hotState.value : pinia.state.value[$id]), + set: (state) => { + /* istanbul ignore if */ + if (hot) { + throw new Error('cannot set hotState'); + } + $patch(($state) => { + assign($state, state); + }); + }, + }); + // add the hotUpdate before plugins to allow them to override it + /* istanbul ignore else */ + { + store._hotUpdate = vueDemi.markRaw((newStore) => { + store._hotUpdating = true; + newStore._hmrPayload.state.forEach((stateKey) => { + if (stateKey in store.$state) { + const newStateTarget = newStore.$state[stateKey]; + const oldStateSource = store.$state[stateKey]; + if (typeof newStateTarget === 'object' && + isPlainObject(newStateTarget) && + isPlainObject(oldStateSource)) { + patchObject(newStateTarget, oldStateSource); + } + else { + // transfer the ref + newStore.$state[stateKey] = oldStateSource; + } + } + // patch direct access properties to allow store.stateProperty to work as + // store.$state.stateProperty + vueDemi.set(store, stateKey, vueDemi.toRef(newStore.$state, stateKey)); + }); + // remove deleted state properties + Object.keys(store.$state).forEach((stateKey) => { + if (!(stateKey in newStore.$state)) { + vueDemi.del(store, stateKey); + } + }); + // avoid devtools logging this as a mutation + isListening = false; + isSyncListening = false; + pinia.state.value[$id] = vueDemi.toRef(newStore._hmrPayload, 'hotState'); + isSyncListening = true; + vueDemi.nextTick().then(() => { + isListening = true; + }); + for (const actionName in newStore._hmrPayload.actions) { + const action = newStore[actionName]; + vueDemi.set(store, actionName, wrapAction(actionName, action)); + } + // TODO: does this work in both setup and option store? + for (const getterName in newStore._hmrPayload.getters) { + const getter = newStore._hmrPayload.getters[getterName]; + const getterValue = isOptionsStore + ? // special handling of options api + vueDemi.computed(() => { + setActivePinia(pinia); + return getter.call(store, store); + }) + : getter; + vueDemi.set(store, getterName, getterValue); + } + // remove deleted getters + Object.keys(store._hmrPayload.getters).forEach((key) => { + if (!(key in newStore._hmrPayload.getters)) { + vueDemi.del(store, key); + } + }); + // remove old actions + Object.keys(store._hmrPayload.actions).forEach((key) => { + if (!(key in newStore._hmrPayload.actions)) { + vueDemi.del(store, key); + } + }); + // update the values used in devtools and to allow deleting new properties later on + store._hmrPayload = newStore._hmrPayload; + store._getters = newStore._getters; + store._hotUpdating = false; + }); + } + if (USE_DEVTOOLS) { + const nonEnumerable = { + writable: true, + configurable: true, + // avoid warning on devtools trying to display this property + enumerable: false, + }; + ['_p', '_hmrPayload', '_getters', '_customProperties'].forEach((p) => { + Object.defineProperty(store, p, assign({ value: store[p] }, nonEnumerable)); + }); + } + /* istanbul ignore if */ + if (vueDemi.isVue2) { + // mark the store as ready before plugins + store._r = true; + } + // apply all plugins + pinia._p.forEach((extender) => { + /* istanbul ignore else */ + if (USE_DEVTOOLS) { + const extensions = scope.run(() => extender({ + store, + app: pinia._a, + pinia, + options: optionsForPlugin, + })); + Object.keys(extensions || {}).forEach((key) => store._customProperties.add(key)); + assign(store, extensions); + } + else { + assign(store, scope.run(() => extender({ + store, + app: pinia._a, + pinia, + options: optionsForPlugin, + }))); + } + }); + if (store.$state && + typeof store.$state === 'object' && + typeof store.$state.constructor === 'function' && + !store.$state.constructor.toString().includes('[native code]')) { + console.warn(`[🍍]: The "state" must be a plain object. It cannot be\n` + + `\tstate: () => new MyClass()\n` + + `Found in store "${store.$id}".`); + } + // only apply hydrate to option stores with an initial state in pinia + if (initialState && + isOptionsStore && + options.hydrate) { + options.hydrate(store.$state, initialState); + } + isListening = true; + isSyncListening = true; + return store; + } + function defineStore( + // TODO: add proper types from above + idOrOptions, setup, setupOptions) { + let id; + let options; + const isSetupStore = typeof setup === 'function'; + if (typeof idOrOptions === 'string') { + id = idOrOptions; + // the option store setup will contain the actual options in this case + options = isSetupStore ? setupOptions : setup; + } + else { + options = idOrOptions; + id = idOrOptions.id; + if (typeof id !== 'string') { + throw new Error(`[🍍]: "defineStore()" must be passed a store id as its first argument.`); + } + } + function useStore(pinia, hot) { + const hasContext = vueDemi.hasInjectionContext(); + pinia = + // in test mode, ignore the argument provided as we can always retrieve a + // pinia instance with getActivePinia() + (pinia) || + (hasContext ? vueDemi.inject(piniaSymbol, null) : null); + if (pinia) + setActivePinia(pinia); + if (!activePinia) { + throw new Error(`[🍍]: "getActivePinia()" was called but there was no active Pinia. Did you forget to install pinia?\n` + + `\tconst pinia = createPinia()\n` + + `\tapp.use(pinia)\n` + + `This will fail in production.`); + } + pinia = activePinia; + if (!pinia._s.has(id)) { + // creating the store registers it in `pinia._s` + if (isSetupStore) { + createSetupStore(id, setup, options, pinia); + } + else { + createOptionsStore(id, options, pinia); + } + /* istanbul ignore else */ + { + // @ts-expect-error: not the right inferred type + useStore._pinia = pinia; + } + } + const store = pinia._s.get(id); + if (hot) { + const hotId = '__hot:' + id; + const newStore = isSetupStore + ? createSetupStore(hotId, setup, options, pinia, true) + : createOptionsStore(hotId, assign({}, options), pinia, true); + hot._hotUpdate(newStore); + // cleanup the state properties and the store from the cache + delete pinia.state.value[hotId]; + pinia._s.delete(hotId); + } + if (IS_CLIENT) { + const currentInstance = vueDemi.getCurrentInstance(); + // save stores in instances to access them devtools + if (currentInstance && + currentInstance.proxy && + // avoid adding stores that are just built for hot module replacement + !hot) { + const vm = currentInstance.proxy; + const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {}); + cache[id] = store; + } + } + // StoreGeneric cannot be casted towards Store + return store; + } + useStore.$id = id; + return useStore; + } + + let mapStoreSuffix = 'Store'; + /** + * Changes the suffix added by `mapStores()`. Can be set to an empty string. + * Defaults to `"Store"`. Make sure to extend the MapStoresCustomization + * interface if you are using TypeScript. + * + * @param suffix - new suffix + */ + function setMapStoreSuffix(suffix // could be 'Store' but that would be annoying for JS + ) { + mapStoreSuffix = suffix; + } + /** + * Allows using stores without the composition API (`setup()`) by generating an + * object to be spread in the `computed` field of a component. It accepts a list + * of store definitions. + * + * @example + * ```js + * export default { + * computed: { + * // other computed properties + * ...mapStores(useUserStore, useCartStore) + * }, + * + * created() { + * this.userStore // store with id "user" + * this.cartStore // store with id "cart" + * } + * } + * ``` + * + * @param stores - list of stores to map to an object + */ + function mapStores(...stores) { + if (Array.isArray(stores[0])) { + console.warn(`[🍍]: Directly pass all stores to "mapStores()" without putting them in an array:\n` + + `Replace\n` + + `\tmapStores([useAuthStore, useCartStore])\n` + + `with\n` + + `\tmapStores(useAuthStore, useCartStore)\n` + + `This will fail in production if not fixed.`); + stores = stores[0]; + } + return stores.reduce((reduced, useStore) => { + // @ts-expect-error: $id is added by defineStore + reduced[useStore.$id + mapStoreSuffix] = function () { + return useStore(this.$pinia); + }; + return reduced; + }, {}); + } + /** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ + function mapState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + reduced[key] = function () { + return useStore(this.$pinia)[key]; + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function () { + const store = useStore(this.$pinia); + const storeKey = keysOrMapper[key]; + // for some reason TS is unable to infer the type of storeKey to be a + // function + return typeof storeKey === 'function' + ? storeKey.call(this, store) + : store[storeKey]; + }; + return reduced; + }, {}); + } + /** + * Alias for `mapState()`. You should use `mapState()` instead. + * @deprecated use `mapState()` instead. + */ + const mapGetters = mapState; + /** + * Allows directly using actions from your store without using the composition + * API (`setup()`) by generating an object to be spread in the `methods` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ + function mapActions(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[key](...args); + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[keysOrMapper[key]](...args); + }; + return reduced; + }, {}); + } + /** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ + function mapWritableState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[key]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[key] = value); + }, + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[keysOrMapper[key]]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[keysOrMapper[key]] = value); + }, + }; + return reduced; + }, {}); + } + + /** + * Creates an object of references with all the state, getters, and plugin-added + * state properties of the store. Similar to `toRefs()` but specifically + * designed for Pinia stores so methods and non reactive properties are + * completely ignored. + * + * @param store - store to extract the refs from + */ + function storeToRefs(store) { + // See https://github.com/vuejs/pinia/issues/852 + // It's easier to just use toRefs() even if it includes more stuff + if (vueDemi.isVue2) { + // @ts-expect-error: toRefs include methods and others + return vueDemi.toRefs(store); + } + else { + store = vueDemi.toRaw(store); + const refs = {}; + for (const key in store) { + const value = store[key]; + if (vueDemi.isRef(value) || vueDemi.isReactive(value)) { + // @ts-expect-error: the key is state or getter + refs[key] = + // --- + vueDemi.toRef(store, key); + } + } + return refs; + } + } + + /** + * Vue 2 Plugin that must be installed for pinia to work. Note **you don't need + * this plugin if you are using Nuxt.js**. Use the `buildModule` instead: + * https://pinia.vuejs.org/ssr/nuxt.html. + * + * @example + * ```js + * import Vue from 'vue' + * import { PiniaVuePlugin, createPinia } from 'pinia' + * + * Vue.use(PiniaVuePlugin) + * const pinia = createPinia() + * + * new Vue({ + * el: '#app', + * // ... + * pinia, + * }) + * ``` + * + * @param _Vue - `Vue` imported from 'vue'. + */ + const PiniaVuePlugin = function (_Vue) { + // Equivalent of + // app.config.globalProperties.$pinia = pinia + _Vue.mixin({ + beforeCreate() { + const options = this.$options; + if (options.pinia) { + const pinia = options.pinia; + // HACK: taken from provide(): https://github.com/vuejs/composition-api/blob/main/src/apis/inject.ts#L31 + /* istanbul ignore else */ + if (!this._provided) { + const provideCache = {}; + Object.defineProperty(this, '_provided', { + get: () => provideCache, + set: (v) => Object.assign(provideCache, v), + }); + } + this._provided[piniaSymbol] = pinia; + // propagate the pinia instance in an SSR friendly way + // avoid adding it to nuxt twice + /* istanbul ignore else */ + if (!this.$pinia) { + this.$pinia = pinia; + } + pinia._a = this; + if (IS_CLIENT) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + } + if (USE_DEVTOOLS) { + registerPiniaDevtools(pinia._a, pinia); + } + } + else if (!this.$pinia && options.parent && options.parent.$pinia) { + this.$pinia = options.parent.$pinia; + } + }, + destroyed() { + delete this._pStores; + }, + }); + }; + + exports.PiniaVuePlugin = PiniaVuePlugin; + exports.acceptHMRUpdate = acceptHMRUpdate; + exports.createPinia = createPinia; + exports.defineStore = defineStore; + exports.getActivePinia = getActivePinia; + exports.mapActions = mapActions; + exports.mapGetters = mapGetters; + exports.mapState = mapState; + exports.mapStores = mapStores; + exports.mapWritableState = mapWritableState; + exports.setActivePinia = setActivePinia; + exports.setMapStoreSuffix = setMapStoreSuffix; + exports.skipHydrate = skipHydrate; + exports.storeToRefs = storeToRefs; + + return exports; + +})({}, VueDemi); diff --git a/node_modules/pinia/dist/pinia.iife.prod.js b/node_modules/pinia/dist/pinia.iife.prod.js new file mode 100644 index 0000000..bee640a --- /dev/null +++ b/node_modules/pinia/dist/pinia.iife.prod.js @@ -0,0 +1,6 @@ +/*! + * pinia v2.1.6 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */ +var Pinia=function(t,e){"use strict";let n;const i=t=>n=t,s=Symbol();function o(t){return t&&"object"==typeof t&&"[object Object]"===Object.prototype.toString.call(t)&&"function"!=typeof t.toJSON}var r;t.MutationType=void 0,(r=t.MutationType||(t.MutationType={})).direct="direct",r.patchObject="patch object",r.patchFunction="patch function";const c="undefined"!=typeof window;const a=()=>{};function u(t,n,i,s=a){t.push(n);const o=()=>{const e=t.indexOf(n);e>-1&&(t.splice(e,1),s())};return!i&&e.getCurrentScope()&&e.onScopeDispose(o),o}function p(t,...e){t.slice().forEach((t=>{t(...e)}))}const f=t=>t();function h(t,n){t instanceof Map&&n instanceof Map&&n.forEach(((e,n)=>t.set(n,e))),t instanceof Set&&n instanceof Set&&n.forEach(t.add,t);for(const i in n){if(!n.hasOwnProperty(i))continue;const s=n[i],r=t[i];t[i]=o(r)&&o(s)&&t.hasOwnProperty(i)&&!e.isRef(s)&&!e.isReactive(s)?h(r,s):s}return t}const l=Symbol(),d=new WeakMap;const{assign:y}=Object;function v(n,s,r={},c,v,$){let b;const _=y({actions:{}},r),j={deep:!0};let O,S,g,m=[],R=[];const P=c.state.value[n];let V;function w(i){let s;O=S=!1,"function"==typeof i?(i(c.state.value[n]),s={type:t.MutationType.patchFunction,storeId:n,events:g}):(h(c.state.value[n],i),s={type:t.MutationType.patchObject,payload:i,storeId:n,events:g});const o=V=Symbol();e.nextTick().then((()=>{V===o&&(O=!0)})),S=!0,p(m,s,c.state.value[n])}$||P||(e.isVue2?e.set(c.state.value,n,{}):c.state.value[n]={}),e.ref({});const M=$?function(){const{state:t}=r,e=t?t():{};this.$patch((t=>{y(t,e)}))}:a;function A(t,e){return function(){i(c);const s=Array.from(arguments),o=[],r=[];let a;p(R,{args:s,name:t,store:T,after:function(t){o.push(t)},onError:function(t){r.push(t)}});try{a=e.apply(this&&this.$id===n?this:T,s)}catch(t){throw p(r,t),t}return a instanceof Promise?a.then((t=>(p(o,t),t))).catch((t=>(p(r,t),Promise.reject(t)))):(p(o,a),a)}}const k={_p:c,$id:n,$onAction:u.bind(null,R),$patch:w,$reset:M,$subscribe(i,s={}){const o=u(m,i,s.detached,(()=>r())),r=b.run((()=>e.watch((()=>c.state.value[n]),(e=>{("sync"===s.flush?S:O)&&i({storeId:n,type:t.MutationType.direct,events:g},e)}),y({},j,s))));return o},$dispose:function(){b.stop(),m=[],R=[],c._s.delete(n)}};e.isVue2&&(k._r=!1);const T=e.reactive(k);c._s.set(n,T);const x=c._a&&c._a.runWithContext||f,E=c._e.run((()=>(b=e.effectScope(),x((()=>b.run(s))))));for(const t in E){const i=E[t];if(e.isRef(i)&&(!e.isRef(I=i)||!I.effect)||e.isReactive(i))$||(!P||(C=i,e.isVue2?d.has(C):o(C)&&C.hasOwnProperty(l))||(e.isRef(i)?i.value=P[t]:h(i,P[t])),e.isVue2?e.set(c.state.value[n],t,i):c.state.value[n][t]=i);else if("function"==typeof i){const n=A(t,i);e.isVue2?e.set(E,t,n):E[t]=n,_.actions[t]=i}}var C,I;return e.isVue2?Object.keys(E).forEach((t=>{e.set(T,t,E[t])})):(y(T,E),y(e.toRaw(T),E)),Object.defineProperty(T,"$state",{get:()=>c.state.value[n],set:t=>{w((e=>{y(e,t)}))}}),e.isVue2&&(T._r=!0),c._p.forEach((t=>{y(T,b.run((()=>t({store:T,app:c._a,pinia:c,options:_}))))})),P&&$&&r.hydrate&&r.hydrate(T.$state,P),O=!0,S=!0,T}let $="Store";function b(t,e){return Array.isArray(e)?e.reduce(((e,n)=>(e[n]=function(){return t(this.$pinia)[n]},e)),{}):Object.keys(e).reduce(((n,i)=>(n[i]=function(){const n=t(this.$pinia),s=e[i];return"function"==typeof s?s.call(this,n):n[s]},n)),{})}const _=b;return t.PiniaVuePlugin=function(t){t.mixin({beforeCreate(){const t=this.$options;if(t.pinia){const e=t.pinia;if(!this._provided){const t={};Object.defineProperty(this,"_provided",{get:()=>t,set:e=>Object.assign(t,e)})}this._provided[s]=e,this.$pinia||(this.$pinia=e),e._a=this,c&&i(e)}else!this.$pinia&&t.parent&&t.parent.$pinia&&(this.$pinia=t.parent.$pinia)},destroyed(){delete this._pStores}})},t.acceptHMRUpdate=function(t,e){return()=>{}},t.createPinia=function(){const t=e.effectScope(!0),n=t.run((()=>e.ref({})));let o=[],r=[];const c=e.markRaw({install(t){i(c),e.isVue2||(c._a=t,t.provide(s,c),t.config.globalProperties.$pinia=c,r.forEach((t=>o.push(t))),r=[])},use(t){return this._a||e.isVue2?o.push(t):r.push(t),this},_p:o,_a:null,_e:t,_s:new Map,state:n});return c},t.defineStore=function(t,o,r){let c,a;const u="function"==typeof o;function p(t,r){const p=e.hasInjectionContext();(t=t||(p?e.inject(s,null):null))&&i(t),(t=n)._s.has(c)||(u?v(c,o,a,t):function(t,n,s,o){const{state:r,actions:c,getters:a}=n,u=s.state.value[t];let p;p=v(t,(function(){u||(e.isVue2?e.set(s.state.value,t,r?r():{}):s.state.value[t]=r?r():{});const n=e.toRefs(s.state.value[t]);return y(n,c,Object.keys(a||{}).reduce(((n,o)=>(n[o]=e.markRaw(e.computed((()=>{i(s);const n=s._s.get(t);if(!e.isVue2||n._r)return a[o].call(n,n)}))),n)),{}))}),n,s,0,!0)}(c,a,t));return t._s.get(c)}return"string"==typeof t?(c=t,a=u?r:o):(a=t,c=t.id),p.$id=c,p},t.getActivePinia=()=>e.hasInjectionContext()&&e.inject(s)||n,t.mapActions=function(t,e){return Array.isArray(e)?e.reduce(((e,n)=>(e[n]=function(...e){return t(this.$pinia)[n](...e)},e)),{}):Object.keys(e).reduce(((n,i)=>(n[i]=function(...n){return t(this.$pinia)[e[i]](...n)},n)),{})},t.mapGetters=_,t.mapState=b,t.mapStores=function(...t){return t.reduce(((t,e)=>(t[e.$id+$]=function(){return e(this.$pinia)},t)),{})},t.mapWritableState=function(t,e){return Array.isArray(e)?e.reduce(((e,n)=>(e[n]={get(){return t(this.$pinia)[n]},set(e){return t(this.$pinia)[n]=e}},e)),{}):Object.keys(e).reduce(((n,i)=>(n[i]={get(){return t(this.$pinia)[e[i]]},set(n){return t(this.$pinia)[e[i]]=n}},n)),{})},t.setActivePinia=i,t.setMapStoreSuffix=function(t){$=t},t.skipHydrate=function(t){return e.isVue2?d.set(t,1)&&t:Object.defineProperty(t,l,{})},t.storeToRefs=function(t){if(e.isVue2)return e.toRefs(t);{t=e.toRaw(t);const n={};for(const i in t){const s=t[i];(e.isRef(s)||e.isReactive(s))&&(n[i]=e.toRef(t,i))}return n}},t}({},VueDemi); diff --git a/node_modules/pinia/dist/pinia.mjs b/node_modules/pinia/dist/pinia.mjs new file mode 100644 index 0000000..4b52ecd --- /dev/null +++ b/node_modules/pinia/dist/pinia.mjs @@ -0,0 +1,2004 @@ +/*! + * pinia v2.1.6 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */ +import { hasInjectionContext, inject, toRaw, watch, unref, markRaw, effectScope, ref, isVue2, isRef, isReactive, set, getCurrentScope, onScopeDispose, getCurrentInstance, reactive, toRef, del, nextTick, computed, toRefs } from 'vue-demi'; +import { setupDevtoolsPlugin } from '@vue/devtools-api'; + +/** + * setActivePinia must be called to handle SSR at the top of functions like + * `fetch`, `setup`, `serverPrefetch` and others + */ +let activePinia; +/** + * Sets or unsets the active pinia. Used in SSR and internally when calling + * actions and getters + * + * @param pinia - Pinia instance + */ +// @ts-expect-error: cannot constrain the type of the return +const setActivePinia = (pinia) => (activePinia = pinia); +/** + * Get the currently active pinia if there is any. + */ +const getActivePinia = () => (hasInjectionContext() && inject(piniaSymbol)) || activePinia; +const piniaSymbol = ((process.env.NODE_ENV !== 'production') ? Symbol('pinia') : /* istanbul ignore next */ Symbol()); + +function isPlainObject( +// eslint-disable-next-line @typescript-eslint/no-explicit-any +o) { + return (o && + typeof o === 'object' && + Object.prototype.toString.call(o) === '[object Object]' && + typeof o.toJSON !== 'function'); +} +// type DeepReadonly = { readonly [P in keyof T]: DeepReadonly } +// TODO: can we change these to numbers? +/** + * Possible types for SubscriptionCallback + */ +var MutationType; +(function (MutationType) { + /** + * Direct mutation of the state: + * + * - `store.name = 'new name'` + * - `store.$state.name = 'new name'` + * - `store.list.push('new item')` + */ + MutationType["direct"] = "direct"; + /** + * Mutated the state with `$patch` and an object + * + * - `store.$patch({ name: 'newName' })` + */ + MutationType["patchObject"] = "patch object"; + /** + * Mutated the state with `$patch` and a function + * + * - `store.$patch(state => state.name = 'newName')` + */ + MutationType["patchFunction"] = "patch function"; + // maybe reset? for $state = {} and $reset +})(MutationType || (MutationType = {})); + +const IS_CLIENT = typeof window !== 'undefined'; +/** + * Should we add the devtools plugins. + * - only if dev mode or forced through the prod devtools flag + * - not in test + * - only if window exists (could change in the future) + */ +const USE_DEVTOOLS = ((process.env.NODE_ENV !== 'production') || (typeof __VUE_PROD_DEVTOOLS__ !== 'undefined' && __VUE_PROD_DEVTOOLS__)) && !(process.env.NODE_ENV === 'test') && IS_CLIENT; + +/* + * FileSaver.js A saveAs() FileSaver implementation. + * + * Originally by Eli Grey, adapted as an ESM module by Eduardo San Martin + * Morote. + * + * License : MIT + */ +// The one and only way of getting global scope in all environments +// https://stackoverflow.com/q/3277182/1008999 +const _global = /*#__PURE__*/ (() => typeof window === 'object' && window.window === window + ? window + : typeof self === 'object' && self.self === self + ? self + : typeof global === 'object' && global.global === global + ? global + : typeof globalThis === 'object' + ? globalThis + : { HTMLElement: null })(); +function bom(blob, { autoBom = false } = {}) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if (autoBom && + /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xfeff), blob], { type: blob.type }); + } + return blob; +} +function download(url, name, opts) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'blob'; + xhr.onload = function () { + saveAs(xhr.response, name, opts); + }; + xhr.onerror = function () { + console.error('could not download file'); + }; + xhr.send(); +} +function corsEnabled(url) { + const xhr = new XMLHttpRequest(); + // use sync to avoid popup blocker + xhr.open('HEAD', url, false); + try { + xhr.send(); + } + catch (e) { } + return xhr.status >= 200 && xhr.status <= 299; +} +// `a.click()` doesn't work for all browsers (#465) +function click(node) { + try { + node.dispatchEvent(new MouseEvent('click')); + } + catch (e) { + const evt = document.createEvent('MouseEvents'); + evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); + node.dispatchEvent(evt); + } +} +const _navigator = + typeof navigator === 'object' ? navigator : { userAgent: '' }; +// Detect WebView inside a native macOS app by ruling out all browsers +// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too +// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos +const isMacOSWebView = /*#__PURE__*/ (() => /Macintosh/.test(_navigator.userAgent) && + /AppleWebKit/.test(_navigator.userAgent) && + !/Safari/.test(_navigator.userAgent))(); +const saveAs = !IS_CLIENT + ? () => { } // noop + : // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView or mini program + typeof HTMLAnchorElement !== 'undefined' && + 'download' in HTMLAnchorElement.prototype && + !isMacOSWebView + ? downloadSaveAs + : // Use msSaveOrOpenBlob as a second approach + 'msSaveOrOpenBlob' in _navigator + ? msSaveAs + : // Fallback to using FileReader and a popup + fileSaverSaveAs; +function downloadSaveAs(blob, name = 'download', opts) { + const a = document.createElement('a'); + a.download = name; + a.rel = 'noopener'; // tabnabbing + // TODO: detect chrome extensions & packaged apps + // a.target = '_blank' + if (typeof blob === 'string') { + // Support regular links + a.href = blob; + if (a.origin !== location.origin) { + if (corsEnabled(a.href)) { + download(blob, name, opts); + } + else { + a.target = '_blank'; + click(a); + } + } + else { + click(a); + } + } + else { + // Support blobs + a.href = URL.createObjectURL(blob); + setTimeout(function () { + URL.revokeObjectURL(a.href); + }, 4e4); // 40s + setTimeout(function () { + click(a); + }, 0); + } +} +function msSaveAs(blob, name = 'download', opts) { + if (typeof blob === 'string') { + if (corsEnabled(blob)) { + download(blob, name, opts); + } + else { + const a = document.createElement('a'); + a.href = blob; + a.target = '_blank'; + setTimeout(function () { + click(a); + }); + } + } + else { + // @ts-ignore: works on windows + navigator.msSaveOrOpenBlob(bom(blob, opts), name); + } +} +function fileSaverSaveAs(blob, name, opts, popup) { + // Open a popup immediately do go around popup blocker + // Mostly only available on user interaction and the fileReader is async so... + popup = popup || open('', '_blank'); + if (popup) { + popup.document.title = popup.document.body.innerText = 'downloading...'; + } + if (typeof blob === 'string') + return download(blob, name, opts); + const force = blob.type === 'application/octet-stream'; + const isSafari = /constructor/i.test(String(_global.HTMLElement)) || 'safari' in _global; + const isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); + if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && + typeof FileReader !== 'undefined') { + // Safari doesn't allow downloading of blob URLs + const reader = new FileReader(); + reader.onloadend = function () { + let url = reader.result; + if (typeof url !== 'string') { + popup = null; + throw new Error('Wrong reader.result type'); + } + url = isChromeIOS + ? url + : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); + if (popup) { + popup.location.href = url; + } + else { + location.assign(url); + } + popup = null; // reverse-tabnabbing #460 + }; + reader.readAsDataURL(blob); + } + else { + const url = URL.createObjectURL(blob); + if (popup) + popup.location.assign(url); + else + location.href = url; + popup = null; // reverse-tabnabbing #460 + setTimeout(function () { + URL.revokeObjectURL(url); + }, 4e4); // 40s + } +} + +/** + * Shows a toast or console.log + * + * @param message - message to log + * @param type - different color of the tooltip + */ +function toastMessage(message, type) { + const piniaMessage = '🍍 ' + message; + if (typeof __VUE_DEVTOOLS_TOAST__ === 'function') { + // No longer available :( + __VUE_DEVTOOLS_TOAST__(piniaMessage, type); + } + else if (type === 'error') { + console.error(piniaMessage); + } + else if (type === 'warn') { + console.warn(piniaMessage); + } + else { + console.log(piniaMessage); + } +} +function isPinia(o) { + return '_a' in o && 'install' in o; +} + +/** + * This file contain devtools actions, they are not Pinia actions. + */ +// --- +function checkClipboardAccess() { + if (!('clipboard' in navigator)) { + toastMessage(`Your browser doesn't support the Clipboard API`, 'error'); + return true; + } +} +function checkNotFocusedError(error) { + if (error instanceof Error && + error.message.toLowerCase().includes('document is not focused')) { + toastMessage('You need to activate the "Emulate a focused page" setting in the "Rendering" panel of devtools.', 'warn'); + return true; + } + return false; +} +async function actionGlobalCopyState(pinia) { + if (checkClipboardAccess()) + return; + try { + await navigator.clipboard.writeText(JSON.stringify(pinia.state.value)); + toastMessage('Global state copied to clipboard.'); + } + catch (error) { + if (checkNotFocusedError(error)) + return; + toastMessage(`Failed to serialize the state. Check the console for more details.`, 'error'); + console.error(error); + } +} +async function actionGlobalPasteState(pinia) { + if (checkClipboardAccess()) + return; + try { + loadStoresState(pinia, JSON.parse(await navigator.clipboard.readText())); + toastMessage('Global state pasted from clipboard.'); + } + catch (error) { + if (checkNotFocusedError(error)) + return; + toastMessage(`Failed to deserialize the state from clipboard. Check the console for more details.`, 'error'); + console.error(error); + } +} +async function actionGlobalSaveState(pinia) { + try { + saveAs(new Blob([JSON.stringify(pinia.state.value)], { + type: 'text/plain;charset=utf-8', + }), 'pinia-state.json'); + } + catch (error) { + toastMessage(`Failed to export the state as JSON. Check the console for more details.`, 'error'); + console.error(error); + } +} +let fileInput; +function getFileOpener() { + if (!fileInput) { + fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = '.json'; + } + function openFile() { + return new Promise((resolve, reject) => { + fileInput.onchange = async () => { + const files = fileInput.files; + if (!files) + return resolve(null); + const file = files.item(0); + if (!file) + return resolve(null); + return resolve({ text: await file.text(), file }); + }; + // @ts-ignore: TODO: changed from 4.3 to 4.4 + fileInput.oncancel = () => resolve(null); + fileInput.onerror = reject; + fileInput.click(); + }); + } + return openFile; +} +async function actionGlobalOpenStateFile(pinia) { + try { + const open = getFileOpener(); + const result = await open(); + if (!result) + return; + const { text, file } = result; + loadStoresState(pinia, JSON.parse(text)); + toastMessage(`Global state imported from "${file.name}".`); + } + catch (error) { + toastMessage(`Failed to import the state from JSON. Check the console for more details.`, 'error'); + console.error(error); + } +} +function loadStoresState(pinia, state) { + for (const key in state) { + const storeState = pinia.state.value[key]; + if (storeState) { + Object.assign(storeState, state[key]); + } + } +} + +function formatDisplay(display) { + return { + _custom: { + display, + }, + }; +} +const PINIA_ROOT_LABEL = '🍍 Pinia (root)'; +const PINIA_ROOT_ID = '_root'; +function formatStoreForInspectorTree(store) { + return isPinia(store) + ? { + id: PINIA_ROOT_ID, + label: PINIA_ROOT_LABEL, + } + : { + id: store.$id, + label: store.$id, + }; +} +function formatStoreForInspectorState(store) { + if (isPinia(store)) { + const storeNames = Array.from(store._s.keys()); + const storeMap = store._s; + const state = { + state: storeNames.map((storeId) => ({ + editable: true, + key: storeId, + value: store.state.value[storeId], + })), + getters: storeNames + .filter((id) => storeMap.get(id)._getters) + .map((id) => { + const store = storeMap.get(id); + return { + editable: false, + key: id, + value: store._getters.reduce((getters, key) => { + getters[key] = store[key]; + return getters; + }, {}), + }; + }), + }; + return state; + } + const state = { + state: Object.keys(store.$state).map((key) => ({ + editable: true, + key, + value: store.$state[key], + })), + }; + // avoid adding empty getters + if (store._getters && store._getters.length) { + state.getters = store._getters.map((getterName) => ({ + editable: false, + key: getterName, + value: store[getterName], + })); + } + if (store._customProperties.size) { + state.customProperties = Array.from(store._customProperties).map((key) => ({ + editable: true, + key, + value: store[key], + })); + } + return state; +} +function formatEventData(events) { + if (!events) + return {}; + if (Array.isArray(events)) { + // TODO: handle add and delete for arrays and objects + return events.reduce((data, event) => { + data.keys.push(event.key); + data.operations.push(event.type); + data.oldValue[event.key] = event.oldValue; + data.newValue[event.key] = event.newValue; + return data; + }, { + oldValue: {}, + keys: [], + operations: [], + newValue: {}, + }); + } + else { + return { + operation: formatDisplay(events.type), + key: formatDisplay(events.key), + oldValue: events.oldValue, + newValue: events.newValue, + }; + } +} +function formatMutationType(type) { + switch (type) { + case MutationType.direct: + return 'mutation'; + case MutationType.patchFunction: + return '$patch'; + case MutationType.patchObject: + return '$patch'; + default: + return 'unknown'; + } +} + +// timeline can be paused when directly changing the state +let isTimelineActive = true; +const componentStateTypes = []; +const MUTATIONS_LAYER_ID = 'pinia:mutations'; +const INSPECTOR_ID = 'pinia'; +const { assign: assign$1 } = Object; +/** + * Gets the displayed name of a store in devtools + * + * @param id - id of the store + * @returns a formatted string + */ +const getStoreType = (id) => '🍍 ' + id; +/** + * Add the pinia plugin without any store. Allows displaying a Pinia plugin tab + * as soon as it is added to the application. + * + * @param app - Vue application + * @param pinia - pinia instance + */ +function registerPiniaDevtools(app, pinia) { + setupDevtoolsPlugin({ + id: 'dev.esm.pinia', + label: 'Pinia 🍍', + logo: 'https://pinia.vuejs.org/logo.svg', + packageName: 'pinia', + homepage: 'https://pinia.vuejs.org', + componentStateTypes, + app, + }, (api) => { + if (typeof api.now !== 'function') { + toastMessage('You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html.'); + } + api.addTimelineLayer({ + id: MUTATIONS_LAYER_ID, + label: `Pinia 🍍`, + color: 0xe5df88, + }); + api.addInspector({ + id: INSPECTOR_ID, + label: 'Pinia 🍍', + icon: 'storage', + treeFilterPlaceholder: 'Search stores', + actions: [ + { + icon: 'content_copy', + action: () => { + actionGlobalCopyState(pinia); + }, + tooltip: 'Serialize and copy the state', + }, + { + icon: 'content_paste', + action: async () => { + await actionGlobalPasteState(pinia); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }, + tooltip: 'Replace the state with the content of your clipboard', + }, + { + icon: 'save', + action: () => { + actionGlobalSaveState(pinia); + }, + tooltip: 'Save the state as a JSON file', + }, + { + icon: 'folder_open', + action: async () => { + await actionGlobalOpenStateFile(pinia); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }, + tooltip: 'Import the state from a JSON file', + }, + ], + nodeActions: [ + { + icon: 'restore', + tooltip: 'Reset the state (with "$reset")', + action: (nodeId) => { + const store = pinia._s.get(nodeId); + if (!store) { + toastMessage(`Cannot reset "${nodeId}" store because it wasn't found.`, 'warn'); + } + else if (typeof store.$reset !== 'function') { + toastMessage(`Cannot reset "${nodeId}" store because it doesn't have a "$reset" method implemented.`, 'warn'); + } + else { + store.$reset(); + toastMessage(`Store "${nodeId}" reset.`); + } + }, + }, + ], + }); + api.on.inspectComponent((payload, ctx) => { + const proxy = (payload.componentInstance && + payload.componentInstance.proxy); + if (proxy && proxy._pStores) { + const piniaStores = payload.componentInstance.proxy._pStores; + Object.values(piniaStores).forEach((store) => { + payload.instanceData.state.push({ + type: getStoreType(store.$id), + key: 'state', + editable: true, + value: store._isOptionsAPI + ? { + _custom: { + value: toRaw(store.$state), + actions: [ + { + icon: 'restore', + tooltip: 'Reset the state of this store', + action: () => store.$reset(), + }, + ], + }, + } + : // NOTE: workaround to unwrap transferred refs + Object.keys(store.$state).reduce((state, key) => { + state[key] = store.$state[key]; + return state; + }, {}), + }); + if (store._getters && store._getters.length) { + payload.instanceData.state.push({ + type: getStoreType(store.$id), + key: 'getters', + editable: false, + value: store._getters.reduce((getters, key) => { + try { + getters[key] = store[key]; + } + catch (error) { + // @ts-expect-error: we just want to show it in devtools + getters[key] = error; + } + return getters; + }, {}), + }); + } + }); + } + }); + api.on.getInspectorTree((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + let stores = [pinia]; + stores = stores.concat(Array.from(pinia._s.values())); + payload.rootNodes = (payload.filter + ? stores.filter((store) => '$id' in store + ? store.$id + .toLowerCase() + .includes(payload.filter.toLowerCase()) + : PINIA_ROOT_LABEL.toLowerCase().includes(payload.filter.toLowerCase())) + : stores).map(formatStoreForInspectorTree); + } + }); + api.on.getInspectorState((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const inspectedStore = payload.nodeId === PINIA_ROOT_ID + ? pinia + : pinia._s.get(payload.nodeId); + if (!inspectedStore) { + // this could be the selected store restored for a different project + // so it's better not to say anything here + return; + } + if (inspectedStore) { + payload.state = formatStoreForInspectorState(inspectedStore); + } + } + }); + api.on.editInspectorState((payload, ctx) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const inspectedStore = payload.nodeId === PINIA_ROOT_ID + ? pinia + : pinia._s.get(payload.nodeId); + if (!inspectedStore) { + return toastMessage(`store "${payload.nodeId}" not found`, 'error'); + } + const { path } = payload; + if (!isPinia(inspectedStore)) { + // access only the state + if (path.length !== 1 || + !inspectedStore._customProperties.has(path[0]) || + path[0] in inspectedStore.$state) { + path.unshift('$state'); + } + } + else { + // Root access, we can omit the `.value` because the devtools API does it for us + path.unshift('state'); + } + isTimelineActive = false; + payload.set(inspectedStore, path, payload.state.value); + isTimelineActive = true; + } + }); + api.on.editComponentState((payload) => { + if (payload.type.startsWith('🍍')) { + const storeId = payload.type.replace(/^🍍\s*/, ''); + const store = pinia._s.get(storeId); + if (!store) { + return toastMessage(`store "${storeId}" not found`, 'error'); + } + const { path } = payload; + if (path[0] !== 'state') { + return toastMessage(`Invalid path for store "${storeId}":\n${path}\nOnly state can be modified.`); + } + // rewrite the first entry to be able to directly set the state as + // well as any other path + path[0] = '$state'; + isTimelineActive = false; + payload.set(store, path, payload.state.value); + isTimelineActive = true; + } + }); + }); +} +function addStoreToDevtools(app, store) { + if (!componentStateTypes.includes(getStoreType(store.$id))) { + componentStateTypes.push(getStoreType(store.$id)); + } + setupDevtoolsPlugin({ + id: 'dev.esm.pinia', + label: 'Pinia 🍍', + logo: 'https://pinia.vuejs.org/logo.svg', + packageName: 'pinia', + homepage: 'https://pinia.vuejs.org', + componentStateTypes, + app, + settings: { + logStoreChanges: { + label: 'Notify about new/deleted stores', + type: 'boolean', + defaultValue: true, + }, + // useEmojis: { + // label: 'Use emojis in messages ⚡️', + // type: 'boolean', + // defaultValue: true, + // }, + }, + }, (api) => { + // gracefully handle errors + const now = typeof api.now === 'function' ? api.now.bind(api) : Date.now; + store.$onAction(({ after, onError, name, args }) => { + const groupId = runningActionId++; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🛫 ' + name, + subtitle: 'start', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + }, + groupId, + }, + }); + after((result) => { + activeAction = undefined; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🛬 ' + name, + subtitle: 'end', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + result, + }, + groupId, + }, + }); + }); + onError((error) => { + activeAction = undefined; + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + logType: 'error', + title: '💥 ' + name, + subtitle: 'end', + data: { + store: formatDisplay(store.$id), + action: formatDisplay(name), + args, + error, + }, + groupId, + }, + }); + }); + }, true); + store._customProperties.forEach((name) => { + watch(() => unref(store[name]), (newValue, oldValue) => { + api.notifyComponentUpdate(); + api.sendInspectorState(INSPECTOR_ID); + if (isTimelineActive) { + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: 'Change', + subtitle: name, + data: { + newValue, + oldValue, + }, + groupId: activeAction, + }, + }); + } + }, { deep: true }); + }); + store.$subscribe(({ events, type }, state) => { + api.notifyComponentUpdate(); + api.sendInspectorState(INSPECTOR_ID); + if (!isTimelineActive) + return; + // rootStore.state[store.id] = state + const eventData = { + time: now(), + title: formatMutationType(type), + data: assign$1({ store: formatDisplay(store.$id) }, formatEventData(events)), + groupId: activeAction, + }; + if (type === MutationType.patchFunction) { + eventData.subtitle = '⤵️'; + } + else if (type === MutationType.patchObject) { + eventData.subtitle = '🧩'; + } + else if (events && !Array.isArray(events)) { + eventData.subtitle = events.type; + } + if (events) { + eventData.data['rawEvent(s)'] = { + _custom: { + display: 'DebuggerEvent', + type: 'object', + tooltip: 'raw DebuggerEvent[]', + value: events, + }, + }; + } + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: eventData, + }); + }, { detached: true, flush: 'sync' }); + const hotUpdate = store._hotUpdate; + store._hotUpdate = markRaw((newStore) => { + hotUpdate(newStore); + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: now(), + title: '🔥 ' + store.$id, + subtitle: 'HMR update', + data: { + store: formatDisplay(store.$id), + info: formatDisplay(`HMR update`), + }, + }, + }); + // update the devtools too + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + }); + const { $dispose } = store; + store.$dispose = () => { + $dispose(); + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + api.getSettings().logStoreChanges && + toastMessage(`Disposed "${store.$id}" store 🗑`); + }; + // trigger an update so it can display new registered stores + api.notifyComponentUpdate(); + api.sendInspectorTree(INSPECTOR_ID); + api.sendInspectorState(INSPECTOR_ID); + api.getSettings().logStoreChanges && + toastMessage(`"${store.$id}" store installed 🆕`); + }); +} +let runningActionId = 0; +let activeAction; +/** + * Patches a store to enable action grouping in devtools by wrapping the store with a Proxy that is passed as the + * context of all actions, allowing us to set `runningAction` on each access and effectively associating any state + * mutation to the action. + * + * @param store - store to patch + * @param actionNames - list of actionst to patch + */ +function patchActionForGrouping(store, actionNames, wrapWithProxy) { + // original actions of the store as they are given by pinia. We are going to override them + const actions = actionNames.reduce((storeActions, actionName) => { + // use toRaw to avoid tracking #541 + storeActions[actionName] = toRaw(store)[actionName]; + return storeActions; + }, {}); + for (const actionName in actions) { + store[actionName] = function () { + // the running action id is incremented in a before action hook + const _actionId = runningActionId; + const trackedStore = wrapWithProxy + ? new Proxy(store, { + get(...args) { + activeAction = _actionId; + return Reflect.get(...args); + }, + set(...args) { + activeAction = _actionId; + return Reflect.set(...args); + }, + }) + : store; + // For Setup Stores we need https://github.com/tc39/proposal-async-context + activeAction = _actionId; + const retValue = actions[actionName].apply(trackedStore, arguments); + // this is safer as async actions in Setup Stores would associate mutations done outside of the action + activeAction = undefined; + return retValue; + }; + } +} +/** + * pinia.use(devtoolsPlugin) + */ +function devtoolsPlugin({ app, store, options }) { + // HMR module + if (store.$id.startsWith('__hot:')) { + return; + } + // detect option api vs setup api + store._isOptionsAPI = !!options.state; + patchActionForGrouping(store, Object.keys(options.actions), store._isOptionsAPI); + // Upgrade the HMR to also update the new actions + const originalHotUpdate = store._hotUpdate; + toRaw(store)._hotUpdate = function (newStore) { + originalHotUpdate.apply(this, arguments); + patchActionForGrouping(store, Object.keys(newStore._hmrPayload.actions), !!store._isOptionsAPI); + }; + addStoreToDevtools(app, + // FIXME: is there a way to allow the assignment from Store to StoreGeneric? + store); +} + +/** + * Creates a Pinia instance to be used by the application + */ +function createPinia() { + const scope = effectScope(true); + // NOTE: here we could check the window object for a state and directly set it + // if there is anything like it with Vue 3 SSR + const state = scope.run(() => ref({})); + let _p = []; + // plugins added before calling app.use(pinia) + let toBeInstalled = []; + const pinia = markRaw({ + install(app) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + if (!isVue2) { + pinia._a = app; + app.provide(piniaSymbol, pinia); + app.config.globalProperties.$pinia = pinia; + /* istanbul ignore else */ + if (USE_DEVTOOLS) { + registerPiniaDevtools(app, pinia); + } + toBeInstalled.forEach((plugin) => _p.push(plugin)); + toBeInstalled = []; + } + }, + use(plugin) { + if (!this._a && !isVue2) { + toBeInstalled.push(plugin); + } + else { + _p.push(plugin); + } + return this; + }, + _p, + // it's actually undefined here + // @ts-expect-error + _a: null, + _e: scope, + _s: new Map(), + state, + }); + // pinia devtools rely on dev only features so they cannot be forced unless + // the dev build of Vue is used. Avoid old browsers like IE11. + if (USE_DEVTOOLS && typeof Proxy !== 'undefined') { + pinia.use(devtoolsPlugin); + } + return pinia; +} + +/** + * Checks if a function is a `StoreDefinition`. + * + * @param fn - object to test + * @returns true if `fn` is a StoreDefinition + */ +const isUseStore = (fn) => { + return typeof fn === 'function' && typeof fn.$id === 'string'; +}; +/** + * Mutates in place `newState` with `oldState` to _hot update_ it. It will + * remove any key not existing in `newState` and recursively merge plain + * objects. + * + * @param newState - new state object to be patched + * @param oldState - old state that should be used to patch newState + * @returns - newState + */ +function patchObject(newState, oldState) { + // no need to go through symbols because they cannot be serialized anyway + for (const key in oldState) { + const subPatch = oldState[key]; + // skip the whole sub tree + if (!(key in newState)) { + continue; + } + const targetValue = newState[key]; + if (isPlainObject(targetValue) && + isPlainObject(subPatch) && + !isRef(subPatch) && + !isReactive(subPatch)) { + newState[key] = patchObject(targetValue, subPatch); + } + else { + // objects are either a bit more complex (e.g. refs) or primitives, so we + // just set the whole thing + if (isVue2) { + set(newState, key, subPatch); + } + else { + newState[key] = subPatch; + } + } + } + return newState; +} +/** + * Creates an _accept_ function to pass to `import.meta.hot` in Vite applications. + * + * @example + * ```js + * const useUser = defineStore(...) + * if (import.meta.hot) { + * import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot)) + * } + * ``` + * + * @param initialUseStore - return of the defineStore to hot update + * @param hot - `import.meta.hot` + */ +function acceptHMRUpdate(initialUseStore, hot) { + // strip as much as possible from iife.prod + if (!(process.env.NODE_ENV !== 'production')) { + return () => { }; + } + return (newModule) => { + const pinia = hot.data.pinia || initialUseStore._pinia; + if (!pinia) { + // this store is still not used + return; + } + // preserve the pinia instance across loads + hot.data.pinia = pinia; + // console.log('got data', newStore) + for (const exportName in newModule) { + const useStore = newModule[exportName]; + // console.log('checking for', exportName) + if (isUseStore(useStore) && pinia._s.has(useStore.$id)) { + // console.log('Accepting update for', useStore.$id) + const id = useStore.$id; + if (id !== initialUseStore.$id) { + console.warn(`The id of the store changed from "${initialUseStore.$id}" to "${id}". Reloading.`); + // return import.meta.hot.invalidate() + return hot.invalidate(); + } + const existingStore = pinia._s.get(id); + if (!existingStore) { + console.log(`[Pinia]: skipping hmr because store doesn't exist yet`); + return; + } + useStore(pinia, existingStore); + } + } + }; +} + +const noop = () => { }; +function addSubscription(subscriptions, callback, detached, onCleanup = noop) { + subscriptions.push(callback); + const removeSubscription = () => { + const idx = subscriptions.indexOf(callback); + if (idx > -1) { + subscriptions.splice(idx, 1); + onCleanup(); + } + }; + if (!detached && getCurrentScope()) { + onScopeDispose(removeSubscription); + } + return removeSubscription; +} +function triggerSubscriptions(subscriptions, ...args) { + subscriptions.slice().forEach((callback) => { + callback(...args); + }); +} + +const fallbackRunWithContext = (fn) => fn(); +function mergeReactiveObjects(target, patchToApply) { + // Handle Map instances + if (target instanceof Map && patchToApply instanceof Map) { + patchToApply.forEach((value, key) => target.set(key, value)); + } + // Handle Set instances + if (target instanceof Set && patchToApply instanceof Set) { + patchToApply.forEach(target.add, target); + } + // no need to go through symbols because they cannot be serialized anyway + for (const key in patchToApply) { + if (!patchToApply.hasOwnProperty(key)) + continue; + const subPatch = patchToApply[key]; + const targetValue = target[key]; + if (isPlainObject(targetValue) && + isPlainObject(subPatch) && + target.hasOwnProperty(key) && + !isRef(subPatch) && + !isReactive(subPatch)) { + // NOTE: here I wanted to warn about inconsistent types but it's not possible because in setup stores one might + // start the value of a property as a certain type e.g. a Map, and then for some reason, during SSR, change that + // to `undefined`. When trying to hydrate, we want to override the Map with `undefined`. + target[key] = mergeReactiveObjects(targetValue, subPatch); + } + else { + // @ts-expect-error: subPatch is a valid value + target[key] = subPatch; + } + } + return target; +} +const skipHydrateSymbol = (process.env.NODE_ENV !== 'production') + ? Symbol('pinia:skipHydration') + : /* istanbul ignore next */ Symbol(); +const skipHydrateMap = /*#__PURE__*/ new WeakMap(); +/** + * Tells Pinia to skip the hydration process of a given object. This is useful in setup stores (only) when you return a + * stateful object in the store but it isn't really state. e.g. returning a router instance in a setup store. + * + * @param obj - target object + * @returns obj + */ +function skipHydrate(obj) { + return isVue2 + ? // in @vue/composition-api, the refs are sealed so defineProperty doesn't work... + /* istanbul ignore next */ skipHydrateMap.set(obj, 1) && obj + : Object.defineProperty(obj, skipHydrateSymbol, {}); +} +/** + * Returns whether a value should be hydrated + * + * @param obj - target variable + * @returns true if `obj` should be hydrated + */ +function shouldHydrate(obj) { + return isVue2 + ? /* istanbul ignore next */ !skipHydrateMap.has(obj) + : !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol); +} +const { assign } = Object; +function isComputed(o) { + return !!(isRef(o) && o.effect); +} +function createOptionsStore(id, options, pinia, hot) { + const { state, actions, getters } = options; + const initialState = pinia.state.value[id]; + let store; + function setup() { + if (!initialState && (!(process.env.NODE_ENV !== 'production') || !hot)) { + /* istanbul ignore if */ + if (isVue2) { + set(pinia.state.value, id, state ? state() : {}); + } + else { + pinia.state.value[id] = state ? state() : {}; + } + } + // avoid creating a state in pinia.state.value + const localState = (process.env.NODE_ENV !== 'production') && hot + ? // use ref() to unwrap refs inside state TODO: check if this is still necessary + toRefs(ref(state ? state() : {}).value) + : toRefs(pinia.state.value[id]); + return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => { + if ((process.env.NODE_ENV !== 'production') && name in localState) { + console.warn(`[🍍]: A getter cannot have the same name as another state property. Rename one of them. Found with "${name}" in store "${id}".`); + } + computedGetters[name] = markRaw(computed(() => { + setActivePinia(pinia); + // it was created just before + const store = pinia._s.get(id); + // allow cross using stores + /* istanbul ignore next */ + if (isVue2 && !store._r) + return; + // @ts-expect-error + // return getters![name].call(context, context) + // TODO: avoid reading the getter while assigning with a global variable + return getters[name].call(store, store); + })); + return computedGetters; + }, {})); + } + store = createSetupStore(id, setup, options, pinia, hot, true); + return store; +} +function createSetupStore($id, setup, options = {}, pinia, hot, isOptionsStore) { + let scope; + const optionsForPlugin = assign({ actions: {} }, options); + /* istanbul ignore if */ + if ((process.env.NODE_ENV !== 'production') && !pinia._e.active) { + throw new Error('Pinia destroyed'); + } + // watcher options for $subscribe + const $subscribeOptions = { + deep: true, + // flush: 'post', + }; + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production') && !isVue2) { + $subscribeOptions.onTrigger = (event) => { + /* istanbul ignore else */ + if (isListening) { + debuggerEvents = event; + // avoid triggering this while the store is being built and the state is being set in pinia + } + else if (isListening == false && !store._hotUpdating) { + // let patch send all the events together later + /* istanbul ignore else */ + if (Array.isArray(debuggerEvents)) { + debuggerEvents.push(event); + } + else { + console.error('🍍 debuggerEvents should be an array. This is most likely an internal Pinia bug.'); + } + } + }; + } + // internal state + let isListening; // set to true at the end + let isSyncListening; // set to true at the end + let subscriptions = []; + let actionSubscriptions = []; + let debuggerEvents; + const initialState = pinia.state.value[$id]; + // avoid setting the state for option stores if it is set + // by the setup + if (!isOptionsStore && !initialState && (!(process.env.NODE_ENV !== 'production') || !hot)) { + /* istanbul ignore if */ + if (isVue2) { + set(pinia.state.value, $id, {}); + } + else { + pinia.state.value[$id] = {}; + } + } + const hotState = ref({}); + // avoid triggering too many listeners + // https://github.com/vuejs/pinia/issues/1129 + let activeListener; + function $patch(partialStateOrMutator) { + let subscriptionMutation; + isListening = isSyncListening = false; + // reset the debugger events since patches are sync + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + debuggerEvents = []; + } + if (typeof partialStateOrMutator === 'function') { + partialStateOrMutator(pinia.state.value[$id]); + subscriptionMutation = { + type: MutationType.patchFunction, + storeId: $id, + events: debuggerEvents, + }; + } + else { + mergeReactiveObjects(pinia.state.value[$id], partialStateOrMutator); + subscriptionMutation = { + type: MutationType.patchObject, + payload: partialStateOrMutator, + storeId: $id, + events: debuggerEvents, + }; + } + const myListenerId = (activeListener = Symbol()); + nextTick().then(() => { + if (activeListener === myListenerId) { + isListening = true; + } + }); + isSyncListening = true; + // because we paused the watcher, we need to manually call the subscriptions + triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]); + } + const $reset = isOptionsStore + ? function $reset() { + const { state } = options; + const newState = state ? state() : {}; + // we use a patch to group all changes into one single subscription + this.$patch(($state) => { + assign($state, newState); + }); + } + : /* istanbul ignore next */ + (process.env.NODE_ENV !== 'production') + ? () => { + throw new Error(`🍍: Store "${$id}" is built using the setup syntax and does not implement $reset().`); + } + : noop; + function $dispose() { + scope.stop(); + subscriptions = []; + actionSubscriptions = []; + pinia._s.delete($id); + } + /** + * Wraps an action to handle subscriptions. + * + * @param name - name of the action + * @param action - action to wrap + * @returns a wrapped action to handle subscriptions + */ + function wrapAction(name, action) { + return function () { + setActivePinia(pinia); + const args = Array.from(arguments); + const afterCallbackList = []; + const onErrorCallbackList = []; + function after(callback) { + afterCallbackList.push(callback); + } + function onError(callback) { + onErrorCallbackList.push(callback); + } + // @ts-expect-error + triggerSubscriptions(actionSubscriptions, { + args, + name, + store, + after, + onError, + }); + let ret; + try { + ret = action.apply(this && this.$id === $id ? this : store, args); + // handle sync errors + } + catch (error) { + triggerSubscriptions(onErrorCallbackList, error); + throw error; + } + if (ret instanceof Promise) { + return ret + .then((value) => { + triggerSubscriptions(afterCallbackList, value); + return value; + }) + .catch((error) => { + triggerSubscriptions(onErrorCallbackList, error); + return Promise.reject(error); + }); + } + // trigger after callbacks + triggerSubscriptions(afterCallbackList, ret); + return ret; + }; + } + const _hmrPayload = /*#__PURE__*/ markRaw({ + actions: {}, + getters: {}, + state: [], + hotState, + }); + const partialStore = { + _p: pinia, + // _s: scope, + $id, + $onAction: addSubscription.bind(null, actionSubscriptions), + $patch, + $reset, + $subscribe(callback, options = {}) { + const removeSubscription = addSubscription(subscriptions, callback, options.detached, () => stopWatcher()); + const stopWatcher = scope.run(() => watch(() => pinia.state.value[$id], (state) => { + if (options.flush === 'sync' ? isSyncListening : isListening) { + callback({ + storeId: $id, + type: MutationType.direct, + events: debuggerEvents, + }, state); + } + }, assign({}, $subscribeOptions, options))); + return removeSubscription; + }, + $dispose, + }; + /* istanbul ignore if */ + if (isVue2) { + // start as non ready + partialStore._r = false; + } + const store = reactive((process.env.NODE_ENV !== 'production') || USE_DEVTOOLS + ? assign({ + _hmrPayload, + _customProperties: markRaw(new Set()), // devtools custom properties + }, partialStore + // must be added later + // setupStore + ) + : partialStore); + // store the partial store now so the setup of stores can instantiate each other before they are finished without + // creating infinite loops. + pinia._s.set($id, store); + const runWithContext = (pinia._a && pinia._a.runWithContext) || fallbackRunWithContext; + // TODO: idea create skipSerialize that marks properties as non serializable and they are skipped + const setupStore = pinia._e.run(() => { + scope = effectScope(); + return runWithContext(() => scope.run(setup)); + }); + // overwrite existing actions to support $onAction + for (const key in setupStore) { + const prop = setupStore[key]; + if ((isRef(prop) && !isComputed(prop)) || isReactive(prop)) { + // mark it as a piece of state to be serialized + if ((process.env.NODE_ENV !== 'production') && hot) { + set(hotState.value, key, toRef(setupStore, key)); + // createOptionStore directly sets the state in pinia.state.value so we + // can just skip that + } + else if (!isOptionsStore) { + // in setup stores we must hydrate the state and sync pinia state tree with the refs the user just created + if (initialState && shouldHydrate(prop)) { + if (isRef(prop)) { + prop.value = initialState[key]; + } + else { + // probably a reactive object, lets recursively assign + // @ts-expect-error: prop is unknown + mergeReactiveObjects(prop, initialState[key]); + } + } + // transfer the ref to the pinia state to keep everything in sync + /* istanbul ignore if */ + if (isVue2) { + set(pinia.state.value[$id], key, prop); + } + else { + pinia.state.value[$id][key] = prop; + } + } + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + _hmrPayload.state.push(key); + } + // action + } + else if (typeof prop === 'function') { + // @ts-expect-error: we are overriding the function we avoid wrapping if + const actionValue = (process.env.NODE_ENV !== 'production') && hot ? prop : wrapAction(key, prop); + // this a hot module replacement store because the hotUpdate method needs + // to do it with the right context + /* istanbul ignore if */ + if (isVue2) { + set(setupStore, key, actionValue); + } + else { + // @ts-expect-error + setupStore[key] = actionValue; + } + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + _hmrPayload.actions[key] = prop; + } + // list actions so they can be used in plugins + // @ts-expect-error + optionsForPlugin.actions[key] = prop; + } + else if ((process.env.NODE_ENV !== 'production')) { + // add getters for devtools + if (isComputed(prop)) { + _hmrPayload.getters[key] = isOptionsStore + ? // @ts-expect-error + options.getters[key] + : prop; + if (IS_CLIENT) { + const getters = setupStore._getters || + // @ts-expect-error: same + (setupStore._getters = markRaw([])); + getters.push(key); + } + } + } + } + // add the state, getters, and action properties + /* istanbul ignore if */ + if (isVue2) { + Object.keys(setupStore).forEach((key) => { + set(store, key, setupStore[key]); + }); + } + else { + assign(store, setupStore); + // allows retrieving reactive objects with `storeToRefs()`. Must be called after assigning to the reactive object. + // Make `storeToRefs()` work with `reactive()` #799 + assign(toRaw(store), setupStore); + } + // use this instead of a computed with setter to be able to create it anywhere + // without linking the computed lifespan to wherever the store is first + // created. + Object.defineProperty(store, '$state', { + get: () => ((process.env.NODE_ENV !== 'production') && hot ? hotState.value : pinia.state.value[$id]), + set: (state) => { + /* istanbul ignore if */ + if ((process.env.NODE_ENV !== 'production') && hot) { + throw new Error('cannot set hotState'); + } + $patch(($state) => { + assign($state, state); + }); + }, + }); + // add the hotUpdate before plugins to allow them to override it + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + store._hotUpdate = markRaw((newStore) => { + store._hotUpdating = true; + newStore._hmrPayload.state.forEach((stateKey) => { + if (stateKey in store.$state) { + const newStateTarget = newStore.$state[stateKey]; + const oldStateSource = store.$state[stateKey]; + if (typeof newStateTarget === 'object' && + isPlainObject(newStateTarget) && + isPlainObject(oldStateSource)) { + patchObject(newStateTarget, oldStateSource); + } + else { + // transfer the ref + newStore.$state[stateKey] = oldStateSource; + } + } + // patch direct access properties to allow store.stateProperty to work as + // store.$state.stateProperty + set(store, stateKey, toRef(newStore.$state, stateKey)); + }); + // remove deleted state properties + Object.keys(store.$state).forEach((stateKey) => { + if (!(stateKey in newStore.$state)) { + del(store, stateKey); + } + }); + // avoid devtools logging this as a mutation + isListening = false; + isSyncListening = false; + pinia.state.value[$id] = toRef(newStore._hmrPayload, 'hotState'); + isSyncListening = true; + nextTick().then(() => { + isListening = true; + }); + for (const actionName in newStore._hmrPayload.actions) { + const action = newStore[actionName]; + set(store, actionName, wrapAction(actionName, action)); + } + // TODO: does this work in both setup and option store? + for (const getterName in newStore._hmrPayload.getters) { + const getter = newStore._hmrPayload.getters[getterName]; + const getterValue = isOptionsStore + ? // special handling of options api + computed(() => { + setActivePinia(pinia); + return getter.call(store, store); + }) + : getter; + set(store, getterName, getterValue); + } + // remove deleted getters + Object.keys(store._hmrPayload.getters).forEach((key) => { + if (!(key in newStore._hmrPayload.getters)) { + del(store, key); + } + }); + // remove old actions + Object.keys(store._hmrPayload.actions).forEach((key) => { + if (!(key in newStore._hmrPayload.actions)) { + del(store, key); + } + }); + // update the values used in devtools and to allow deleting new properties later on + store._hmrPayload = newStore._hmrPayload; + store._getters = newStore._getters; + store._hotUpdating = false; + }); + } + if (USE_DEVTOOLS) { + const nonEnumerable = { + writable: true, + configurable: true, + // avoid warning on devtools trying to display this property + enumerable: false, + }; + ['_p', '_hmrPayload', '_getters', '_customProperties'].forEach((p) => { + Object.defineProperty(store, p, assign({ value: store[p] }, nonEnumerable)); + }); + } + /* istanbul ignore if */ + if (isVue2) { + // mark the store as ready before plugins + store._r = true; + } + // apply all plugins + pinia._p.forEach((extender) => { + /* istanbul ignore else */ + if (USE_DEVTOOLS) { + const extensions = scope.run(() => extender({ + store, + app: pinia._a, + pinia, + options: optionsForPlugin, + })); + Object.keys(extensions || {}).forEach((key) => store._customProperties.add(key)); + assign(store, extensions); + } + else { + assign(store, scope.run(() => extender({ + store, + app: pinia._a, + pinia, + options: optionsForPlugin, + }))); + } + }); + if ((process.env.NODE_ENV !== 'production') && + store.$state && + typeof store.$state === 'object' && + typeof store.$state.constructor === 'function' && + !store.$state.constructor.toString().includes('[native code]')) { + console.warn(`[🍍]: The "state" must be a plain object. It cannot be\n` + + `\tstate: () => new MyClass()\n` + + `Found in store "${store.$id}".`); + } + // only apply hydrate to option stores with an initial state in pinia + if (initialState && + isOptionsStore && + options.hydrate) { + options.hydrate(store.$state, initialState); + } + isListening = true; + isSyncListening = true; + return store; +} +function defineStore( +// TODO: add proper types from above +idOrOptions, setup, setupOptions) { + let id; + let options; + const isSetupStore = typeof setup === 'function'; + if (typeof idOrOptions === 'string') { + id = idOrOptions; + // the option store setup will contain the actual options in this case + options = isSetupStore ? setupOptions : setup; + } + else { + options = idOrOptions; + id = idOrOptions.id; + if ((process.env.NODE_ENV !== 'production') && typeof id !== 'string') { + throw new Error(`[🍍]: "defineStore()" must be passed a store id as its first argument.`); + } + } + function useStore(pinia, hot) { + const hasContext = hasInjectionContext(); + pinia = + // in test mode, ignore the argument provided as we can always retrieve a + // pinia instance with getActivePinia() + ((process.env.NODE_ENV === 'test') && activePinia && activePinia._testing ? null : pinia) || + (hasContext ? inject(piniaSymbol, null) : null); + if (pinia) + setActivePinia(pinia); + if ((process.env.NODE_ENV !== 'production') && !activePinia) { + throw new Error(`[🍍]: "getActivePinia()" was called but there was no active Pinia. Did you forget to install pinia?\n` + + `\tconst pinia = createPinia()\n` + + `\tapp.use(pinia)\n` + + `This will fail in production.`); + } + pinia = activePinia; + if (!pinia._s.has(id)) { + // creating the store registers it in `pinia._s` + if (isSetupStore) { + createSetupStore(id, setup, options, pinia); + } + else { + createOptionsStore(id, options, pinia); + } + /* istanbul ignore else */ + if ((process.env.NODE_ENV !== 'production')) { + // @ts-expect-error: not the right inferred type + useStore._pinia = pinia; + } + } + const store = pinia._s.get(id); + if ((process.env.NODE_ENV !== 'production') && hot) { + const hotId = '__hot:' + id; + const newStore = isSetupStore + ? createSetupStore(hotId, setup, options, pinia, true) + : createOptionsStore(hotId, assign({}, options), pinia, true); + hot._hotUpdate(newStore); + // cleanup the state properties and the store from the cache + delete pinia.state.value[hotId]; + pinia._s.delete(hotId); + } + if ((process.env.NODE_ENV !== 'production') && IS_CLIENT) { + const currentInstance = getCurrentInstance(); + // save stores in instances to access them devtools + if (currentInstance && + currentInstance.proxy && + // avoid adding stores that are just built for hot module replacement + !hot) { + const vm = currentInstance.proxy; + const cache = '_pStores' in vm ? vm._pStores : (vm._pStores = {}); + cache[id] = store; + } + } + // StoreGeneric cannot be casted towards Store + return store; + } + useStore.$id = id; + return useStore; +} + +let mapStoreSuffix = 'Store'; +/** + * Changes the suffix added by `mapStores()`. Can be set to an empty string. + * Defaults to `"Store"`. Make sure to extend the MapStoresCustomization + * interface if you are using TypeScript. + * + * @param suffix - new suffix + */ +function setMapStoreSuffix(suffix // could be 'Store' but that would be annoying for JS +) { + mapStoreSuffix = suffix; +} +/** + * Allows using stores without the composition API (`setup()`) by generating an + * object to be spread in the `computed` field of a component. It accepts a list + * of store definitions. + * + * @example + * ```js + * export default { + * computed: { + * // other computed properties + * ...mapStores(useUserStore, useCartStore) + * }, + * + * created() { + * this.userStore // store with id "user" + * this.cartStore // store with id "cart" + * } + * } + * ``` + * + * @param stores - list of stores to map to an object + */ +function mapStores(...stores) { + if ((process.env.NODE_ENV !== 'production') && Array.isArray(stores[0])) { + console.warn(`[🍍]: Directly pass all stores to "mapStores()" without putting them in an array:\n` + + `Replace\n` + + `\tmapStores([useAuthStore, useCartStore])\n` + + `with\n` + + `\tmapStores(useAuthStore, useCartStore)\n` + + `This will fail in production if not fixed.`); + stores = stores[0]; + } + return stores.reduce((reduced, useStore) => { + // @ts-expect-error: $id is added by defineStore + reduced[useStore.$id + mapStoreSuffix] = function () { + return useStore(this.$pinia); + }; + return reduced; + }, {}); +} +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + reduced[key] = function () { + return useStore(this.$pinia)[key]; + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function () { + const store = useStore(this.$pinia); + const storeKey = keysOrMapper[key]; + // for some reason TS is unable to infer the type of storeKey to be a + // function + return typeof storeKey === 'function' + ? storeKey.call(this, store) + : store[storeKey]; + }; + return reduced; + }, {}); +} +/** + * Alias for `mapState()`. You should use `mapState()` instead. + * @deprecated use `mapState()` instead. + */ +const mapGetters = mapState; +/** + * Allows directly using actions from your store without using the composition + * API (`setup()`) by generating an object to be spread in the `methods` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapActions(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[key](...args); + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[keysOrMapper[key]](...args); + }; + return reduced; + }, {}); +} +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapWritableState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[key]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[key] = value); + }, + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[keysOrMapper[key]]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[keysOrMapper[key]] = value); + }, + }; + return reduced; + }, {}); +} + +/** + * Creates an object of references with all the state, getters, and plugin-added + * state properties of the store. Similar to `toRefs()` but specifically + * designed for Pinia stores so methods and non reactive properties are + * completely ignored. + * + * @param store - store to extract the refs from + */ +function storeToRefs(store) { + // See https://github.com/vuejs/pinia/issues/852 + // It's easier to just use toRefs() even if it includes more stuff + if (isVue2) { + // @ts-expect-error: toRefs include methods and others + return toRefs(store); + } + else { + store = toRaw(store); + const refs = {}; + for (const key in store) { + const value = store[key]; + if (isRef(value) || isReactive(value)) { + // @ts-expect-error: the key is state or getter + refs[key] = + // --- + toRef(store, key); + } + } + return refs; + } +} + +/** + * Vue 2 Plugin that must be installed for pinia to work. Note **you don't need + * this plugin if you are using Nuxt.js**. Use the `buildModule` instead: + * https://pinia.vuejs.org/ssr/nuxt.html. + * + * @example + * ```js + * import Vue from 'vue' + * import { PiniaVuePlugin, createPinia } from 'pinia' + * + * Vue.use(PiniaVuePlugin) + * const pinia = createPinia() + * + * new Vue({ + * el: '#app', + * // ... + * pinia, + * }) + * ``` + * + * @param _Vue - `Vue` imported from 'vue'. + */ +const PiniaVuePlugin = function (_Vue) { + // Equivalent of + // app.config.globalProperties.$pinia = pinia + _Vue.mixin({ + beforeCreate() { + const options = this.$options; + if (options.pinia) { + const pinia = options.pinia; + // HACK: taken from provide(): https://github.com/vuejs/composition-api/blob/main/src/apis/inject.ts#L31 + /* istanbul ignore else */ + if (!this._provided) { + const provideCache = {}; + Object.defineProperty(this, '_provided', { + get: () => provideCache, + set: (v) => Object.assign(provideCache, v), + }); + } + this._provided[piniaSymbol] = pinia; + // propagate the pinia instance in an SSR friendly way + // avoid adding it to nuxt twice + /* istanbul ignore else */ + if (!this.$pinia) { + this.$pinia = pinia; + } + pinia._a = this; + if (IS_CLIENT) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + } + if (USE_DEVTOOLS) { + registerPiniaDevtools(pinia._a, pinia); + } + } + else if (!this.$pinia && options.parent && options.parent.$pinia) { + this.$pinia = options.parent.$pinia; + } + }, + destroyed() { + delete this._pStores; + }, + }); +}; + +export { MutationType, PiniaVuePlugin, acceptHMRUpdate, createPinia, defineStore, getActivePinia, mapActions, mapGetters, mapState, mapStores, mapWritableState, setActivePinia, setMapStoreSuffix, skipHydrate, storeToRefs }; diff --git a/node_modules/pinia/dist/pinia.prod.cjs b/node_modules/pinia/dist/pinia.prod.cjs new file mode 100644 index 0000000..2afd99f --- /dev/null +++ b/node_modules/pinia/dist/pinia.prod.cjs @@ -0,0 +1,808 @@ +/*! + * pinia v2.1.6 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */ +'use strict'; + +var vueDemi = require('vue-demi'); + +/** + * setActivePinia must be called to handle SSR at the top of functions like + * `fetch`, `setup`, `serverPrefetch` and others + */ +let activePinia; +/** + * Sets or unsets the active pinia. Used in SSR and internally when calling + * actions and getters + * + * @param pinia - Pinia instance + */ +// @ts-expect-error: cannot constrain the type of the return +const setActivePinia = (pinia) => (activePinia = pinia); +/** + * Get the currently active pinia if there is any. + */ +const getActivePinia = () => (vueDemi.hasInjectionContext() && vueDemi.inject(piniaSymbol)) || activePinia; +const piniaSymbol = (/* istanbul ignore next */ Symbol()); + +function isPlainObject( +// eslint-disable-next-line @typescript-eslint/no-explicit-any +o) { + return (o && + typeof o === 'object' && + Object.prototype.toString.call(o) === '[object Object]' && + typeof o.toJSON !== 'function'); +} +// type DeepReadonly = { readonly [P in keyof T]: DeepReadonly } +// TODO: can we change these to numbers? +/** + * Possible types for SubscriptionCallback + */ +exports.MutationType = void 0; +(function (MutationType) { + /** + * Direct mutation of the state: + * + * - `store.name = 'new name'` + * - `store.$state.name = 'new name'` + * - `store.list.push('new item')` + */ + MutationType["direct"] = "direct"; + /** + * Mutated the state with `$patch` and an object + * + * - `store.$patch({ name: 'newName' })` + */ + MutationType["patchObject"] = "patch object"; + /** + * Mutated the state with `$patch` and a function + * + * - `store.$patch(state => state.name = 'newName')` + */ + MutationType["patchFunction"] = "patch function"; + // maybe reset? for $state = {} and $reset +})(exports.MutationType || (exports.MutationType = {})); + +const IS_CLIENT = typeof window !== 'undefined'; + +/** + * Creates a Pinia instance to be used by the application + */ +function createPinia() { + const scope = vueDemi.effectScope(true); + // NOTE: here we could check the window object for a state and directly set it + // if there is anything like it with Vue 3 SSR + const state = scope.run(() => vueDemi.ref({})); + let _p = []; + // plugins added before calling app.use(pinia) + let toBeInstalled = []; + const pinia = vueDemi.markRaw({ + install(app) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + if (!vueDemi.isVue2) { + pinia._a = app; + app.provide(piniaSymbol, pinia); + app.config.globalProperties.$pinia = pinia; + toBeInstalled.forEach((plugin) => _p.push(plugin)); + toBeInstalled = []; + } + }, + use(plugin) { + if (!this._a && !vueDemi.isVue2) { + toBeInstalled.push(plugin); + } + else { + _p.push(plugin); + } + return this; + }, + _p, + // it's actually undefined here + // @ts-expect-error + _a: null, + _e: scope, + _s: new Map(), + state, + }); + return pinia; +} + +/** + * Creates an _accept_ function to pass to `import.meta.hot` in Vite applications. + * + * @example + * ```js + * const useUser = defineStore(...) + * if (import.meta.hot) { + * import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot)) + * } + * ``` + * + * @param initialUseStore - return of the defineStore to hot update + * @param hot - `import.meta.hot` + */ +function acceptHMRUpdate(initialUseStore, hot) { + // strip as much as possible from iife.prod + { + return () => { }; + } +} + +const noop = () => { }; +function addSubscription(subscriptions, callback, detached, onCleanup = noop) { + subscriptions.push(callback); + const removeSubscription = () => { + const idx = subscriptions.indexOf(callback); + if (idx > -1) { + subscriptions.splice(idx, 1); + onCleanup(); + } + }; + if (!detached && vueDemi.getCurrentScope()) { + vueDemi.onScopeDispose(removeSubscription); + } + return removeSubscription; +} +function triggerSubscriptions(subscriptions, ...args) { + subscriptions.slice().forEach((callback) => { + callback(...args); + }); +} + +const fallbackRunWithContext = (fn) => fn(); +function mergeReactiveObjects(target, patchToApply) { + // Handle Map instances + if (target instanceof Map && patchToApply instanceof Map) { + patchToApply.forEach((value, key) => target.set(key, value)); + } + // Handle Set instances + if (target instanceof Set && patchToApply instanceof Set) { + patchToApply.forEach(target.add, target); + } + // no need to go through symbols because they cannot be serialized anyway + for (const key in patchToApply) { + if (!patchToApply.hasOwnProperty(key)) + continue; + const subPatch = patchToApply[key]; + const targetValue = target[key]; + if (isPlainObject(targetValue) && + isPlainObject(subPatch) && + target.hasOwnProperty(key) && + !vueDemi.isRef(subPatch) && + !vueDemi.isReactive(subPatch)) { + // NOTE: here I wanted to warn about inconsistent types but it's not possible because in setup stores one might + // start the value of a property as a certain type e.g. a Map, and then for some reason, during SSR, change that + // to `undefined`. When trying to hydrate, we want to override the Map with `undefined`. + target[key] = mergeReactiveObjects(targetValue, subPatch); + } + else { + // @ts-expect-error: subPatch is a valid value + target[key] = subPatch; + } + } + return target; +} +const skipHydrateSymbol = /* istanbul ignore next */ Symbol(); +const skipHydrateMap = /*#__PURE__*/ new WeakMap(); +/** + * Tells Pinia to skip the hydration process of a given object. This is useful in setup stores (only) when you return a + * stateful object in the store but it isn't really state. e.g. returning a router instance in a setup store. + * + * @param obj - target object + * @returns obj + */ +function skipHydrate(obj) { + return vueDemi.isVue2 + ? // in @vue/composition-api, the refs are sealed so defineProperty doesn't work... + /* istanbul ignore next */ skipHydrateMap.set(obj, 1) && obj + : Object.defineProperty(obj, skipHydrateSymbol, {}); +} +/** + * Returns whether a value should be hydrated + * + * @param obj - target variable + * @returns true if `obj` should be hydrated + */ +function shouldHydrate(obj) { + return vueDemi.isVue2 + ? /* istanbul ignore next */ !skipHydrateMap.has(obj) + : !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol); +} +const { assign } = Object; +function isComputed(o) { + return !!(vueDemi.isRef(o) && o.effect); +} +function createOptionsStore(id, options, pinia, hot) { + const { state, actions, getters } = options; + const initialState = pinia.state.value[id]; + let store; + function setup() { + if (!initialState && (!false )) { + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(pinia.state.value, id, state ? state() : {}); + } + else { + pinia.state.value[id] = state ? state() : {}; + } + } + // avoid creating a state in pinia.state.value + const localState = vueDemi.toRefs(pinia.state.value[id]); + return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => { + computedGetters[name] = vueDemi.markRaw(vueDemi.computed(() => { + setActivePinia(pinia); + // it was created just before + const store = pinia._s.get(id); + // allow cross using stores + /* istanbul ignore next */ + if (vueDemi.isVue2 && !store._r) + return; + // @ts-expect-error + // return getters![name].call(context, context) + // TODO: avoid reading the getter while assigning with a global variable + return getters[name].call(store, store); + })); + return computedGetters; + }, {})); + } + store = createSetupStore(id, setup, options, pinia, hot, true); + return store; +} +function createSetupStore($id, setup, options = {}, pinia, hot, isOptionsStore) { + let scope; + const optionsForPlugin = assign({ actions: {} }, options); + // watcher options for $subscribe + const $subscribeOptions = { + deep: true, + // flush: 'post', + }; + // internal state + let isListening; // set to true at the end + let isSyncListening; // set to true at the end + let subscriptions = []; + let actionSubscriptions = []; + let debuggerEvents; + const initialState = pinia.state.value[$id]; + // avoid setting the state for option stores if it is set + // by the setup + if (!isOptionsStore && !initialState && (!false )) { + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(pinia.state.value, $id, {}); + } + else { + pinia.state.value[$id] = {}; + } + } + vueDemi.ref({}); + // avoid triggering too many listeners + // https://github.com/vuejs/pinia/issues/1129 + let activeListener; + function $patch(partialStateOrMutator) { + let subscriptionMutation; + isListening = isSyncListening = false; + if (typeof partialStateOrMutator === 'function') { + partialStateOrMutator(pinia.state.value[$id]); + subscriptionMutation = { + type: exports.MutationType.patchFunction, + storeId: $id, + events: debuggerEvents, + }; + } + else { + mergeReactiveObjects(pinia.state.value[$id], partialStateOrMutator); + subscriptionMutation = { + type: exports.MutationType.patchObject, + payload: partialStateOrMutator, + storeId: $id, + events: debuggerEvents, + }; + } + const myListenerId = (activeListener = Symbol()); + vueDemi.nextTick().then(() => { + if (activeListener === myListenerId) { + isListening = true; + } + }); + isSyncListening = true; + // because we paused the watcher, we need to manually call the subscriptions + triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]); + } + const $reset = isOptionsStore + ? function $reset() { + const { state } = options; + const newState = state ? state() : {}; + // we use a patch to group all changes into one single subscription + this.$patch(($state) => { + assign($state, newState); + }); + } + : /* istanbul ignore next */ + noop; + function $dispose() { + scope.stop(); + subscriptions = []; + actionSubscriptions = []; + pinia._s.delete($id); + } + /** + * Wraps an action to handle subscriptions. + * + * @param name - name of the action + * @param action - action to wrap + * @returns a wrapped action to handle subscriptions + */ + function wrapAction(name, action) { + return function () { + setActivePinia(pinia); + const args = Array.from(arguments); + const afterCallbackList = []; + const onErrorCallbackList = []; + function after(callback) { + afterCallbackList.push(callback); + } + function onError(callback) { + onErrorCallbackList.push(callback); + } + // @ts-expect-error + triggerSubscriptions(actionSubscriptions, { + args, + name, + store, + after, + onError, + }); + let ret; + try { + ret = action.apply(this && this.$id === $id ? this : store, args); + // handle sync errors + } + catch (error) { + triggerSubscriptions(onErrorCallbackList, error); + throw error; + } + if (ret instanceof Promise) { + return ret + .then((value) => { + triggerSubscriptions(afterCallbackList, value); + return value; + }) + .catch((error) => { + triggerSubscriptions(onErrorCallbackList, error); + return Promise.reject(error); + }); + } + // trigger after callbacks + triggerSubscriptions(afterCallbackList, ret); + return ret; + }; + } + const partialStore = { + _p: pinia, + // _s: scope, + $id, + $onAction: addSubscription.bind(null, actionSubscriptions), + $patch, + $reset, + $subscribe(callback, options = {}) { + const removeSubscription = addSubscription(subscriptions, callback, options.detached, () => stopWatcher()); + const stopWatcher = scope.run(() => vueDemi.watch(() => pinia.state.value[$id], (state) => { + if (options.flush === 'sync' ? isSyncListening : isListening) { + callback({ + storeId: $id, + type: exports.MutationType.direct, + events: debuggerEvents, + }, state); + } + }, assign({}, $subscribeOptions, options))); + return removeSubscription; + }, + $dispose, + }; + /* istanbul ignore if */ + if (vueDemi.isVue2) { + // start as non ready + partialStore._r = false; + } + const store = vueDemi.reactive(partialStore); + // store the partial store now so the setup of stores can instantiate each other before they are finished without + // creating infinite loops. + pinia._s.set($id, store); + const runWithContext = (pinia._a && pinia._a.runWithContext) || fallbackRunWithContext; + // TODO: idea create skipSerialize that marks properties as non serializable and they are skipped + const setupStore = pinia._e.run(() => { + scope = vueDemi.effectScope(); + return runWithContext(() => scope.run(setup)); + }); + // overwrite existing actions to support $onAction + for (const key in setupStore) { + const prop = setupStore[key]; + if ((vueDemi.isRef(prop) && !isComputed(prop)) || vueDemi.isReactive(prop)) { + // mark it as a piece of state to be serialized + if (!isOptionsStore) { + // in setup stores we must hydrate the state and sync pinia state tree with the refs the user just created + if (initialState && shouldHydrate(prop)) { + if (vueDemi.isRef(prop)) { + prop.value = initialState[key]; + } + else { + // probably a reactive object, lets recursively assign + // @ts-expect-error: prop is unknown + mergeReactiveObjects(prop, initialState[key]); + } + } + // transfer the ref to the pinia state to keep everything in sync + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(pinia.state.value[$id], key, prop); + } + else { + pinia.state.value[$id][key] = prop; + } + } + // action + } + else if (typeof prop === 'function') { + // @ts-expect-error: we are overriding the function we avoid wrapping if + const actionValue = wrapAction(key, prop); + // this a hot module replacement store because the hotUpdate method needs + // to do it with the right context + /* istanbul ignore if */ + if (vueDemi.isVue2) { + vueDemi.set(setupStore, key, actionValue); + } + else { + // @ts-expect-error + setupStore[key] = actionValue; + } + // list actions so they can be used in plugins + // @ts-expect-error + optionsForPlugin.actions[key] = prop; + } + else ; + } + // add the state, getters, and action properties + /* istanbul ignore if */ + if (vueDemi.isVue2) { + Object.keys(setupStore).forEach((key) => { + vueDemi.set(store, key, setupStore[key]); + }); + } + else { + assign(store, setupStore); + // allows retrieving reactive objects with `storeToRefs()`. Must be called after assigning to the reactive object. + // Make `storeToRefs()` work with `reactive()` #799 + assign(vueDemi.toRaw(store), setupStore); + } + // use this instead of a computed with setter to be able to create it anywhere + // without linking the computed lifespan to wherever the store is first + // created. + Object.defineProperty(store, '$state', { + get: () => (pinia.state.value[$id]), + set: (state) => { + $patch(($state) => { + assign($state, state); + }); + }, + }); + /* istanbul ignore if */ + if (vueDemi.isVue2) { + // mark the store as ready before plugins + store._r = true; + } + // apply all plugins + pinia._p.forEach((extender) => { + /* istanbul ignore else */ + { + assign(store, scope.run(() => extender({ + store, + app: pinia._a, + pinia, + options: optionsForPlugin, + }))); + } + }); + // only apply hydrate to option stores with an initial state in pinia + if (initialState && + isOptionsStore && + options.hydrate) { + options.hydrate(store.$state, initialState); + } + isListening = true; + isSyncListening = true; + return store; +} +function defineStore( +// TODO: add proper types from above +idOrOptions, setup, setupOptions) { + let id; + let options; + const isSetupStore = typeof setup === 'function'; + if (typeof idOrOptions === 'string') { + id = idOrOptions; + // the option store setup will contain the actual options in this case + options = isSetupStore ? setupOptions : setup; + } + else { + options = idOrOptions; + id = idOrOptions.id; + } + function useStore(pinia, hot) { + const hasContext = vueDemi.hasInjectionContext(); + pinia = + // in test mode, ignore the argument provided as we can always retrieve a + // pinia instance with getActivePinia() + ((process.env.NODE_ENV === 'test') && activePinia && activePinia._testing ? null : pinia) || + (hasContext ? vueDemi.inject(piniaSymbol, null) : null); + if (pinia) + setActivePinia(pinia); + pinia = activePinia; + if (!pinia._s.has(id)) { + // creating the store registers it in `pinia._s` + if (isSetupStore) { + createSetupStore(id, setup, options, pinia); + } + else { + createOptionsStore(id, options, pinia); + } + } + const store = pinia._s.get(id); + // StoreGeneric cannot be casted towards Store + return store; + } + useStore.$id = id; + return useStore; +} + +let mapStoreSuffix = 'Store'; +/** + * Changes the suffix added by `mapStores()`. Can be set to an empty string. + * Defaults to `"Store"`. Make sure to extend the MapStoresCustomization + * interface if you are using TypeScript. + * + * @param suffix - new suffix + */ +function setMapStoreSuffix(suffix // could be 'Store' but that would be annoying for JS +) { + mapStoreSuffix = suffix; +} +/** + * Allows using stores without the composition API (`setup()`) by generating an + * object to be spread in the `computed` field of a component. It accepts a list + * of store definitions. + * + * @example + * ```js + * export default { + * computed: { + * // other computed properties + * ...mapStores(useUserStore, useCartStore) + * }, + * + * created() { + * this.userStore // store with id "user" + * this.cartStore // store with id "cart" + * } + * } + * ``` + * + * @param stores - list of stores to map to an object + */ +function mapStores(...stores) { + return stores.reduce((reduced, useStore) => { + // @ts-expect-error: $id is added by defineStore + reduced[useStore.$id + mapStoreSuffix] = function () { + return useStore(this.$pinia); + }; + return reduced; + }, {}); +} +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + reduced[key] = function () { + return useStore(this.$pinia)[key]; + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function () { + const store = useStore(this.$pinia); + const storeKey = keysOrMapper[key]; + // for some reason TS is unable to infer the type of storeKey to be a + // function + return typeof storeKey === 'function' + ? storeKey.call(this, store) + : store[storeKey]; + }; + return reduced; + }, {}); +} +/** + * Alias for `mapState()`. You should use `mapState()` instead. + * @deprecated use `mapState()` instead. + */ +const mapGetters = mapState; +/** + * Allows directly using actions from your store without using the composition + * API (`setup()`) by generating an object to be spread in the `methods` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapActions(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[key](...args); + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-expect-error + reduced[key] = function (...args) { + return useStore(this.$pinia)[keysOrMapper[key]](...args); + }; + return reduced; + }, {}); +} +/** + * Allows using state and getters from one store without using the composition + * API (`setup()`) by generating an object to be spread in the `computed` field + * of a component. + * + * @param useStore - store to map from + * @param keysOrMapper - array or object + */ +function mapWritableState(useStore, keysOrMapper) { + return Array.isArray(keysOrMapper) + ? keysOrMapper.reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[key]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[key] = value); + }, + }; + return reduced; + }, {}) + : Object.keys(keysOrMapper).reduce((reduced, key) => { + // @ts-ignore + reduced[key] = { + get() { + return useStore(this.$pinia)[keysOrMapper[key]]; + }, + set(value) { + // it's easier to type it here as any + return (useStore(this.$pinia)[keysOrMapper[key]] = value); + }, + }; + return reduced; + }, {}); +} + +/** + * Creates an object of references with all the state, getters, and plugin-added + * state properties of the store. Similar to `toRefs()` but specifically + * designed for Pinia stores so methods and non reactive properties are + * completely ignored. + * + * @param store - store to extract the refs from + */ +function storeToRefs(store) { + // See https://github.com/vuejs/pinia/issues/852 + // It's easier to just use toRefs() even if it includes more stuff + if (vueDemi.isVue2) { + // @ts-expect-error: toRefs include methods and others + return vueDemi.toRefs(store); + } + else { + store = vueDemi.toRaw(store); + const refs = {}; + for (const key in store) { + const value = store[key]; + if (vueDemi.isRef(value) || vueDemi.isReactive(value)) { + // @ts-expect-error: the key is state or getter + refs[key] = + // --- + vueDemi.toRef(store, key); + } + } + return refs; + } +} + +/** + * Vue 2 Plugin that must be installed for pinia to work. Note **you don't need + * this plugin if you are using Nuxt.js**. Use the `buildModule` instead: + * https://pinia.vuejs.org/ssr/nuxt.html. + * + * @example + * ```js + * import Vue from 'vue' + * import { PiniaVuePlugin, createPinia } from 'pinia' + * + * Vue.use(PiniaVuePlugin) + * const pinia = createPinia() + * + * new Vue({ + * el: '#app', + * // ... + * pinia, + * }) + * ``` + * + * @param _Vue - `Vue` imported from 'vue'. + */ +const PiniaVuePlugin = function (_Vue) { + // Equivalent of + // app.config.globalProperties.$pinia = pinia + _Vue.mixin({ + beforeCreate() { + const options = this.$options; + if (options.pinia) { + const pinia = options.pinia; + // HACK: taken from provide(): https://github.com/vuejs/composition-api/blob/main/src/apis/inject.ts#L31 + /* istanbul ignore else */ + if (!this._provided) { + const provideCache = {}; + Object.defineProperty(this, '_provided', { + get: () => provideCache, + set: (v) => Object.assign(provideCache, v), + }); + } + this._provided[piniaSymbol] = pinia; + // propagate the pinia instance in an SSR friendly way + // avoid adding it to nuxt twice + /* istanbul ignore else */ + if (!this.$pinia) { + this.$pinia = pinia; + } + pinia._a = this; + if (IS_CLIENT) { + // this allows calling useStore() outside of a component setup after + // installing pinia's plugin + setActivePinia(pinia); + } + } + else if (!this.$pinia && options.parent && options.parent.$pinia) { + this.$pinia = options.parent.$pinia; + } + }, + destroyed() { + delete this._pStores; + }, + }); +}; + +exports.PiniaVuePlugin = PiniaVuePlugin; +exports.acceptHMRUpdate = acceptHMRUpdate; +exports.createPinia = createPinia; +exports.defineStore = defineStore; +exports.getActivePinia = getActivePinia; +exports.mapActions = mapActions; +exports.mapGetters = mapGetters; +exports.mapState = mapState; +exports.mapStores = mapStores; +exports.mapWritableState = mapWritableState; +exports.setActivePinia = setActivePinia; +exports.setMapStoreSuffix = setMapStoreSuffix; +exports.skipHydrate = skipHydrate; +exports.storeToRefs = storeToRefs; diff --git a/node_modules/pinia/index.cjs b/node_modules/pinia/index.cjs new file mode 100644 index 0000000..9fc1f5c --- /dev/null +++ b/node_modules/pinia/index.cjs @@ -0,0 +1,7 @@ +'use strict' + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./dist/pinia.prod.cjs') +} else { + module.exports = require('./dist/pinia.cjs') +} diff --git a/node_modules/pinia/index.js b/node_modules/pinia/index.js new file mode 100644 index 0000000..9fc1f5c --- /dev/null +++ b/node_modules/pinia/index.js @@ -0,0 +1,7 @@ +'use strict' + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./dist/pinia.prod.cjs') +} else { + module.exports = require('./dist/pinia.cjs') +} diff --git a/node_modules/pinia/package.json b/node_modules/pinia/package.json new file mode 100644 index 0000000..c13f7f3 --- /dev/null +++ b/node_modules/pinia/package.json @@ -0,0 +1,100 @@ +{ + "name": "pinia", + "version": "2.1.6", + "description": "Intuitive, type safe and flexible Store for Vue", + "main": "index.js", + "module": "dist/pinia.mjs", + "unpkg": "dist/pinia.iife.js", + "jsdelivr": "dist/pinia.iife.js", + "types": "dist/pinia.d.ts", + "exports": { + ".": { + "types": "./dist/pinia.d.ts", + "node": { + "import": { + "production": "./dist/pinia.prod.cjs", + "development": "./dist/pinia.mjs", + "default": "./dist/pinia.mjs" + }, + "require": { + "production": "./dist/pinia.prod.cjs", + "development": "./dist/pinia.cjs", + "default": "./index.js" + } + }, + "import": "./dist/pinia.mjs", + "require": "./index.js" + }, + "./package.json": "./package.json", + "./dist/*": "./dist/*" + }, + "sideEffects": false, + "author": { + "name": "Eduardo San Martin Morote", + "email": "posva13@gmail.com" + }, + "funding": "https://github.com/sponsors/posva", + "files": [ + "dist/*.js", + "dist/*.mjs", + "dist/*.cjs", + "dist/pinia.d.ts", + "index.js", + "index.cjs", + "LICENSE", + "README.md" + ], + "keywords": [ + "vue", + "vuex", + "store", + "pinia", + "piña", + "pigna", + "composition", + "api", + "setup", + "typed", + "typescript", + "ts", + "type", + "safe" + ], + "license": "MIT", + "devDependencies": { + "@microsoft/api-extractor": "7.34.4", + "@vue/test-utils": "^2.4.0" + }, + "dependencies": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.3.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "@vue/composition-api": { + "optional": true + } + }, + "repository": { + "type": "git", + "url": "git+https://github.com/vuejs/pinia.git" + }, + "bugs": { + "url": "https://github.com/vuejs/pinia/issues" + }, + "homepage": "https://github.com/vuejs/pinia#readme", + "scripts": { + "build": "rimraf dist && rollup -c ../../rollup.config.mjs --environment TARGET:pinia", + "build:dts": "api-extractor run --local --verbose && tail -n +3 ./src/globalExtensions.ts >> dist/pinia.d.ts", + "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s --commit-path . -l pinia -r 1", + "test:dts": "tsc -p ./test-dts/tsconfig.json", + "test": "yarn run build && yarn run build:dts && yarn test:dts" + } +} \ No newline at end of file diff --git a/node_modules/vue-demi/LICENSE b/node_modules/vue-demi/LICENSE new file mode 100644 index 0000000..894ffaf --- /dev/null +++ b/node_modules/vue-demi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-present, Anthony Fu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/vue-demi/README.md b/node_modules/vue-demi/README.md new file mode 100644 index 0000000..4f23e0b --- /dev/null +++ b/node_modules/vue-demi/README.md @@ -0,0 +1,228 @@ + + +

+Vue Demi (half in French) is a developing utility
allows you to write Universal Vue Libraries for Vue 2 & 3
+See more details in this blog post +

+ +
+ +
+ +## Strategies + +- `<=2.6`: exports from `vue` + `@vue/composition-api` with plugin auto installing. +- `2.7`: exports from `vue` (Composition API is built-in in Vue 2.7). +- `>=3.0`: exports from `vue`, with polyfill of Vue 2's `set` and `del` API. + +## Usage + +Install this as your plugin's dependency: + +```bash +npm i vue-demi +# or +yarn add vue-demi +# or +pnpm i vue-demi +``` + +Add `vue` and `@vue/composition-api` to your plugin's peer dependencies to specify what versions you support. + +```jsonc +{ + "dependencies": { + "vue-demi": "latest" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^2.0.0 || >=3.0.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + }, + "devDependencies": { + "vue": "^3.0.0" // or "^2.6.0" base on your preferred working environment + }, +} +``` + +Import everything related to Vue from it, it will redirect to `vue@2` + `@vue/composition-api` or `vue@3` based on users' environments. + +```ts +import { ref, reactive, defineComponent } from 'vue-demi' +``` + +Publish your plugin and all is done! + +> When using with [Vite](https://vitejs.dev), you will need to opt-out the pre-bundling to get `vue-demi` work properly by +> ```js +> // vite.config.js +> export default defineConfig({ +> optimizeDeps: { +> exclude: ['vue-demi'] +> } +> }) +> ``` + +### Extra APIs + +`Vue Demi` provides extra APIs to help distinguish users' environments and to do some version-specific logic. + +### `isVue2` `isVue3` + +```ts +import { isVue2, isVue3 } from 'vue-demi' + +if (isVue2) { + // Vue 2 only +} else { + // Vue 3 only +} +``` + +### `Vue2` + +To avoid bringing in all the tree-shakable modules, we provide a `Vue2` export to support access to Vue 2's global API. (See [#41](https://github.com/vueuse/vue-demi/issues/41).) + +```ts +import { Vue2 } from 'vue-demi' + +if (Vue2) { + Vue2.config.ignoredElements.push('x-foo') +} +``` + +### `install()` + +Composition API in Vue 2 is provided as a plugin and needs to be installed on the Vue instance before using. Normally, `vue-demi` will try to install it automatically. For some usages where you might need to ensure the plugin gets installed correctly, the `install()` API is exposed to as a safe version of `Vue.use(CompositionAPI)`. `install()` in the Vue 3 environment will be an empty function (no-op). + +```ts +import { install } from 'vue-demi' + +install() +``` + +## CLI + +### Manually Switch Versions + +To explicitly switch the redirecting version, you can use these commands in your project's root. + +```bash +npx vue-demi-switch 2 +# or +npx vue-demi-switch 3 +``` + +### Package Aliasing + +If you would like to import `vue` under an alias, you can use the following command + +```bash +npx vue-demi-switch 2 vue2 +# or +npx vue-demi-switch 3 vue3 +``` + +Then `vue-demi` will redirect APIs from the alias name you specified, for example: + +```ts +import * as Vue from 'vue3' + +var isVue2 = false +var isVue3 = true +var Vue2 = undefined + +export * from 'vue3' +export { + Vue, + Vue2, + isVue2, + isVue3, +} +``` + +### Auto Fix + +If the `postinstall` hook doesn't get triggered or you have updated the Vue version, try to run the following command to resolve the redirecting. + +```bash +npx vue-demi-fix +``` + +### Isomorphic Testings + +You can support testing for both versions by adding npm alias in your dev dependencies. For example: + +```json +{ + "scripts": { + "test:2": "vue-demi-switch 2 vue2 && jest", + "test:3": "vue-demi-switch 3 && jest", + }, + "devDependencies": { + "vue": "^3.0.0", + "vue2": "npm:vue@2" + }, +} +``` + +or + +```json +{ + "scripts": { + "test:2": "vue-demi-switch 2 && jest", + "test:3": "vue-demi-switch 3 vue3 && jest", + }, + "devDependencies": { + "vue": "^2.6.0", + "vue3": "npm:vue@3" + }, +} +``` + +## Examples + +See [examples](./examples). + +## Who is using this? + +- [VueUse](https://github.com/vueuse/vueuse) - Collection of Composition API utils +- [@vue/apollo-composable](https://github.com/vuejs/vue-apollo/tree/v4/packages/vue-apollo-composable) - Apollo GraphQL functions for Vue Composition API +- [vuelidate](https://github.com/vuelidate/vuelidate) - Simple, lightweight model-based validation +- [vue-composition-test-utils](https://github.com/ariesjia/vue-composition-test-utils) - Simple vue composition api unit test utilities +- [vue-use-stripe](https://github.com/frandiox/vue-use-stripe) - Stripe Elements wrapper for Vue.js +- [@opd/g2plot-vue](https://github.com/open-data-plan/g2plot-vue) - G2plot for vue +- [vue-echarts](https://github.com/ecomfe/vue-echarts) - Vue.js component for Apache ECharts. +- [fluent-vue](https://github.com/Demivan/fluent-vue) - Vue.js integration for [Fluent.js](https://github.com/projectfluent/fluent.js) - JavaScript implementation of [Project Fluent](https://projectfluent.org) +- [vue-datatable-url-sync](https://github.com/socotecio/vue-datatable-url-sync) - Synchronize datatable options and filters with the url to keep user preference even after refresh or navigation +- [vue-insta-stories](https://github.com/UnevenSoftware/vue-insta-stories) - Instagram stories in your vue projects. +- [vue-tiny-validate](https://github.com/FrontLabsOfficial/vue-tiny-validate) - Tiny Vue Validate Composition +- [v-perfect-signature](https://github.com/wobsoriano/v-perfect-signature) - Pressure-sensitive signature drawing for Vue 2 and 3 +- [vue-winbox](https://github.com/wobsoriano/vue-winbox) - A wrapper component for WinBox.js that adds the ability to mount Vue components. +- [vue-word-highlighter](https://github.com/kawamataryo/vue-word-highlighter) - The word highlighter library for Vue 2 and Vue 3 +- [vue-chart-3](https://github.com/victorgarciaesgi/vue-chart-3) - Vue.js component for Chart.js +- [json-editor-vue](https://github.com/cloydlau/json-editor-vue) - JSON editor & viewer for Vue 2 and 3. +- [kidar-echarts](https://github.com/kidarjs/kidar-echarts) - A simpler echarts component for Vue 2 and 3. +- [vue3-sketch-ruler](https://github.com/kakajun/vue3-sketch-ruler) - The zoom operation used for page presentation for Vue 2 and 3( Replace render function with template ) +- [vue-rough-notation](https://github.com/Leecason/vue-rough-notation) - RoughNotation wrapper component for Vue 2 and 3. +- [vue-request](https://github.com/AttoJS/vue-request) - Vue composition API for data fetching, supports SWR, polling, error retry, cache request, pagination, etc. +- [vue3-lazyload](https://github.com/murongg/vue3-lazyload) - A vue3.x image lazyload plugin. +- [vue-codemirror6](https://github.com/logue/vue-codemirror6) - CodeMirror6 component for Vue2 and 3. +> open a PR to add your library ;) + +## Underhood + +See [the blog post](https://antfu.me/posts/make-libraries-working-with-vue-2-and-3/#-introducing-vue-demi). + +## License + +MIT License © 2020 [Anthony Fu](https://github.com/antfu) diff --git a/node_modules/vue-demi/bin/vue-demi-fix.js b/node_modules/vue-demi/bin/vue-demi-fix.js new file mode 100644 index 0000000..684a621 --- /dev/null +++ b/node_modules/vue-demi/bin/vue-demi-fix.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node +'use strict' +require('../scripts/postinstall') diff --git a/node_modules/vue-demi/bin/vue-demi-switch.js b/node_modules/vue-demi/bin/vue-demi-switch.js new file mode 100644 index 0000000..360eada --- /dev/null +++ b/node_modules/vue-demi/bin/vue-demi-switch.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node +'use strict' +require('../scripts/switch-cli') diff --git a/node_modules/vue-demi/lib/index.cjs b/node_modules/vue-demi/lib/index.cjs new file mode 100644 index 0000000..5f873d2 --- /dev/null +++ b/node_modules/vue-demi/lib/index.cjs @@ -0,0 +1,32 @@ +var Vue = require('vue') +var VueCompositionAPI = require('@vue/composition-api') + +function install(_vue) { + var vueLib = _vue || Vue + if (vueLib && 'default' in vueLib) { + vueLib = vueLib.default + } + + if (vueLib && !vueLib['__composition_api_installed__']) { + if (VueCompositionAPI && 'default' in VueCompositionAPI) + vueLib.use(VueCompositionAPI.default) + else if (VueCompositionAPI) + vueLib.use(VueCompositionAPI) + } +} + +install(Vue) + +Object.keys(VueCompositionAPI).forEach(function(key) { + exports[key] = VueCompositionAPI[key] +}) + +exports.Vue = Vue +exports.Vue2 = Vue +exports.isVue2 = true +exports.isVue3 = false +exports.install = install +exports.version = Vue.version + +// Not implemented https://github.com/vuejs/core/pull/8111, falls back to getCurrentInstance() +exports.hasInjectionContext = () => !!VueCompositionAPI.getCurrentInstance() diff --git a/node_modules/vue-demi/lib/index.d.ts b/node_modules/vue-demi/lib/index.d.ts new file mode 100644 index 0000000..bbdcbc5 --- /dev/null +++ b/node_modules/vue-demi/lib/index.d.ts @@ -0,0 +1,33 @@ +import Vue from 'vue' +import type { PluginFunction, PluginObject } from 'vue' +declare const isVue2: boolean +declare const isVue3: boolean +declare const Vue2: typeof Vue | undefined +declare const version: string +declare const install: (vue?: typeof Vue) => void +/** + * @deprecated To avoid bringing in all the tree-shakable modules, this API has been deprecated. Use `Vue2` or named exports instead. + * Refer to https://github.com/vueuse/vue-demi/issues/41 + */ +declare const V: typeof Vue + +/** + * DebuggerEvent is a Vue 3 development only feature. This type cannot exist in Vue 2. + */ +export declare type DebuggerEvent = never + +// accept no generic because Vue 3 doesn't accept any +// https://github.com/vuejs/vue-next/pull/2758/ +export declare type Plugin = PluginObject | PluginFunction +export type { VNode } from 'vue' +export * from '@vue/composition-api' +export { + V as Vue, + Vue2, + isVue2, + isVue3, + version, + install, +} + +export declare function hasInjectionContext(): boolean diff --git a/node_modules/vue-demi/lib/index.iife.js b/node_modules/vue-demi/lib/index.iife.js new file mode 100644 index 0000000..2179268 --- /dev/null +++ b/node_modules/vue-demi/lib/index.iife.js @@ -0,0 +1,115 @@ +var VueDemi = (function (VueDemi, Vue, VueCompositionAPI) { + if (VueDemi.install) { + return VueDemi + } + if (!Vue) { + console.error('[vue-demi] no Vue instance found, please be sure to import `vue` before `vue-demi`.') + return VueDemi + } + + // Vue 2.7 + if (Vue.version.slice(0, 4) === '2.7.') { + for (var key in Vue) { + VueDemi[key] = Vue[key] + } + VueDemi.isVue2 = true + VueDemi.isVue3 = false + VueDemi.install = function () {} + VueDemi.Vue = Vue + VueDemi.Vue2 = Vue + VueDemi.version = Vue.version + VueDemi.warn = Vue.util.warn + VueDemi.hasInjectionContext = () => !!VueDemi.getCurrentInstance() + function createApp(rootComponent, rootProps) { + var vm + var provide = {} + var app = { + config: Vue.config, + use: Vue.use.bind(Vue), + mixin: Vue.mixin.bind(Vue), + component: Vue.component.bind(Vue), + provide: function (key, value) { + provide[key] = value + return this + }, + directive: function (name, dir) { + if (dir) { + Vue.directive(name, dir) + return app + } else { + return Vue.directive(name) + } + }, + mount: function (el, hydrating) { + if (!vm) { + vm = new Vue(Object.assign({ propsData: rootProps }, rootComponent, { provide: Object.assign(provide, rootComponent.provide) })) + vm.$mount(el, hydrating) + return vm + } else { + return vm + } + }, + unmount: function () { + if (vm) { + vm.$destroy() + vm = undefined + } + }, + } + return app + } + VueDemi.createApp = createApp + } + // Vue 2.6.x + else if (Vue.version.slice(0, 2) === '2.') { + if (VueCompositionAPI) { + for (var key in VueCompositionAPI) { + VueDemi[key] = VueCompositionAPI[key] + } + VueDemi.isVue2 = true + VueDemi.isVue3 = false + VueDemi.install = function () {} + VueDemi.Vue = Vue + VueDemi.Vue2 = Vue + VueDemi.version = Vue.version + VueDemi.hasInjectionContext = () => !!VueDemi.getCurrentInstance() + } else { + console.error('[vue-demi] no VueCompositionAPI instance found, please be sure to import `@vue/composition-api` before `vue-demi`.') + } + } + // Vue 3 + else if (Vue.version.slice(0, 2) === '3.') { + for (var key in Vue) { + VueDemi[key] = Vue[key] + } + VueDemi.isVue2 = false + VueDemi.isVue3 = true + VueDemi.install = function () {} + VueDemi.Vue = Vue + VueDemi.Vue2 = undefined + VueDemi.version = Vue.version + VueDemi.set = function (target, key, val) { + if (Array.isArray(target)) { + target.length = Math.max(target.length, key) + target.splice(key, 1, val) + return val + } + target[key] = val + return val + } + VueDemi.del = function (target, key) { + if (Array.isArray(target)) { + target.splice(key, 1) + return + } + delete target[key] + } + } else { + console.error('[vue-demi] Vue version ' + Vue.version + ' is unsupported.') + } + return VueDemi +})( + (this.VueDemi = this.VueDemi || (typeof VueDemi !== 'undefined' ? VueDemi : {})), + this.Vue || (typeof Vue !== 'undefined' ? Vue : undefined), + this.VueCompositionAPI || (typeof VueCompositionAPI !== 'undefined' ? VueCompositionAPI : undefined) +); diff --git a/node_modules/vue-demi/lib/index.mjs b/node_modules/vue-demi/lib/index.mjs new file mode 100644 index 0000000..2c18122 --- /dev/null +++ b/node_modules/vue-demi/lib/index.mjs @@ -0,0 +1,49 @@ +import Vue from 'vue' +import VueCompositionAPI, { getCurrentInstance } from '@vue/composition-api/dist/vue-composition-api.mjs' + +function install(_vue) { + _vue = _vue || Vue + if (_vue && !_vue['__composition_api_installed__']) + _vue.use(VueCompositionAPI) +} + +install(Vue) + +var isVue2 = true +var isVue3 = false +var Vue2 = Vue +var version = Vue.version + +/**VCA-EXPORTS**/ +export * from '@vue/composition-api/dist/vue-composition-api.mjs' +/**VCA-EXPORTS**/ + +export { + Vue, + Vue2, + isVue2, + isVue3, + version, + install, +} + + +// Vue 3 components mock +function createMockComponent(name) { + return { + setup() { + throw new Error('[vue-demi] ' + name + ' is not supported in Vue 2. It\'s provided to avoid compiler errors.') + } + } +} +export var Fragment = /*#__PURE__*/ createMockComponent('Fragment') +export var Transition = /*#__PURE__*/ createMockComponent('Transition') +export var TransitionGroup = /*#__PURE__*/ createMockComponent('TransitionGroup') +export var Teleport = /*#__PURE__*/ createMockComponent('Teleport') +export var Suspense = /*#__PURE__*/ createMockComponent('Suspense') +export var KeepAlive = /*#__PURE__*/ createMockComponent('KeepAlive') + +// Not implemented https://github.com/vuejs/core/pull/8111, falls back to getCurrentInstance() +export function hasInjectionContext() { + return !!getCurrentInstance() +} diff --git a/node_modules/vue-demi/lib/v2.7/index.cjs b/node_modules/vue-demi/lib/v2.7/index.cjs new file mode 100644 index 0000000..1dce010 --- /dev/null +++ b/node_modules/vue-demi/lib/v2.7/index.cjs @@ -0,0 +1,58 @@ +var VueModule = require('vue') + +// get the real Vue https://github.com/vueuse/vue-demi/issues/192 +var Vue = VueModule.default || VueModule + +exports.Vue = Vue +exports.Vue2 = Vue +exports.isVue2 = true +exports.isVue3 = false +exports.install = function () {} +exports.warn = Vue.util.warn + +// createApp polyfill +exports.createApp = function (rootComponent, rootProps) { + var vm + var provide = {} + var app = { + config: Vue.config, + use: Vue.use.bind(Vue), + mixin: Vue.mixin.bind(Vue), + component: Vue.component.bind(Vue), + provide: function (key, value) { + provide[key] = value + return this + }, + directive: function (name, dir) { + if (dir) { + Vue.directive(name, dir) + return app + } else { + return Vue.directive(name) + } + }, + mount: function (el, hydrating) { + if (!vm) { + vm = new Vue(Object.assign({ propsData: rootProps }, rootComponent, { provide: Object.assign(provide, rootComponent.provide) })) + vm.$mount(el, hydrating) + return vm + } else { + return vm + } + }, + unmount: function () { + if (vm) { + vm.$destroy() + vm = undefined + } + }, + } + return app +} + +Object.keys(VueModule).forEach(function (key) { + exports[key] = VueModule[key] +}) + +// Not implemented https://github.com/vuejs/core/pull/8111, falls back to getCurrentInstance() +exports.hasInjectionContext = () => !!VueModule.getCurrentInstance() diff --git a/node_modules/vue-demi/lib/v2.7/index.d.ts b/node_modules/vue-demi/lib/v2.7/index.d.ts new file mode 100644 index 0000000..827c7b2 --- /dev/null +++ b/node_modules/vue-demi/lib/v2.7/index.d.ts @@ -0,0 +1,38 @@ +import Vue from 'vue' +import type { PluginFunction, PluginObject, VueConstructor, Directive, InjectionKey, Component } from 'vue' + +declare const isVue2: boolean +declare const isVue3: boolean +declare const Vue2: typeof Vue | undefined +declare const version: string +declare const install: (vue?: typeof Vue) => void +export declare function warn(msg: string, vm?: Component | null): void +/** + * @deprecated To avoid bringing in all the tree-shakable modules, this API has been deprecated. Use `Vue2` or named exports instead. + * Refer to https://github.com/vueuse/vue-demi/issues/41 + */ +declare const V: typeof Vue + +// accept no generic because Vue 3 doesn't accept any +// https://github.com/vuejs/vue-next/pull/2758/ +export declare type Plugin = PluginObject | PluginFunction +export type { VNode } from 'vue' +export * from 'vue' +export { V as Vue, Vue2, isVue2, isVue3, version, install } + +// #region createApp polyfill +export interface App { + config: VueConstructor['config'] + use: VueConstructor['use'] + mixin: VueConstructor['mixin'] + component: VueConstructor['component'] + directive(name: string): Directive | undefined + directive(name: string, directive: Directive): this + provide(key: InjectionKey | string, value: T): this + mount: Vue['$mount'] + unmount: Vue['$destroy'] +} +export declare function createApp(rootComponent: any, rootProps?: any): App +// #endregion + +export declare function hasInjectionContext(): boolean diff --git a/node_modules/vue-demi/lib/v2.7/index.mjs b/node_modules/vue-demi/lib/v2.7/index.mjs new file mode 100644 index 0000000..e575059 --- /dev/null +++ b/node_modules/vue-demi/lib/v2.7/index.mjs @@ -0,0 +1,80 @@ +import Vue from 'vue' +import { getCurrentInstance } from 'vue' + +var isVue2 = true +var isVue3 = false +var Vue2 = Vue +var warn = Vue.util.warn + +function install() {} + +// createApp polyfill +export function createApp(rootComponent, rootProps) { + var vm + var provide = {} + var app = { + config: Vue.config, + use: Vue.use.bind(Vue), + mixin: Vue.mixin.bind(Vue), + component: Vue.component.bind(Vue), + provide: function (key, value) { + provide[key] = value + return this + }, + directive: function (name, dir) { + if (dir) { + Vue.directive(name, dir) + return app + } else { + return Vue.directive(name) + } + }, + mount: function (el, hydrating) { + if (!vm) { + vm = new Vue(Object.assign({ propsData: rootProps }, rootComponent, { provide: Object.assign(provide, rootComponent.provide) })) + vm.$mount(el, hydrating) + return vm + } else { + return vm + } + }, + unmount: function () { + if (vm) { + vm.$destroy() + vm = undefined + } + }, + } + return app +} + +export { + Vue, + Vue2, + isVue2, + isVue3, + install, + warn +} + +// Vue 3 components mock +function createMockComponent(name) { + return { + setup() { + throw new Error('[vue-demi] ' + name + ' is not supported in Vue 2. It\'s provided to avoid compiler errors.') + } + } +} +export var Fragment = /*#__PURE__*/ createMockComponent('Fragment') +export var Transition = /*#__PURE__*/ createMockComponent('Transition') +export var TransitionGroup = /*#__PURE__*/ createMockComponent('TransitionGroup') +export var Teleport = /*#__PURE__*/ createMockComponent('Teleport') +export var Suspense = /*#__PURE__*/ createMockComponent('Suspense') +export var KeepAlive = /*#__PURE__*/ createMockComponent('KeepAlive') + +export * from 'vue' + +// Not implemented https://github.com/vuejs/core/pull/8111, falls back to getCurrentInstance() +export function hasInjectionContext() { + return !!getCurrentInstance() +} diff --git a/node_modules/vue-demi/lib/v2/index.cjs b/node_modules/vue-demi/lib/v2/index.cjs new file mode 100644 index 0000000..5f873d2 --- /dev/null +++ b/node_modules/vue-demi/lib/v2/index.cjs @@ -0,0 +1,32 @@ +var Vue = require('vue') +var VueCompositionAPI = require('@vue/composition-api') + +function install(_vue) { + var vueLib = _vue || Vue + if (vueLib && 'default' in vueLib) { + vueLib = vueLib.default + } + + if (vueLib && !vueLib['__composition_api_installed__']) { + if (VueCompositionAPI && 'default' in VueCompositionAPI) + vueLib.use(VueCompositionAPI.default) + else if (VueCompositionAPI) + vueLib.use(VueCompositionAPI) + } +} + +install(Vue) + +Object.keys(VueCompositionAPI).forEach(function(key) { + exports[key] = VueCompositionAPI[key] +}) + +exports.Vue = Vue +exports.Vue2 = Vue +exports.isVue2 = true +exports.isVue3 = false +exports.install = install +exports.version = Vue.version + +// Not implemented https://github.com/vuejs/core/pull/8111, falls back to getCurrentInstance() +exports.hasInjectionContext = () => !!VueCompositionAPI.getCurrentInstance() diff --git a/node_modules/vue-demi/lib/v2/index.d.ts b/node_modules/vue-demi/lib/v2/index.d.ts new file mode 100644 index 0000000..bbdcbc5 --- /dev/null +++ b/node_modules/vue-demi/lib/v2/index.d.ts @@ -0,0 +1,33 @@ +import Vue from 'vue' +import type { PluginFunction, PluginObject } from 'vue' +declare const isVue2: boolean +declare const isVue3: boolean +declare const Vue2: typeof Vue | undefined +declare const version: string +declare const install: (vue?: typeof Vue) => void +/** + * @deprecated To avoid bringing in all the tree-shakable modules, this API has been deprecated. Use `Vue2` or named exports instead. + * Refer to https://github.com/vueuse/vue-demi/issues/41 + */ +declare const V: typeof Vue + +/** + * DebuggerEvent is a Vue 3 development only feature. This type cannot exist in Vue 2. + */ +export declare type DebuggerEvent = never + +// accept no generic because Vue 3 doesn't accept any +// https://github.com/vuejs/vue-next/pull/2758/ +export declare type Plugin = PluginObject | PluginFunction +export type { VNode } from 'vue' +export * from '@vue/composition-api' +export { + V as Vue, + Vue2, + isVue2, + isVue3, + version, + install, +} + +export declare function hasInjectionContext(): boolean diff --git a/node_modules/vue-demi/lib/v2/index.mjs b/node_modules/vue-demi/lib/v2/index.mjs new file mode 100644 index 0000000..2c18122 --- /dev/null +++ b/node_modules/vue-demi/lib/v2/index.mjs @@ -0,0 +1,49 @@ +import Vue from 'vue' +import VueCompositionAPI, { getCurrentInstance } from '@vue/composition-api/dist/vue-composition-api.mjs' + +function install(_vue) { + _vue = _vue || Vue + if (_vue && !_vue['__composition_api_installed__']) + _vue.use(VueCompositionAPI) +} + +install(Vue) + +var isVue2 = true +var isVue3 = false +var Vue2 = Vue +var version = Vue.version + +/**VCA-EXPORTS**/ +export * from '@vue/composition-api/dist/vue-composition-api.mjs' +/**VCA-EXPORTS**/ + +export { + Vue, + Vue2, + isVue2, + isVue3, + version, + install, +} + + +// Vue 3 components mock +function createMockComponent(name) { + return { + setup() { + throw new Error('[vue-demi] ' + name + ' is not supported in Vue 2. It\'s provided to avoid compiler errors.') + } + } +} +export var Fragment = /*#__PURE__*/ createMockComponent('Fragment') +export var Transition = /*#__PURE__*/ createMockComponent('Transition') +export var TransitionGroup = /*#__PURE__*/ createMockComponent('TransitionGroup') +export var Teleport = /*#__PURE__*/ createMockComponent('Teleport') +export var Suspense = /*#__PURE__*/ createMockComponent('Suspense') +export var KeepAlive = /*#__PURE__*/ createMockComponent('KeepAlive') + +// Not implemented https://github.com/vuejs/core/pull/8111, falls back to getCurrentInstance() +export function hasInjectionContext() { + return !!getCurrentInstance() +} diff --git a/node_modules/vue-demi/lib/v3/index.cjs b/node_modules/vue-demi/lib/v3/index.cjs new file mode 100644 index 0000000..8197f90 --- /dev/null +++ b/node_modules/vue-demi/lib/v3/index.cjs @@ -0,0 +1,29 @@ +var Vue = require('vue') + +Object.keys(Vue).forEach(function(key) { + exports[key] = Vue[key] +}) + +exports.set = function(target, key, val) { + if (Array.isArray(target)) { + target.length = Math.max(target.length, key) + target.splice(key, 1, val) + return val + } + target[key] = val + return val +} + +exports.del = function(target, key) { + if (Array.isArray(target)) { + target.splice(key, 1) + return + } + delete target[key] +} + +exports.Vue = Vue +exports.Vue2 = undefined +exports.isVue2 = false +exports.isVue3 = true +exports.install = function(){} diff --git a/node_modules/vue-demi/lib/v3/index.d.ts b/node_modules/vue-demi/lib/v3/index.d.ts new file mode 100644 index 0000000..897b4c5 --- /dev/null +++ b/node_modules/vue-demi/lib/v3/index.d.ts @@ -0,0 +1,22 @@ +import * as Vue from 'vue' +declare const isVue2: boolean +declare const isVue3: boolean +declare const Vue2: any +declare const install: (vue?: any) => void +/** + * @deprecated To avoid bringing in all the tree-shakable modules, this API has been deprecated. Use `Vue2` or named exports instead. + * Refer to https://github.com/vueuse/vue-demi/issues/41 + */ +declare const V: typeof Vue + +export function set(target: any, key: any, val: T): T +export function del(target: any, key: any): void + +export * from 'vue' +export { + V as Vue, + Vue2, + isVue2, + isVue3, + install, +} diff --git a/node_modules/vue-demi/lib/v3/index.mjs b/node_modules/vue-demi/lib/v3/index.mjs new file mode 100644 index 0000000..be3a96d --- /dev/null +++ b/node_modules/vue-demi/lib/v3/index.mjs @@ -0,0 +1,34 @@ +import * as Vue from 'vue' + +var isVue2 = false +var isVue3 = true +var Vue2 = undefined + +function install() {} + +export function set(target, key, val) { + if (Array.isArray(target)) { + target.length = Math.max(target.length, key) + target.splice(key, 1, val) + return val + } + target[key] = val + return val +} + +export function del(target, key) { + if (Array.isArray(target)) { + target.splice(key, 1) + return + } + delete target[key] +} + +export * from 'vue' +export { + Vue, + Vue2, + isVue2, + isVue3, + install, +} diff --git a/node_modules/vue-demi/package.json b/node_modules/vue-demi/package.json new file mode 100644 index 0000000..27e4dfc --- /dev/null +++ b/node_modules/vue-demi/package.json @@ -0,0 +1,47 @@ +{ + "name": "vue-demi", + "version": "0.14.6", + "engines": { + "node": ">=12" + }, + "repository": "https://github.com/antfu/vue-demi.git", + "funding": "https://github.com/sponsors/antfu", + "license": "MIT", + "author": "Anthony Fu ", + "main": "lib/index.cjs", + "jsdelivr": "lib/index.iife.js", + "unpkg": "lib/index.iife.js", + "module": "lib/index.mjs", + "types": "lib/index.d.ts", + "exports": { + ".": { + "types": "./lib/index.d.ts", + "require": "./lib/index.cjs", + "import": "./lib/index.mjs", + "browser": "./lib/index.mjs" + }, + "./*": "./*" + }, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "files": [ + "lib", + "bin", + "scripts" + ], + "scripts": { + "postinstall": "node ./scripts/postinstall.js", + "release": "npx bumpp --tag --commit --push && npm publish" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } +} diff --git a/node_modules/vue-demi/scripts/postinstall.js b/node_modules/vue-demi/scripts/postinstall.js new file mode 100644 index 0000000..62484ec --- /dev/null +++ b/node_modules/vue-demi/scripts/postinstall.js @@ -0,0 +1,19 @@ +const { switchVersion, loadModule } = require('./utils') + +const Vue = loadModule('vue') + +if (!Vue || typeof Vue.version !== 'string') { + console.warn('[vue-demi] Vue is not found. Please run "npm install vue" to install.') +} +else if (Vue.version.startsWith('2.7.')) { + switchVersion(2.7) +} +else if (Vue.version.startsWith('2.')) { + switchVersion(2) +} +else if (Vue.version.startsWith('3.')) { + switchVersion(3) +} +else { + console.warn(`[vue-demi] Vue version v${Vue.version} is not suppported.`) +} diff --git a/node_modules/vue-demi/scripts/switch-cli.js b/node_modules/vue-demi/scripts/switch-cli.js new file mode 100644 index 0000000..3c104ca --- /dev/null +++ b/node_modules/vue-demi/scripts/switch-cli.js @@ -0,0 +1,18 @@ +const { switchVersion } = require('./utils') + +const version = process.argv[2] +const vueEntry = process.argv[3] || 'vue' + +if (version === '2.7') { + switchVersion(2.7, vueEntry) + console.log(`[vue-demi] Switched for Vue 2.7 (entry: "${vueEntry}")`) +} else if (version === '2') { + switchVersion(2, vueEntry) + console.log(`[vue-demi] Switched for Vue 2 (entry: "${vueEntry}")`) +} else if (version === '3') { + switchVersion(3, vueEntry) + console.log(`[vue-demi] Switched for Vue 3 (entry: "${vueEntry}")`) +} else { + console.warn(`[vue-demi] expecting version "2" or "2.7" or "3" but got "${version}"`) + process.exit(1) +} diff --git a/node_modules/vue-demi/scripts/utils.js b/node_modules/vue-demi/scripts/utils.js new file mode 100644 index 0000000..eff99f0 --- /dev/null +++ b/node_modules/vue-demi/scripts/utils.js @@ -0,0 +1,62 @@ +const fs = require('fs') +const path = require('path') + +const dir = path.resolve(__dirname, '..', 'lib') + +function loadModule(name) { + try { + return require(name) + } catch (e) { + return undefined + } +} + +function copy(name, version, vue) { + vue = vue || 'vue' + const src = path.join(dir, `v${version}`, name) + const dest = path.join(dir, name) + let content = fs.readFileSync(src, 'utf-8') + content = content.replace(/'vue'/g, `'${vue}'`) + // unlink for pnpm, #92 + try { + fs.unlinkSync(dest) + } catch (error) { } + fs.writeFileSync(dest, content, 'utf-8') +} + +function updateVue2API() { + const ignoreList = ['version', 'default'] + const VCA = loadModule('@vue/composition-api') + if (!VCA) { + console.warn('[vue-demi] Composition API plugin is not found. Please run "npm install @vue/composition-api" to install.') + return + } + + const exports = Object.keys(VCA).filter(i => !ignoreList.includes(i)) + + const esmPath = path.join(dir, 'index.mjs') + let content = fs.readFileSync(esmPath, 'utf-8') + + content = content.replace( + /\/\*\*VCA-EXPORTS\*\*\/[\s\S]+\/\*\*VCA-EXPORTS\*\*\//m, +`/**VCA-EXPORTS**/ +export { ${exports.join(', ')} } from '@vue/composition-api/dist/vue-composition-api.mjs' +/**VCA-EXPORTS**/` + ) + + fs.writeFileSync(esmPath, content, 'utf-8') + +} + +function switchVersion(version, vue) { + copy('index.cjs', version, vue) + copy('index.mjs', version, vue) + copy('index.d.ts', version, vue) + + if (version === 2) + updateVue2API() +} + + +module.exports.loadModule = loadModule +module.exports.switchVersion = switchVersion diff --git a/node_modules/vue/LICENSE b/node_modules/vue/LICENSE new file mode 100644 index 0000000..b65dd9e --- /dev/null +++ b/node_modules/vue/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-present, Yuxi (Evan) You + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/vue/README.md b/node_modules/vue/README.md new file mode 100644 index 0000000..862d58f --- /dev/null +++ b/node_modules/vue/README.md @@ -0,0 +1,386 @@ +

Vue logo

+ +

+ Build Status + Coverage Status + Downloads + Version + License + Chat +
+ Build Status +

+ +

Supporting Vue.js

+ +Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/vue/blob/dev/BACKERS.md). If you'd like to join them, please consider: + +- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou). +- [Become a backer or sponsor on Open Collective](https://opencollective.com/vuejs). +- [One-time donation via PayPal or crypto-currencies](https://vuejs.org/support-vuejs/#One-time-Donations). + +#### What's the difference between Patreon and OpenCollective? + +Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform. + +

Special Sponsors

+ + +

+ + + +

+ + + +

Platinum Sponsors

+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + +

Platinum Sponsors (China)

+ + + + + + +
+ + + +
+ + +

Gold Sponsors

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + +

Sponsors via Open Collective

+ +

Platinum

+ + + + +

Gold

+ + + + + + + + + + + + +--- + +## Introduction + +Vue (pronounced `/vjuː/`, like view) is a **progressive framework** for building user interfaces. It is designed from the ground up to be incrementally adoptable, and can easily scale between a library and a framework depending on different use cases. It consists of an approachable core library that focuses on the view layer only, and an ecosystem of supporting libraries that helps you tackle complexity in large Single-Page Applications. + +#### Browser Compatibility + +Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/compat-table/es5/) (IE8 and below are not supported). + +## Ecosystem + +| Project | Status | Description | +|---------|--------|-------------| +| [vue-router] | [![vue-router-status]][vue-router-package] | Single-page application routing | +| [vuex] | [![vuex-status]][vuex-package] | Large-scale state management | +| [vue-cli] | [![vue-cli-status]][vue-cli-package] | Project scaffolding | +| [vue-loader] | [![vue-loader-status]][vue-loader-package] | Single File Component (`*.vue` file) loader for webpack | +| [vue-server-renderer] | [![vue-server-renderer-status]][vue-server-renderer-package] | Server-side rendering support | +| [vue-class-component] | [![vue-class-component-status]][vue-class-component-package] | TypeScript decorator for a class-based API | +| [vue-rx] | [![vue-rx-status]][vue-rx-package] | RxJS integration | +| [vue-devtools] | [![vue-devtools-status]][vue-devtools-package] | Browser DevTools extension | + +[vue-router]: https://github.com/vuejs/vue-router +[vuex]: https://github.com/vuejs/vuex +[vue-cli]: https://github.com/vuejs/vue-cli +[vue-loader]: https://github.com/vuejs/vue-loader +[vue-server-renderer]: https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer +[vue-class-component]: https://github.com/vuejs/vue-class-component +[vue-rx]: https://github.com/vuejs/vue-rx +[vue-devtools]: https://github.com/vuejs/vue-devtools + +[vue-router-status]: https://img.shields.io/npm/v/vue-router.svg +[vuex-status]: https://img.shields.io/npm/v/vuex.svg +[vue-cli-status]: https://img.shields.io/npm/v/@vue/cli.svg +[vue-loader-status]: https://img.shields.io/npm/v/vue-loader.svg +[vue-server-renderer-status]: https://img.shields.io/npm/v/vue-server-renderer.svg +[vue-class-component-status]: https://img.shields.io/npm/v/vue-class-component.svg +[vue-rx-status]: https://img.shields.io/npm/v/vue-rx.svg +[vue-devtools-status]: https://img.shields.io/chrome-web-store/v/nhdogjmejiglipccpnnnanhbledajbpd.svg + +[vue-router-package]: https://npmjs.com/package/vue-router +[vuex-package]: https://npmjs.com/package/vuex +[vue-cli-package]: https://npmjs.com/package/@vue/cli +[vue-loader-package]: https://npmjs.com/package/vue-loader +[vue-server-renderer-package]: https://npmjs.com/package/vue-server-renderer +[vue-class-component-package]: https://npmjs.com/package/vue-class-component +[vue-rx-package]: https://npmjs.com/package/vue-rx +[vue-devtools-package]: https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd + +## Documentation + +To check out [live examples](https://vuejs.org/v2/examples/) and docs, visit [vuejs.org](https://vuejs.org). + +## Questions + +For questions and support please use [the official forum](https://forum.vuejs.org) or [community chat](https://chat.vuejs.org/). The issue list of this repo is **exclusively** for bug reports and feature requests. + +## Issues + +Please make sure to read the [Issue Reporting Checklist](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately. + +## Changelog + +Detailed changes for each release are documented in the [release notes](https://github.com/vuejs/vue/releases). + +## Stay In Touch + +- [Twitter](https://twitter.com/vuejs) +- [Blog](https://medium.com/the-vue-point) +- [Job Board](https://vuejobs.com/?ref=vuejs) + +## Contribution + +Please make sure to read the [Contributing Guide](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md) before making a pull request. If you have a Vue-related project/component/tool, add it with a pull request to [this curated list](https://github.com/vuejs/awesome-vue)! + +Thank you to all the people who already contributed to Vue! + + + + +## License + +[MIT](https://opensource.org/licenses/MIT) + +Copyright (c) 2013-present, Yuxi (Evan) You diff --git a/node_modules/vue/dist/README.md b/node_modules/vue/dist/README.md new file mode 100644 index 0000000..19386ec --- /dev/null +++ b/node_modules/vue/dist/README.md @@ -0,0 +1,122 @@ +## Explanation of Build Files + +| | UMD | CommonJS | ES Module | +| --- | --- | --- | --- | +| **Full** | vue.js | vue.common.js | vue.esm.js | +| **Runtime-only** | vue.runtime.js | vue.runtime.common.js | vue.runtime.esm.js | +| **Full (production)** | vue.min.js | | | +| **Runtime-only (production)** | vue.runtime.min.js | | | + +### Terms + +- **Full**: builds that contain both the compiler and the runtime. + +- **Compiler**: code that is responsible for compiling template strings into JavaScript render functions. + +- **Runtime**: code that is responsible for creating Vue instances, rendering and patching virtual DOM, etc. Basically everything minus the compiler. + +- **[UMD](https://github.com/umdjs/umd)**: UMD builds can be used directly in the browser via a `` + : '' + } + + renderScripts (context: Object): string { + if (this.clientManifest) { + const initial = this.preloadFiles.filter(({ file }) => isJS(file)) + const async = (this.getUsedAsyncFiles(context) || []).filter(({ file }) => isJS(file)) + const needed = [initial[0]].concat(async, initial.slice(1)) + return needed.map(({ file }) => { + return `` + }).join('') + } else { + return '' + } + } + + getUsedAsyncFiles (context: Object): ?Array { + if (!context._mappedFiles && context._registeredComponents && this.mapFiles) { + const registered = Array.from(context._registeredComponents) + context._mappedFiles = this.mapFiles(registered).map(normalizeFile) + } + return context._mappedFiles + } + + // create a transform stream + createStream (context: ?Object): TemplateStream { + if (!this.parsedTemplate) { + throw new Error('createStream cannot be called without a template.') + } + return new TemplateStream(this, this.parsedTemplate, context || {}) + } +} + +function normalizeFile (file: string): Resource { + const withoutQuery = file.replace(/\?.*/, '') + const extension = path.extname(withoutQuery).slice(1) + return { + file, + extension, + fileWithoutQuery: withoutQuery, + asType: getPreloadType(extension) + } +} + +function getPreloadType (ext: string): string { + if (ext === 'js') { + return 'script' + } else if (ext === 'css') { + return 'style' + } else if (/jpe?g|png|svg|gif|webp|ico/.test(ext)) { + return 'image' + } else if (/woff2?|ttf|otf|eot/.test(ext)) { + return 'font' + } else { + // not exhausting all possibilities here, but above covers common cases + return '' + } +} diff --git a/node_modules/vue/src/server/template-renderer/parse-template.js b/node_modules/vue/src/server/template-renderer/parse-template.js new file mode 100644 index 0000000..1ccfe89 --- /dev/null +++ b/node_modules/vue/src/server/template-renderer/parse-template.js @@ -0,0 +1,42 @@ +/* @flow */ + +const compile = require('lodash.template') +const compileOptions = { + escape: /{{([^{][\s\S]+?[^}])}}/g, + interpolate: /{{{([\s\S]+?)}}}/g +} + +export type ParsedTemplate = { + head: (data: any) => string; + neck: (data: any) => string; + tail: (data: any) => string; +}; + +export function parseTemplate ( + template: string, + contentPlaceholder?: string = '' +): ParsedTemplate { + if (typeof template === 'object') { + return template + } + + let i = template.indexOf('') + const j = template.indexOf(contentPlaceholder) + + if (j < 0) { + throw new Error(`Content placeholder not found in template.`) + } + + if (i < 0) { + i = template.indexOf('') + if (i < 0) { + i = j + } + } + + return { + head: compile(template.slice(0, i), compileOptions), + neck: compile(template.slice(i, j), compileOptions), + tail: compile(template.slice(j + contentPlaceholder.length), compileOptions) + } +} diff --git a/node_modules/vue/src/server/template-renderer/template-stream.js b/node_modules/vue/src/server/template-renderer/template-stream.js new file mode 100644 index 0000000..ed4db78 --- /dev/null +++ b/node_modules/vue/src/server/template-renderer/template-stream.js @@ -0,0 +1,82 @@ +/* @flow */ + +const Transform = require('stream').Transform +import type TemplateRenderer from './index' +import type { ParsedTemplate } from './parse-template' + +export default class TemplateStream extends Transform { + started: boolean; + renderer: TemplateRenderer; + template: ParsedTemplate; + context: Object; + inject: boolean; + + constructor ( + renderer: TemplateRenderer, + template: ParsedTemplate, + context: Object + ) { + super() + this.started = false + this.renderer = renderer + this.template = template + this.context = context || {} + this.inject = renderer.inject + } + + _transform (data: Buffer | string, encoding: string, done: Function) { + if (!this.started) { + this.emit('beforeStart') + this.start() + } + this.push(data) + done() + } + + start () { + this.started = true + this.push(this.template.head(this.context)) + + if (this.inject) { + // inline server-rendered head meta information + if (this.context.head) { + this.push(this.context.head) + } + + // inline preload/prefetch directives for initial/async chunks + const links = this.renderer.renderResourceHints(this.context) + if (links) { + this.push(links) + } + + // CSS files and inline server-rendered CSS collected by vue-style-loader + const styles = this.renderer.renderStyles(this.context) + if (styles) { + this.push(styles) + } + } + + this.push(this.template.neck(this.context)) + } + + _flush (done: Function) { + this.emit('beforeEnd') + + if (this.inject) { + // inline initial store state + const state = this.renderer.renderState(this.context) + if (state) { + this.push(state) + } + + // embed scripts needed + const scripts = this.renderer.renderScripts(this.context) + if (scripts) { + this.push(scripts) + } + } + + this.push(this.template.tail(this.context)) + done() + } +} diff --git a/node_modules/vue/src/server/util.js b/node_modules/vue/src/server/util.js new file mode 100644 index 0000000..908f8c9 --- /dev/null +++ b/node_modules/vue/src/server/util.js @@ -0,0 +1,18 @@ +/* @flow */ + +export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file) + +export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file) + +export function createPromiseCallback () { + let resolve, reject + const promise: Promise = new Promise((_resolve, _reject) => { + resolve = _resolve + reject = _reject + }) + const cb = (err: Error, res?: string) => { + if (err) return reject(err) + resolve(res || '') + } + return { promise, cb } +} diff --git a/node_modules/vue/src/server/webpack-plugin/client.js b/node_modules/vue/src/server/webpack-plugin/client.js new file mode 100644 index 0000000..ec7b875 --- /dev/null +++ b/node_modules/vue/src/server/webpack-plugin/client.js @@ -0,0 +1,67 @@ +const hash = require('hash-sum') +const uniq = require('lodash.uniq') +import { isJS, isCSS, getAssetName, onEmit, stripModuleIdHash } from './util' + +export default class VueSSRClientPlugin { + constructor (options = {}) { + this.options = Object.assign({ + filename: 'vue-ssr-client-manifest.json' + }, options) + } + + apply (compiler) { + const stage = 'PROCESS_ASSETS_STAGE_ADDITIONAL' + onEmit(compiler, 'vue-client-plugin', stage, (compilation, cb) => { + const stats = compilation.getStats().toJson() + + const allFiles = uniq(stats.assets + .map(a => a.name)) + + const initialFiles = uniq(Object.keys(stats.entrypoints) + .map(name => stats.entrypoints[name].assets) + .reduce((assets, all) => all.concat(assets), []) + .map(getAssetName) + .filter((file) => isJS(file) || isCSS(file))) + + const asyncFiles = allFiles + .filter((file) => isJS(file) || isCSS(file)) + .filter(file => initialFiles.indexOf(file) < 0) + + const manifest = { + publicPath: stats.publicPath, + all: allFiles, + initial: initialFiles, + async: asyncFiles, + modules: { /* [identifier: string]: Array */ } + } + + const assetModules = stats.modules.filter(m => m.assets.length) + const fileToIndex = asset => manifest.all.indexOf(getAssetName(asset)) + stats.modules.forEach(m => { + // ignore modules duplicated in multiple chunks + if (m.chunks.length === 1) { + const cid = m.chunks[0] + const chunk = stats.chunks.find(c => c.id === cid) + if (!chunk || !chunk.files) { + return + } + const id = stripModuleIdHash(m.identifier) + const files = manifest.modules[hash(id)] = chunk.files.map(fileToIndex) + // find all asset modules associated with the same chunk + assetModules.forEach(m => { + if (m.chunks.some(id => id === cid)) { + files.push.apply(files, m.assets.map(fileToIndex)) + } + }) + } + }) + + const json = JSON.stringify(manifest, null, 2) + compilation.assets[this.options.filename] = { + source: () => json, + size: () => json.length + } + cb() + }) + } +} diff --git a/node_modules/vue/src/server/webpack-plugin/server.js b/node_modules/vue/src/server/webpack-plugin/server.js new file mode 100644 index 0000000..02fab24 --- /dev/null +++ b/node_modules/vue/src/server/webpack-plugin/server.js @@ -0,0 +1,69 @@ +import { validate, isJS, getAssetName, onEmit } from './util' + +export default class VueSSRServerPlugin { + constructor (options = {}) { + this.options = Object.assign({ + filename: 'vue-ssr-server-bundle.json' + }, options) + } + + apply (compiler) { + validate(compiler) + + const stage = 'PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER' + onEmit(compiler, 'vue-server-plugin', stage, (compilation, cb) => { + const stats = compilation.getStats().toJson() + const entryName = Object.keys(stats.entrypoints)[0] + const entryInfo = stats.entrypoints[entryName] + + if (!entryInfo) { + // #5553 + return cb() + } + + const entryAssets = entryInfo.assets + .map(getAssetName) + .filter(isJS) + + if (entryAssets.length > 1) { + throw new Error( + `Server-side bundle should have one single entry file. ` + + `Avoid using CommonsChunkPlugin in the server config.` + ) + } + + const entry = entryAssets[0] + if (!entry || typeof entry !== 'string') { + throw new Error( + `Entry "${entryName}" not found. Did you specify the correct entry option?` + ) + } + + const bundle = { + entry, + files: {}, + maps: {} + } + + Object.keys(compilation.assets).forEach(name => { + if (isJS(name)) { + bundle.files[name] = compilation.assets[name].source() + } else if (name.match(/\.js\.map$/)) { + bundle.maps[name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[name].source()) + } + // do not emit anything else for server + delete compilation.assets[name] + }) + + const json = JSON.stringify(bundle, null, 2) + const filename = this.options.filename + + compilation.assets[filename] = { + source: () => json, + size: () => json.length + } + + cb() + }) + } +} diff --git a/node_modules/vue/src/server/webpack-plugin/util.js b/node_modules/vue/src/server/webpack-plugin/util.js new file mode 100644 index 0000000..844671b --- /dev/null +++ b/node_modules/vue/src/server/webpack-plugin/util.js @@ -0,0 +1,73 @@ +const { red, yellow } = require('chalk') +const webpack = require('webpack') + +const prefix = `[vue-server-renderer-webpack-plugin]` +const warn = exports.warn = msg => console.error(red(`${prefix} ${msg}\n`)) +const tip = exports.tip = msg => console.log(yellow(`${prefix} ${msg}\n`)) + +const isWebpack5 = !!(webpack.version && webpack.version[0] > 4) + +export const validate = compiler => { + if (compiler.options.target !== 'node') { + warn('webpack config `target` should be "node".') + } + + if (compiler.options.output) { + if (compiler.options.output.library) { + // Webpack >= 5.0.0 + if (compiler.options.output.library.type !== 'commonjs2') { + warn('webpack config `output.library.type` should be "commonjs2".') + } + } else if (compiler.options.output.libraryTarget !== 'commonjs2') { + // Webpack < 5.0.0 + warn('webpack config `output.libraryTarget` should be "commonjs2".') + } + } + + if (!compiler.options.externals) { + tip( + 'It is recommended to externalize dependencies in the server build for ' + + 'better build performance.' + ) + } +} + +export const onEmit = (compiler, name, stageName, hook) => { + if (isWebpack5) { + // Webpack >= 5.0.0 + compiler.hooks.compilation.tap(name, compilation => { + if (compilation.compiler !== compiler) { + // Ignore child compilers + return + } + const stage = webpack.Compilation[stageName] + compilation.hooks.processAssets.tapAsync({ name, stage }, (assets, cb) => { + hook(compilation, cb) + }) + }) + } else if (compiler.hooks) { + // Webpack >= 4.0.0 + compiler.hooks.emit.tapAsync(name, hook) + } else { + // Webpack < 4.0.0 + compiler.plugin('emit', hook) + } +} + +export const stripModuleIdHash = id => { + if (isWebpack5) { + // Webpack >= 5.0.0 + return id.replace(/\|\w+$/, '') + } + // Webpack < 5.0.0 + return id.replace(/\s\w+$/, '') +} + +export const getAssetName = asset => { + if (typeof asset === 'string') { + return asset + } + return asset.name +} + +export { isJS, isCSS } from '../util' diff --git a/node_modules/vue/src/server/write.js b/node_modules/vue/src/server/write.js new file mode 100644 index 0000000..27a5e8a --- /dev/null +++ b/node_modules/vue/src/server/write.js @@ -0,0 +1,50 @@ +/* @flow */ + +const MAX_STACK_DEPTH = 800 +const noop = _ => _ + +const defer = typeof process !== 'undefined' && process.nextTick + ? process.nextTick + : typeof Promise !== 'undefined' + ? fn => Promise.resolve().then(fn) + : typeof setTimeout !== 'undefined' + ? setTimeout + : noop + +if (defer === noop) { + throw new Error( + 'Your JavaScript runtime does not support any asynchronous primitives ' + + 'that are required by vue-server-renderer. Please use a polyfill for ' + + 'either Promise or setTimeout.' + ) +} + +export function createWriteFunction ( + write: (text: string, next: Function) => boolean, + onError: Function +): Function { + let stackDepth = 0 + const cachedWrite = (text, next) => { + if (text && cachedWrite.caching) { + cachedWrite.cacheBuffer[cachedWrite.cacheBuffer.length - 1] += text + } + const waitForNext = write(text, next) + if (waitForNext !== true) { + if (stackDepth >= MAX_STACK_DEPTH) { + defer(() => { + try { next() } catch (e) { + onError(e) + } + }) + } else { + stackDepth++ + next() + stackDepth-- + } + } + } + cachedWrite.caching = false + cachedWrite.cacheBuffer = [] + cachedWrite.componentBuffer = [] + return cachedWrite +} diff --git a/node_modules/vue/src/sfc/parser.js b/node_modules/vue/src/sfc/parser.js new file mode 100644 index 0000000..59c5fc3 --- /dev/null +++ b/node_modules/vue/src/sfc/parser.js @@ -0,0 +1,134 @@ +/* @flow */ + +import deindent from 'de-indent' +import { parseHTML } from 'compiler/parser/html-parser' +import { makeMap } from 'shared/util' + +const splitRE = /\r?\n/g +const replaceRE = /./g +const isSpecialTag = makeMap('script,style,template', true) + +/** + * Parse a single-file component (*.vue) file into an SFC Descriptor Object. + */ +export function parseComponent ( + content: string, + options?: Object = {} +): SFCDescriptor { + const sfc: SFCDescriptor = { + template: null, + script: null, + styles: [], + customBlocks: [], + errors: [] + } + let depth = 0 + let currentBlock: ?SFCBlock = null + + let warn = msg => { + sfc.errors.push(msg) + } + + if (process.env.NODE_ENV !== 'production' && options.outputSourceRange) { + warn = (msg, range) => { + const data: WarningMessage = { msg } + if (range.start != null) { + data.start = range.start + } + if (range.end != null) { + data.end = range.end + } + sfc.errors.push(data) + } + } + + function start ( + tag: string, + attrs: Array, + unary: boolean, + start: number, + end: number + ) { + if (depth === 0) { + currentBlock = { + type: tag, + content: '', + start: end, + attrs: attrs.reduce((cumulated, { name, value }) => { + cumulated[name] = value || true + return cumulated + }, {}) + } + if (isSpecialTag(tag)) { + checkAttrs(currentBlock, attrs) + if (tag === 'style') { + sfc.styles.push(currentBlock) + } else { + sfc[tag] = currentBlock + } + } else { // custom blocks + sfc.customBlocks.push(currentBlock) + } + } + if (!unary) { + depth++ + } + } + + function checkAttrs (block: SFCBlock, attrs: Array) { + for (let i = 0; i < attrs.length; i++) { + const attr = attrs[i] + if (attr.name === 'lang') { + block.lang = attr.value + } + if (attr.name === 'scoped') { + block.scoped = true + } + if (attr.name === 'module') { + block.module = attr.value || true + } + if (attr.name === 'src') { + block.src = attr.value + } + } + } + + function end (tag: string, start: number) { + if (depth === 1 && currentBlock) { + currentBlock.end = start + let text = content.slice(currentBlock.start, currentBlock.end) + if (options.deindent !== false) { + text = deindent(text) + } + // pad content so that linters and pre-processors can output correct + // line numbers in errors and warnings + if (currentBlock.type !== 'template' && options.pad) { + text = padContent(currentBlock, options.pad) + text + } + currentBlock.content = text + currentBlock = null + } + depth-- + } + + function padContent (block: SFCBlock, pad: true | "line" | "space") { + if (pad === 'space') { + return content.slice(0, block.start).replace(replaceRE, ' ') + } else { + const offset = content.slice(0, block.start).split(splitRE).length + const padChar = block.type === 'script' && !block.lang + ? '//\n' + : '\n' + return Array(offset).join(padChar) + } + } + + parseHTML(content, { + warn, + start, + end, + outputSourceRange: options.outputSourceRange + }) + + return sfc +} diff --git a/node_modules/vue/src/shared/constants.js b/node_modules/vue/src/shared/constants.js new file mode 100644 index 0000000..a8b15e0 --- /dev/null +++ b/node_modules/vue/src/shared/constants.js @@ -0,0 +1,22 @@ +export const SSR_ATTR = 'data-server-rendered' + +export const ASSET_TYPES = [ + 'component', + 'directive', + 'filter' +] + +export const LIFECYCLE_HOOKS = [ + 'beforeCreate', + 'created', + 'beforeMount', + 'mounted', + 'beforeUpdate', + 'updated', + 'beforeDestroy', + 'destroyed', + 'activated', + 'deactivated', + 'errorCaptured', + 'serverPrefetch' +] diff --git a/node_modules/vue/src/shared/util.js b/node_modules/vue/src/shared/util.js new file mode 100644 index 0000000..9f240c7 --- /dev/null +++ b/node_modules/vue/src/shared/util.js @@ -0,0 +1,343 @@ +/* @flow */ + +export const emptyObject = Object.freeze({}) + +// These helpers produce better VM code in JS engines due to their +// explicitness and function inlining. +export function isUndef (v: any): boolean %checks { + return v === undefined || v === null +} + +export function isDef (v: any): boolean %checks { + return v !== undefined && v !== null +} + +export function isTrue (v: any): boolean %checks { + return v === true +} + +export function isFalse (v: any): boolean %checks { + return v === false +} + +/** + * Check if value is primitive. + */ +export function isPrimitive (value: any): boolean %checks { + return ( + typeof value === 'string' || + typeof value === 'number' || + // $flow-disable-line + typeof value === 'symbol' || + typeof value === 'boolean' + ) +} + +/** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + */ +export function isObject (obj: mixed): boolean %checks { + return obj !== null && typeof obj === 'object' +} + +/** + * Get the raw type string of a value, e.g., [object Object]. + */ +const _toString = Object.prototype.toString + +export function toRawType (value: any): string { + return _toString.call(value).slice(8, -1) +} + +/** + * Strict object type check. Only returns true + * for plain JavaScript objects. + */ +export function isPlainObject (obj: any): boolean { + return _toString.call(obj) === '[object Object]' +} + +export function isRegExp (v: any): boolean { + return _toString.call(v) === '[object RegExp]' +} + +/** + * Check if val is a valid array index. + */ +export function isValidArrayIndex (val: any): boolean { + const n = parseFloat(String(val)) + return n >= 0 && Math.floor(n) === n && isFinite(val) +} + +export function isPromise (val: any): boolean { + return ( + isDef(val) && + typeof val.then === 'function' && + typeof val.catch === 'function' + ) +} + +/** + * Convert a value to a string that is actually rendered. + */ +export function toString (val: any): string { + return val == null + ? '' + : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) + ? JSON.stringify(val, null, 2) + : String(val) +} + +/** + * Convert an input value to a number for persistence. + * If the conversion fails, return original string. + */ +export function toNumber (val: string): number | string { + const n = parseFloat(val) + return isNaN(n) ? val : n +} + +/** + * Make a map and return a function for checking if a key + * is in that map. + */ +export function makeMap ( + str: string, + expectsLowerCase?: boolean +): (key: string) => true | void { + const map = Object.create(null) + const list: Array = str.split(',') + for (let i = 0; i < list.length; i++) { + map[list[i]] = true + } + return expectsLowerCase + ? val => map[val.toLowerCase()] + : val => map[val] +} + +/** + * Check if a tag is a built-in tag. + */ +export const isBuiltInTag = makeMap('slot,component', true) + +/** + * Check if an attribute is a reserved attribute. + */ +export const isReservedAttribute = makeMap('key,ref,slot,slot-scope,is') + +/** + * Remove an item from an array. + */ +export function remove (arr: Array, item: any): Array | void { + if (arr.length) { + const index = arr.indexOf(item) + if (index > -1) { + return arr.splice(index, 1) + } + } +} + +/** + * Check whether an object has the property. + */ +const hasOwnProperty = Object.prototype.hasOwnProperty +export function hasOwn (obj: Object | Array<*>, key: string): boolean { + return hasOwnProperty.call(obj, key) +} + +/** + * Create a cached version of a pure function. + */ +export function cached (fn: F): F { + const cache = Object.create(null) + return (function cachedFn (str: string) { + const hit = cache[str] + return hit || (cache[str] = fn(str)) + }: any) +} + +/** + * Camelize a hyphen-delimited string. + */ +const camelizeRE = /-(\w)/g +export const camelize = cached((str: string): string => { + return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '') +}) + +/** + * Capitalize a string. + */ +export const capitalize = cached((str: string): string => { + return str.charAt(0).toUpperCase() + str.slice(1) +}) + +/** + * Hyphenate a camelCase string. + */ +const hyphenateRE = /\B([A-Z])/g +export const hyphenate = cached((str: string): string => { + return str.replace(hyphenateRE, '-$1').toLowerCase() +}) + +/** + * Simple bind polyfill for environments that do not support it, + * e.g., PhantomJS 1.x. Technically, we don't need this anymore + * since native bind is now performant enough in most browsers. + * But removing it would mean breaking code that was able to run in + * PhantomJS 1.x, so this must be kept for backward compatibility. + */ + +/* istanbul ignore next */ +function polyfillBind (fn: Function, ctx: Object): Function { + function boundFn (a) { + const l = arguments.length + return l + ? l > 1 + ? fn.apply(ctx, arguments) + : fn.call(ctx, a) + : fn.call(ctx) + } + + boundFn._length = fn.length + return boundFn +} + +function nativeBind (fn: Function, ctx: Object): Function { + return fn.bind(ctx) +} + +export const bind = Function.prototype.bind + ? nativeBind + : polyfillBind + +/** + * Convert an Array-like object to a real Array. + */ +export function toArray (list: any, start?: number): Array { + start = start || 0 + let i = list.length - start + const ret: Array = new Array(i) + while (i--) { + ret[i] = list[i + start] + } + return ret +} + +/** + * Mix properties into target object. + */ +export function extend (to: Object, _from: ?Object): Object { + for (const key in _from) { + to[key] = _from[key] + } + return to +} + +/** + * Merge an Array of Objects into a single Object. + */ +export function toObject (arr: Array): Object { + const res = {} + for (let i = 0; i < arr.length; i++) { + if (arr[i]) { + extend(res, arr[i]) + } + } + return res +} + +/* eslint-disable no-unused-vars */ + +/** + * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). + */ +export function noop (a?: any, b?: any, c?: any) {} + +/** + * Always return false. + */ +export const no = (a?: any, b?: any, c?: any) => false + +/* eslint-enable no-unused-vars */ + +/** + * Return the same value. + */ +export const identity = (_: any) => _ + +/** + * Generate a string containing static keys from compiler modules. + */ +export function genStaticKeys (modules: Array): string { + return modules.reduce((keys, m) => { + return keys.concat(m.staticKeys || []) + }, []).join(',') +} + +/** + * Check if two values are loosely equal - that is, + * if they are plain objects, do they have the same shape? + */ +export function looseEqual (a: any, b: any): boolean { + if (a === b) return true + const isObjectA = isObject(a) + const isObjectB = isObject(b) + if (isObjectA && isObjectB) { + try { + const isArrayA = Array.isArray(a) + const isArrayB = Array.isArray(b) + if (isArrayA && isArrayB) { + return a.length === b.length && a.every((e, i) => { + return looseEqual(e, b[i]) + }) + } else if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime() + } else if (!isArrayA && !isArrayB) { + const keysA = Object.keys(a) + const keysB = Object.keys(b) + return keysA.length === keysB.length && keysA.every(key => { + return looseEqual(a[key], b[key]) + }) + } else { + /* istanbul ignore next */ + return false + } + } catch (e) { + /* istanbul ignore next */ + return false + } + } else if (!isObjectA && !isObjectB) { + return String(a) === String(b) + } else { + return false + } +} + +/** + * Return the first index at which a loosely equal value can be + * found in the array (if value is a plain object, the array must + * contain an object of the same shape), or -1 if it is not present. + */ +export function looseIndexOf (arr: Array, val: mixed): number { + for (let i = 0; i < arr.length; i++) { + if (looseEqual(arr[i], val)) return i + } + return -1 +} + +/** + * Ensure a function is called only once. + */ +export function once (fn: Function): Function { + let called = false + return function () { + if (!called) { + called = true + fn.apply(this, arguments) + } + } +} diff --git a/node_modules/vue/types/index.d.ts b/node_modules/vue/types/index.d.ts new file mode 100644 index 0000000..58ceb20 --- /dev/null +++ b/node_modules/vue/types/index.d.ts @@ -0,0 +1,39 @@ +import { Vue } from "./vue"; +import "./umd"; + +export default Vue; + +export { + CreateElement, + VueConstructor +} from "./vue"; + +export { + Component, + AsyncComponent, + ComponentOptions, + FunctionalComponentOptions, + RenderContext, + PropType, + PropOptions, + ComputedOptions, + WatchHandler, + WatchOptions, + WatchOptionsWithHandler, + DirectiveFunction, + DirectiveOptions +} from "./options"; + +export { + PluginFunction, + PluginObject +} from "./plugin"; + +export { + VNodeChildren, + VNodeChildrenArrayContents, + VNode, + VNodeComponentOptions, + VNodeData, + VNodeDirective +} from "./vnode"; diff --git a/node_modules/vue/types/options.d.ts b/node_modules/vue/types/options.d.ts new file mode 100644 index 0000000..ff26605 --- /dev/null +++ b/node_modules/vue/types/options.d.ts @@ -0,0 +1,207 @@ +import { Vue, CreateElement, CombinedVueInstance } from "./vue"; +import { VNode, VNodeData, VNodeDirective, NormalizedScopedSlot } from "./vnode"; + +type Constructor = { + new (...args: any[]): any; +} + +// we don't support infer props in async component +// N.B. ComponentOptions is contravariant, the default generic should be bottom type +export type Component, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> = + | typeof Vue + | FunctionalComponentOptions + | ComponentOptions + +type EsModule = T | { default: T } + +type ImportedComponent, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> + = EsModule> + +export type AsyncComponent, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> + = AsyncComponentPromise + | AsyncComponentFactory + +export type AsyncComponentPromise, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> = ( + resolve: (component: Component) => void, + reject: (reason?: any) => void +) => Promise> | void; + +export type AsyncComponentFactory, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> = () => { + component: Promise>; + loading?: ImportedComponent; + error?: ImportedComponent; + delay?: number; + timeout?: number; +} + +/** + * When the `Computed` type parameter on `ComponentOptions` is inferred, + * it should have a property with the return type of every get-accessor. + * Since there isn't a way to query for the return type of a function, we allow TypeScript + * to infer from the shape of `Accessors` and work backwards. + */ +export type Accessors = { + [K in keyof T]: (() => T[K]) | ComputedOptions +} + +type DataDef = Data | ((this: Readonly & V) => Data) +/** + * This type should be used when an array of strings is used for a component's `props` value. + */ +export type ThisTypedComponentOptionsWithArrayProps = + object & + ComponentOptions, V>, Methods, Computed, PropNames[], Record> & + ThisType>>>; + +/** + * This type should be used when an object mapped to `PropOptions` is used for a component's `props` value. + */ +export type ThisTypedComponentOptionsWithRecordProps = + object & + ComponentOptions, Methods, Computed, RecordPropsDefinition, Props> & + ThisType>>; + +type DefaultData = object | ((this: V) => object); +type DefaultProps = Record; +type DefaultMethods = { [key: string]: (this: V, ...args: any[]) => any }; +type DefaultComputed = { [key: string]: any }; +export interface ComponentOptions< + V extends Vue, + Data=DefaultData, + Methods=DefaultMethods, + Computed=DefaultComputed, + PropsDef=PropsDefinition, + Props=DefaultProps> { + data?: Data; + props?: PropsDef; + propsData?: object; + computed?: Accessors; + methods?: Methods; + watch?: Record | WatchHandler>; + + el?: Element | string; + template?: string; + // hack is for functional component type inference, should not be used in user code + render?(createElement: CreateElement, hack: RenderContext): VNode; + renderError?(createElement: CreateElement, err: Error): VNode; + staticRenderFns?: ((createElement: CreateElement) => VNode)[]; + + beforeCreate?(this: V): void; + created?(): void; + beforeDestroy?(): void; + destroyed?(): void; + beforeMount?(): void; + mounted?(): void; + beforeUpdate?(): void; + updated?(): void; + activated?(): void; + deactivated?(): void; + errorCaptured?(err: Error, vm: Vue, info: string): boolean | void; + serverPrefetch?(this: V): Promise; + + directives?: { [key: string]: DirectiveFunction | DirectiveOptions }; + components?: { [key: string]: Component | AsyncComponent }; + transitions?: { [key: string]: object }; + filters?: { [key: string]: Function }; + + provide?: object | (() => object); + inject?: InjectOptions; + + model?: { + prop?: string; + event?: string; + }; + + parent?: Vue; + mixins?: (ComponentOptions | typeof Vue)[]; + name?: string; + // TODO: support properly inferred 'extends' + extends?: ComponentOptions | typeof Vue; + delimiters?: [string, string]; + comments?: boolean; + inheritAttrs?: boolean; +} + +export interface FunctionalComponentOptions> { + name?: string; + props?: PropDefs; + model?: { + prop?: string; + event?: string; + }; + inject?: InjectOptions; + functional: boolean; + render?(this: undefined, createElement: CreateElement, context: RenderContext): VNode | VNode[]; +} + +export interface RenderContext { + props: Props; + children: VNode[]; + slots(): any; + data: VNodeData; + parent: Vue; + listeners: { [key: string]: Function | Function[] }; + scopedSlots: { [key: string]: NormalizedScopedSlot }; + injections: any +} + +export type Prop = { (): T } | { new(...args: never[]): T & object } | { new(...args: string[]): Function } + +export type PropType = Prop | Prop[]; + +export type PropValidator = PropOptions | PropType; + +export interface PropOptions { + type?: PropType; + required?: boolean; + default?: T | null | undefined | (() => T | null | undefined); + validator?(value: T): boolean; +} + +export type RecordPropsDefinition = { + [K in keyof T]: PropValidator +} +export type ArrayPropsDefinition = (keyof T)[]; +export type PropsDefinition = ArrayPropsDefinition | RecordPropsDefinition; + +export interface ComputedOptions { + get?(): T; + set?(value: T): void; + cache?: boolean; +} + +export type WatchHandler = string | ((val: T, oldVal: T) => void); + +export interface WatchOptions { + deep?: boolean; + immediate?: boolean; +} + +export interface WatchOptionsWithHandler extends WatchOptions { + handler: WatchHandler; +} + +export interface DirectiveBinding extends Readonly { + readonly modifiers: { [key: string]: boolean }; +} + +export type DirectiveFunction = ( + el: HTMLElement, + binding: DirectiveBinding, + vnode: VNode, + oldVnode: VNode +) => void; + +export interface DirectiveOptions { + bind?: DirectiveFunction; + inserted?: DirectiveFunction; + update?: DirectiveFunction; + componentUpdated?: DirectiveFunction; + unbind?: DirectiveFunction; +} + +export type InjectKey = string | symbol; + +export type InjectOptions = { + [key: string]: InjectKey | { from?: InjectKey, default?: any } +} | string[]; diff --git a/node_modules/vue/types/plugin.d.ts b/node_modules/vue/types/plugin.d.ts new file mode 100644 index 0000000..5741f86 --- /dev/null +++ b/node_modules/vue/types/plugin.d.ts @@ -0,0 +1,8 @@ +import { Vue as _Vue } from "./vue"; + +export type PluginFunction = (Vue: typeof _Vue, options?: T) => void; + +export interface PluginObject { + install: PluginFunction; + [key: string]: any; +} diff --git a/node_modules/vue/types/umd.d.ts b/node_modules/vue/types/umd.d.ts new file mode 100644 index 0000000..d1dc8d1 --- /dev/null +++ b/node_modules/vue/types/umd.d.ts @@ -0,0 +1,48 @@ +import * as V from "./index"; +import { + DefaultData, + DefaultProps, + DefaultMethods, + DefaultComputed, + PropsDefinition +} from "./options"; + +// Expose some types for backward compatibility... +declare namespace Vue { + // vue.d.ts + export type CreateElement = V.CreateElement; + export type VueConstructor = V.VueConstructor; + + // options.d.ts + export type Component, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> = V.Component; + export type AsyncComponent, Methods=DefaultMethods, Computed=DefaultComputed, Props=DefaultProps> = V.AsyncComponent; + export type ComponentOptions, Methods=DefaultMethods, Computed=DefaultComputed, PropsDef=PropsDefinition, Props=DefaultProps> = V.ComponentOptions; + export type FunctionalComponentOptions> = V.FunctionalComponentOptions; + export type RenderContext = V.RenderContext; + export type PropType = V.PropType; + export type PropOptions = V.PropOptions; + export type ComputedOptions = V.ComputedOptions; + export type WatchHandler = V.WatchHandler; + export type WatchOptions = V.WatchOptions; + export type WatchOptionsWithHandler = V.WatchOptionsWithHandler; + export type DirectiveFunction = V.DirectiveFunction; + export type DirectiveOptions = V.DirectiveOptions; + + // plugin.d.ts + export type PluginFunction = V.PluginFunction; + export type PluginObject = V.PluginObject; + + // vnode.d.ts + export type VNodeChildren = V.VNodeChildren; + export type VNodeChildrenArrayContents = V.VNodeChildrenArrayContents; + export type VNode = V.VNode; + export type VNodeComponentOptions = V.VNodeComponentOptions; + export type VNodeData = V.VNodeData; + export type VNodeDirective = V.VNodeDirective; +} + +declare class Vue extends V.default {} + +export = Vue; + +export as namespace Vue; diff --git a/node_modules/vue/types/vnode.d.ts b/node_modules/vue/types/vnode.d.ts new file mode 100644 index 0000000..997980c --- /dev/null +++ b/node_modules/vue/types/vnode.d.ts @@ -0,0 +1,76 @@ +import { Vue } from "./vue"; + +export type ScopedSlot = (props: any) => ScopedSlotReturnValue; +type ScopedSlotReturnValue = VNode | string | boolean | null | undefined | ScopedSlotReturnArray; +interface ScopedSlotReturnArray extends Array {} + +// Scoped slots are guaranteed to return Array of VNodes starting in 2.6 +export type NormalizedScopedSlot = (props: any) => ScopedSlotChildren; +export type ScopedSlotChildren = VNode[] | undefined; + +// Relaxed type compatible with $createElement +export type VNodeChildren = VNodeChildrenArrayContents | [ScopedSlot] | string | boolean | null | undefined; +export interface VNodeChildrenArrayContents extends Array {} + +export interface VNode { + tag?: string; + data?: VNodeData; + children?: VNode[]; + text?: string; + elm?: Node; + ns?: string; + context?: Vue; + key?: string | number | symbol | boolean; + componentOptions?: VNodeComponentOptions; + componentInstance?: Vue; + parent?: VNode; + raw?: boolean; + isStatic?: boolean; + isRootInsert: boolean; + isComment: boolean; +} + +export interface VNodeComponentOptions { + Ctor: typeof Vue; + propsData?: object; + listeners?: object; + children?: VNode[]; + tag?: string; +} + +export interface VNodeData { + key?: string | number; + slot?: string; + scopedSlots?: { [key: string]: ScopedSlot | undefined }; + ref?: string; + refInFor?: boolean; + tag?: string; + staticClass?: string; + class?: any; + staticStyle?: { [key: string]: any }; + style?: string | object[] | object; + props?: { [key: string]: any }; + attrs?: { [key: string]: any }; + domProps?: { [key: string]: any }; + hook?: { [key: string]: Function }; + on?: { [key: string]: Function | Function[] }; + nativeOn?: { [key: string]: Function | Function[] }; + transition?: object; + show?: boolean; + inlineTemplate?: { + render: Function; + staticRenderFns: Function[]; + }; + directives?: VNodeDirective[]; + keepAlive?: boolean; +} + +export interface VNodeDirective { + name: string; + value?: any; + oldValue?: any; + expression?: string; + arg?: string; + oldArg?: string; + modifiers?: { [key: string]: boolean }; +} diff --git a/node_modules/vue/types/vue.d.ts b/node_modules/vue/types/vue.d.ts new file mode 100644 index 0000000..7adb5a5 --- /dev/null +++ b/node_modules/vue/types/vue.d.ts @@ -0,0 +1,132 @@ +import { + Component, + AsyncComponent, + ComponentOptions, + FunctionalComponentOptions, + WatchOptionsWithHandler, + WatchHandler, + DirectiveOptions, + DirectiveFunction, + RecordPropsDefinition, + ThisTypedComponentOptionsWithArrayProps, + ThisTypedComponentOptionsWithRecordProps, + WatchOptions, +} from "./options"; +import { VNode, VNodeData, VNodeChildren, NormalizedScopedSlot } from "./vnode"; +import { PluginFunction, PluginObject } from "./plugin"; + +export interface CreateElement { + (tag?: string | Component | AsyncComponent | (() => Component), children?: VNodeChildren): VNode; + (tag?: string | Component | AsyncComponent | (() => Component), data?: VNodeData, children?: VNodeChildren): VNode; +} + +export interface Vue { + readonly $el: Element; + readonly $options: ComponentOptions; + readonly $parent: Vue; + readonly $root: Vue; + readonly $children: Vue[]; + readonly $refs: { [key: string]: Vue | Element | (Vue | Element)[] | undefined }; + readonly $slots: { [key: string]: VNode[] | undefined }; + readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined }; + readonly $isServer: boolean; + readonly $data: Record; + readonly $props: Record; + readonly $ssrContext: any; + readonly $vnode: VNode; + readonly $attrs: Record; + readonly $listeners: Record; + + $mount(elementOrSelector?: Element | string, hydrating?: boolean): this; + $forceUpdate(): void; + $destroy(): void; + $set: typeof Vue.set; + $delete: typeof Vue.delete; + $watch( + expOrFn: string, + callback: (this: this, n: any, o: any) => void, + options?: WatchOptions + ): (() => void); + $watch( + expOrFn: (this: this) => T, + callback: (this: this, n: T, o: T) => void, + options?: WatchOptions + ): (() => void); + $on(event: string | string[], callback: Function): this; + $once(event: string | string[], callback: Function): this; + $off(event?: string | string[], callback?: Function): this; + $emit(event: string, ...args: any[]): this; + $nextTick(callback: (this: this) => void): void; + $nextTick(): Promise; + $createElement: CreateElement; +} + +export type CombinedVueInstance = Data & Methods & Computed & Props & Instance; +export type ExtendedVue = VueConstructor & Vue>; + +export interface VueConfiguration { + silent: boolean; + optionMergeStrategies: any; + devtools: boolean; + productionTip: boolean; + performance: boolean; + errorHandler(err: Error, vm: Vue, info: string): void; + warnHandler(msg: string, vm: Vue, trace: string): void; + ignoredElements: (string | RegExp)[]; + keyCodes: { [key: string]: number | number[] }; + async: boolean; +} + +export interface VueConstructor { + new (options?: ThisTypedComponentOptionsWithArrayProps): CombinedVueInstance>; + // ideally, the return type should just contain Props, not Record. But TS requires to have Base constructors with the same return type. + new (options?: ThisTypedComponentOptionsWithRecordProps): CombinedVueInstance>; + new (options?: ComponentOptions): CombinedVueInstance>; + + extend(options?: ThisTypedComponentOptionsWithArrayProps): ExtendedVue>; + extend(options?: ThisTypedComponentOptionsWithRecordProps): ExtendedVue; + extend(definition: FunctionalComponentOptions, PropNames[]>): ExtendedVue>; + extend(definition: FunctionalComponentOptions>): ExtendedVue; + extend(options?: ComponentOptions): ExtendedVue; + + nextTick(callback: (this: T) => void, context?: T): void; + nextTick(): Promise + set(object: object, key: string | number, value: T): T; + set(array: T[], key: number, value: T): T; + delete(object: object, key: string | number): void; + delete(array: T[], key: number): void; + + directive( + id: string, + definition?: DirectiveOptions | DirectiveFunction + ): DirectiveOptions; + filter(id: string, definition?: Function): Function; + + component(id: string): VueConstructor; + component(id: string, constructor: VC): VC; + component(id: string, definition: AsyncComponent): ExtendedVue; + component(id: string, definition?: ThisTypedComponentOptionsWithArrayProps): ExtendedVue>; + component(id: string, definition?: ThisTypedComponentOptionsWithRecordProps): ExtendedVue; + component(id: string, definition: FunctionalComponentOptions, PropNames[]>): ExtendedVue>; + component(id: string, definition: FunctionalComponentOptions>): ExtendedVue; + component(id: string, definition?: ComponentOptions): ExtendedVue; + + use(plugin: PluginObject | PluginFunction, options?: T): VueConstructor; + use(plugin: PluginObject | PluginFunction, ...options: any[]): VueConstructor; + mixin(mixin: VueConstructor | ComponentOptions): VueConstructor; + compile(template: string): { + render(createElement: typeof Vue.prototype.$createElement): VNode; + staticRenderFns: (() => VNode)[]; + }; + + observable(obj: T): T; + + util: { + warn(msg: string, vm?: InstanceType): void; + }; + + config: VueConfiguration; + version: string; +} + +export const Vue: VueConstructor; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..da0af16 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,105 @@ +{ + "name": "version-record", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "version-record", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "pinia": "^2.1.6" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", + "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" + }, + "node_modules/pinia": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.6.tgz", + "integrity": "sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==", + "dependencies": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.3.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz", + "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==", + "peer": true + }, + "node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + } + }, + "dependencies": { + "@vue/devtools-api": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", + "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" + }, + "pinia": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.6.tgz", + "integrity": "sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==", + "requires": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + } + }, + "vue": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz", + "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==", + "peer": true + }, + "vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "requires": {} + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..04934e8 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "version-record", + "version": "1.0.0", + "description": "", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "pinia": "^2.1.6" + } +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..b1e3ed8 --- /dev/null +++ b/pages.json @@ -0,0 +1,55 @@ +{ + "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "首页" + } + }, + { + "path": "pages/wikipedia/index", + "style": { + "navigationBarTitleText": "百科" + } + }, + { + "path": "pages/user/index", + "style": { + "navigationBarTitleText": "我的" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "uni-app", + "navigationBarBackgroundColor": "#F8F8F8", + "backgroundColor": "#F8F8F8" + }, + "uniIdRouter": {}, + "tabBar": { + "color": "#999999", + "selectedColor": "#26758d", + "borderStyle": "black", + "backgroundColor": "#ffffff", + "height": "50px", + "fontSize": "10px", + "iconWidth": "20px", + "spacing": "3px", + "list": [{ + "pagePath": "pages/index/index", + "iconPath": "static/tabs/home.png", + "selectedIconPath": "static/tabs/home2.png", + "text": "首页" + }, { + "pagePath": "pages/wikipedia/index", + "iconPath": "static/tabs/order.png", + "selectedIconPath": "static/tabs/order2.png", + "text": "百科" + }, { + "pagePath": "pages/user/index", + "iconPath": "static/tabs/user.png", + "selectedIconPath": "static/tabs/user2.png", + "text": "我的" + }] + } +} diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..a109fa8 --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/pages/user/index.vue b/pages/user/index.vue new file mode 100644 index 0000000..02409e3 --- /dev/null +++ b/pages/user/index.vue @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/pages/webview/webview.vue b/pages/webview/webview.vue new file mode 100644 index 0000000..3a2b421 --- /dev/null +++ b/pages/webview/webview.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/pages/wikipedia/index.vue b/pages/wikipedia/index.vue new file mode 100644 index 0000000..02409e3 --- /dev/null +++ b/pages/wikipedia/index.vue @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..b5771e2 Binary files /dev/null and b/static/logo.png differ diff --git a/static/tabs/cart.png b/static/tabs/cart.png new file mode 100644 index 0000000..ee948f4 Binary files /dev/null and b/static/tabs/cart.png differ diff --git a/static/tabs/cart2.png b/static/tabs/cart2.png new file mode 100644 index 0000000..e5f405a Binary files /dev/null and b/static/tabs/cart2.png differ diff --git a/static/tabs/home.png b/static/tabs/home.png new file mode 100644 index 0000000..fd631a7 Binary files /dev/null and b/static/tabs/home.png differ diff --git a/static/tabs/home2.png b/static/tabs/home2.png new file mode 100644 index 0000000..8ca04a1 Binary files /dev/null and b/static/tabs/home2.png differ diff --git a/static/tabs/order.png b/static/tabs/order.png new file mode 100644 index 0000000..ca458ac Binary files /dev/null and b/static/tabs/order.png differ diff --git a/static/tabs/order2.png b/static/tabs/order2.png new file mode 100644 index 0000000..04c4a23 Binary files /dev/null and b/static/tabs/order2.png differ diff --git a/static/tabs/share.png b/static/tabs/share.png new file mode 100644 index 0000000..45ba6eb Binary files /dev/null and b/static/tabs/share.png differ diff --git a/static/tabs/user.png b/static/tabs/user.png new file mode 100644 index 0000000..aed30f9 Binary files /dev/null and b/static/tabs/user.png differ diff --git a/static/tabs/user2.png b/static/tabs/user2.png new file mode 100644 index 0000000..4ccd320 Binary files /dev/null and b/static/tabs/user2.png differ diff --git a/static/vip2.png b/static/vip2.png new file mode 100644 index 0000000..b446732 Binary files /dev/null and b/static/vip2.png differ diff --git a/store/index.js b/store/index.js new file mode 100644 index 0000000..2a9a49e --- /dev/null +++ b/store/index.js @@ -0,0 +1,150 @@ +import { defineStore } from 'pinia' +import api from '@/api/index' +// import config from '../config' +// useStore 可以是 useUser、useCart 之类的任何东西 +// 第一个参数是应用程序中 store 的唯一 id +export const useStore = defineStore('main2', { + state: () => { + return { + // 所有这些属性都将自动推断其类型 + isLogin: false, + userInfo:null, + access_token:'', + historySearchWords:'', + course_detail_id:0, + timer:null, + surplus_seconds:null,// 倒计时 + test_time:0,//测试用时 + test_timer:null, + total_score:0, + status_bar_height: 0, + debounceTimer:null, + systemInfo:null, + cartList:[], + cartChange:false, + remark_text:'', + address:'' + } + }, + actions:{ + //应用初始化,在这里获取必要的基础信息 + appInit() { + //获取设备信息 + const { statusBarHeight } = uni.getSystemInfoSync(); + this.status_bar_height = statusBarHeight + }, + countdownFunc(minutes){ // 计时 + this.surplus_seconds = minutes*60 + }, + saveToken(token){ // 保存token + uni.setStorage({ + key: 'access_token', + data: token, + success: function () { + console.log('token was saved'); + } + }); + }, + saveVisitState(){ // 保存浏览状态 + uni.setStorage({ + key: 'visitState', + data: 1, + success: function () { + console.log('visitState was saved'); + } + }); + }, + checkLogin(){ // 检查是否登录 + let access_token = uni.getStorageSync('access_token') + // let visitState = uni.getStorageSync('visitState') + console.log(access_token) + if(access_token) { + this.access_token = access_token + this.isLogin = true + this.getUserInfo() + } + // else{ + // if(!visitState) { + // // uni.navigateTo({ + // // url:`/pages/user/login` + // // }); + // } + // } + }, + async getUserInfo() {// 获取用户信息 + const _this = this + //测试 + // 拦截器 + // uni.addInterceptor('request',{ + // complete(res) { + // // console.log('拦截信息:',res) + // if(res.data.data.tag === 'user') { // user接口 + // // console.log('interceptor-complete',res) + // if(res.data.code === 1) { + // _this.userInfo = res.data.data.user + // } + + // if(res.data.code === 7 ) { // token过期 清除token缓存 + // _this.access_token = '' + // _this.isLogin = false + // uni.removeStorageSync('access_token'); + // uni.removeStorageSync('visitState'); + // } + + // if(res.header.authorization) { + // _this.saveToken(res.header.authorization) + // _this.isLogin = true + // } + // uni.removeInterceptor('request') + // } + // } + // }) + //测试 结束 + const res = await api.getUserInfo() + // console.log('用户信息:',res) + if(res.code == 1) { + this.userInfo = res.data + uni.setStorageSync('userInfo',res.data); + } + // else if(res.code == 7){ // token过期 清除token缓存 + // this.access_token = '' + // this.isLogin = false + // uni.removeStorageSync('access_token'); + // uni.removeStorageSync('visitState'); + // } + }, + logout() { // 登出 + this.userInfo = null + this.isLogin = false + uni.removeStorageSync('access_token'); + uni.removeStorageSync('visitState'); + }, + clearStorageFunc() { // 清除倒计时缓存 + uni.removeStorageSync('surplus_seconds') + uni.removeStorageSync('test_time') + uni.removeStorageSync('saved_right_indexs_storage') // 清除正确题目的提交记录 + }, + toLogin() { // 跳转登录页 + uni.navigateTo({ + url:'/pages/user/login' + }); + }, + showMsg(msg,type){ + uni.showToast({ + title: msg, + icon :type || 'none', + duration: 2000 + }); + }, + async getCartList(){ + const res = await api.getCartList() + // console.log(res) + if(res.code === 1) { + // if(res.data.length >0) { + this.cartList = res.data + // cart_list.value = res.data + // } + } + } + } +}) \ No newline at end of file diff --git a/uni.promisify.adaptor.js b/uni.promisify.adaptor.js new file mode 100644 index 0000000..47fbce1 --- /dev/null +++ b/uni.promisify.adaptor.js @@ -0,0 +1,10 @@ +uni.addInterceptor({ + returnValue (res) { + if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) { + return res; + } + return new Promise((resolve, reject) => { + res.then((res) => res[0] ? reject(res[0]) : resolve(res[1])); + }); + }, +}); \ No newline at end of file diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..a9a742d --- /dev/null +++ b/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color:#333;//基本色 +$uni-text-color-inverse:#fff;//反色 +$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable:#c0c0c0; + +/* 背景颜色 */ +$uni-bg-color:#ffffff; +$uni-bg-color-grey:#f8f8f8; +$uni-bg-color-hover:#f1f1f1;//点击状态颜色 +$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 + +/* 边框颜色 */ +$uni-border-color:#c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm:12px; +$uni-font-size-base:14px; +$uni-font-size-lg:16; + +/* 图片尺寸 */ +$uni-img-size-sm:20px; +$uni-img-size-base:26px; +$uni-img-size-lg:40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:26px; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:15px; diff --git a/uni_modules/uni-popup/changelog.md b/uni_modules/uni-popup/changelog.md new file mode 100644 index 0000000..bc59f07 --- /dev/null +++ b/uni_modules/uni-popup/changelog.md @@ -0,0 +1,68 @@ +## 1.8.3(2023-04-17) +- 修复 uni-popup 重复打开时的 bug +## 1.8.2(2023-02-02) +- uni-popup-dialog 组件新增 inputType 属性 +## 1.8.1(2022-12-01) +- 修复 nvue 下 v-show 报错 +## 1.8.0(2022-11-29) +- 优化 主题样式 +## 1.7.9(2022-04-02) +- 修复 弹出层内部无法滚动的bug +## 1.7.8(2022-03-28) +- 修复 小程序中高度错误的bug +## 1.7.7(2022-03-17) +- 修复 快速调用open出现问题的Bug +## 1.7.6(2022-02-14) +- 修复 safeArea 属性不能设置为false的bug +## 1.7.5(2022-01-19) +- 修复 isMaskClick 失效的bug +## 1.7.4(2022-01-19) +- 新增 cancelText \ confirmText 属性 ,可自定义文本 +- 新增 maskBackgroundColor 属性 ,可以修改蒙版颜色 +- 优化 maskClick属性 更新为 isMaskClick ,解决微信小程序警告的问题 +## 1.7.3(2022-01-13) +- 修复 设置 safeArea 属性不生效的bug +## 1.7.2(2021-11-26) +- 优化 组件示例 +## 1.7.1(2021-11-26) +- 修复 vuedoc 文字错误 +## 1.7.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-popup](https://uniapp.dcloud.io/component/uniui/uni-popup) +## 1.6.2(2021-08-24) +- 新增 支持国际化 +## 1.6.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.6.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.5.0(2021-06-23) +- 新增 mask-click 遮罩层点击事件 +## 1.4.5(2021-06-22) +- 修复 nvue 平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +## 1.4.4(2021-06-18) +- 修复 H5平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +## 1.4.3(2021-06-08) +- 修复 错误的 watch 字段 +- 修复 safeArea 属性不生效的问题 +- 修复 点击内容,再点击遮罩无法关闭的Bug +## 1.4.2(2021-05-12) +- 新增 组件示例地址 +## 1.4.1(2021-04-29) +- 修复 组件内放置 input 、textarea 组件,无法聚焦的问题 +## 1.4.0 (2021-04-29) +- 新增 type 属性的 left\right 值,支持左右弹出 +- 新增 open(String:type) 方法参数 ,可以省略 type 属性 ,直接传入类型打开指定弹窗 +- 新增 backgroundColor 属性,可定义主窗口背景色,默认不显示背景色 +- 新增 safeArea 属性,是否适配底部安全区 +- 修复 App\h5\微信小程序底部安全区占位不对的Bug +- 修复 App 端弹出等待的Bug +- 优化 提升低配设备性能,优化动画卡顿问题 +- 优化 更简单的组件自定义方式 +## 1.2.9(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.2.8(2021-02-05) +- 调整为uni_modules目录规范 +## 1.2.7(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持 PC 端 +- 新增 uni-popup-message 、uni-popup-dialog扩展组件支持 PC 端 diff --git a/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js b/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js new file mode 100644 index 0000000..a747b9f --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + this.$once('hook:beforeDestroy', () => { + document.removeEventListener('keyup', listener) + }) + }, + render: () => {} +} +// #endif diff --git a/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue b/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue new file mode 100644 index 0000000..9bc87fc --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue @@ -0,0 +1,275 @@ + + + + + diff --git a/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue new file mode 100644 index 0000000..7f27a1e --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue @@ -0,0 +1,143 @@ + + + + diff --git a/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue new file mode 100644 index 0000000..ab08656 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue @@ -0,0 +1,187 @@ + + + + diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/en.json b/uni_modules/uni-popup/components/uni-popup/i18n/en.json new file mode 100644 index 0000000..8c0f5f3 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/en.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "cancel", + "uni-popup.ok": "ok", + "uni-popup.placeholder": "pleace enter", + "uni-popup.title": "Hint", + "uni-popup.shareTitle": "Share to" +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/index.js b/uni_modules/uni-popup/components/uni-popup/i18n/index.js new file mode 100644 index 0000000..fa8f0f3 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json new file mode 100644 index 0000000..8e5b99f --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "取消", + "uni-popup.ok": "确定", + "uni-popup.placeholder": "请输入", + "uni-popup.title": "提示", + "uni-popup.shareTitle": "分享到" +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json new file mode 100644 index 0000000..06ce162 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "取消", + "uni-popup.ok": "確定", + "uni-popup.placeholder": "請輸入", + "uni-popup.title": "提示", + "uni-popup.shareTitle": "分享到" +} diff --git a/uni_modules/uni-popup/components/uni-popup/keypress.js b/uni_modules/uni-popup/components/uni-popup/keypress.js new file mode 100644 index 0000000..16a5818 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + // this.$once('hook:beforeDestroy', () => { + // document.removeEventListener('keyup', listener) + // }) + }, + render: () => {} +} +// #endif diff --git a/uni_modules/uni-popup/components/uni-popup/popup.js b/uni_modules/uni-popup/components/uni-popup/popup.js new file mode 100644 index 0000000..a37fb9f --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/popup.js @@ -0,0 +1,26 @@ + +export default { + data() { + return { + + } + }, + created(){ + this.popup = this.getParent() + }, + methods:{ + /** + * 获取父元素实例 + */ + getParent(name = 'uniPopup') { + let parent = this.$parent; + let parentName = parent.$options.name; + while (parentName !== name) { + parent = parent.$parent; + if (!parent) return false + parentName = parent.$options.name; + } + return parent; + }, + } +} diff --git a/uni_modules/uni-popup/components/uni-popup/uni-popup.vue b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue new file mode 100644 index 0000000..54afee2 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue @@ -0,0 +1,473 @@ + + + + diff --git a/uni_modules/uni-popup/package.json b/uni_modules/uni-popup/package.json new file mode 100644 index 0000000..f40556b --- /dev/null +++ b/uni_modules/uni-popup/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-popup", + "displayName": "uni-popup 弹出层", + "version": "1.8.3", + "description": " Popup 组件,提供常用的弹层", + "keywords": [ + "uni-ui", + "弹出层", + "弹窗", + "popup", + "弹框" + ], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-transition" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-popup/readme.md b/uni_modules/uni-popup/readme.md new file mode 100644 index 0000000..fdad4b3 --- /dev/null +++ b/uni_modules/uni-popup/readme.md @@ -0,0 +1,17 @@ + + +## Popup 弹出层 +> **组件名:uni-popup** +> 代码块: `uPopup` +> 关联组件:`uni-transition` + + +弹出层组件,在应用中弹出一个消息提示窗口、提示框等 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-popup) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + + + diff --git a/uni_modules/uni-scss/changelog.md b/uni_modules/uni-scss/changelog.md new file mode 100644 index 0000000..b863bb0 --- /dev/null +++ b/uni_modules/uni-scss/changelog.md @@ -0,0 +1,8 @@ +## 1.0.3(2022-01-21) +- 优化 组件示例 +## 1.0.2(2021-11-22) +- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题 +## 1.0.1(2021-11-22) +- 修复 vue3中scss语法兼容问题 +## 1.0.0(2021-11-18) +- init diff --git a/uni_modules/uni-scss/index.scss b/uni_modules/uni-scss/index.scss new file mode 100644 index 0000000..1744a5f --- /dev/null +++ b/uni_modules/uni-scss/index.scss @@ -0,0 +1 @@ +@import './styles/index.scss'; diff --git a/uni_modules/uni-scss/package.json b/uni_modules/uni-scss/package.json new file mode 100644 index 0000000..7cc0ccb --- /dev/null +++ b/uni_modules/uni-scss/package.json @@ -0,0 +1,82 @@ +{ + "id": "uni-scss", + "displayName": "uni-scss 辅助样式", + "version": "1.0.3", + "description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。", + "keywords": [ + "uni-scss", + "uni-ui", + "辅助样式" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-scss/readme.md b/uni_modules/uni-scss/readme.md new file mode 100644 index 0000000..b7d1c25 --- /dev/null +++ b/uni_modules/uni-scss/readme.md @@ -0,0 +1,4 @@ +`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/index.scss b/uni_modules/uni-scss/styles/index.scss new file mode 100644 index 0000000..ffac4fe --- /dev/null +++ b/uni_modules/uni-scss/styles/index.scss @@ -0,0 +1,7 @@ +@import './setting/_variables.scss'; +@import './setting/_border.scss'; +@import './setting/_color.scss'; +@import './setting/_space.scss'; +@import './setting/_radius.scss'; +@import './setting/_text.scss'; +@import './setting/_styles.scss'; diff --git a/uni_modules/uni-scss/styles/setting/_border.scss b/uni_modules/uni-scss/styles/setting/_border.scss new file mode 100644 index 0000000..12a11c3 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_border.scss @@ -0,0 +1,3 @@ +.uni-border { + border: 1px $uni-border-1 solid; +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_color.scss b/uni_modules/uni-scss/styles/setting/_color.scss new file mode 100644 index 0000000..1ededd9 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_color.scss @@ -0,0 +1,66 @@ + +// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐 +// @mixin get-styles($k,$c) { +// @if $k == size or $k == weight{ +// font-#{$k}:#{$c} +// }@else{ +// #{$k}:#{$c} +// } +// } +$uni-ui-color:( + // 主色 + primary: $uni-primary, + primary-disable: $uni-primary-disable, + primary-light: $uni-primary-light, + // 辅助色 + success: $uni-success, + success-disable: $uni-success-disable, + success-light: $uni-success-light, + warning: $uni-warning, + warning-disable: $uni-warning-disable, + warning-light: $uni-warning-light, + error: $uni-error, + error-disable: $uni-error-disable, + error-light: $uni-error-light, + info: $uni-info, + info-disable: $uni-info-disable, + info-light: $uni-info-light, + // 中性色 + main-color: $uni-main-color, + base-color: $uni-base-color, + secondary-color: $uni-secondary-color, + extra-color: $uni-extra-color, + // 背景色 + bg-color: $uni-bg-color, + // 边框颜色 + border-1: $uni-border-1, + border-2: $uni-border-2, + border-3: $uni-border-3, + border-4: $uni-border-4, + // 黑色 + black:$uni-black, + // 白色 + white:$uni-white, + // 透明 + transparent:$uni-transparent +) !default; +@each $key, $child in $uni-ui-color { + .uni-#{"" + $key} { + color: $child; + } + .uni-#{"" + $key}-bg { + background-color: $child; + } +} +.uni-shadow-sm { + box-shadow: $uni-shadow-sm; +} +.uni-shadow-base { + box-shadow: $uni-shadow-base; +} +.uni-shadow-lg { + box-shadow: $uni-shadow-lg; +} +.uni-mask { + background-color:$uni-mask; +} diff --git a/uni_modules/uni-scss/styles/setting/_radius.scss b/uni_modules/uni-scss/styles/setting/_radius.scss new file mode 100644 index 0000000..9a0428b --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_radius.scss @@ -0,0 +1,55 @@ +@mixin radius($r,$d:null ,$important: false){ + $radius-value:map-get($uni-radius, $r) if($important, !important, null); + // Key exists within the $uni-radius variable + @if (map-has-key($uni-radius, $r) and $d){ + @if $d == t { + border-top-left-radius:$radius-value; + border-top-right-radius:$radius-value; + }@else if $d == r { + border-top-right-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == b { + border-bottom-left-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == l { + border-top-left-radius:$radius-value; + border-bottom-left-radius:$radius-value; + }@else if $d == tl { + border-top-left-radius:$radius-value; + }@else if $d == tr { + border-top-right-radius:$radius-value; + }@else if $d == br { + border-bottom-right-radius:$radius-value; + }@else if $d == bl { + border-bottom-left-radius:$radius-value; + } + }@else{ + border-radius:$radius-value; + } +} + +@each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $key} { + @include radius($key) + } + }@else{ + .uni-radius { + @include radius($key) + } + } +} + +@each $direction in t, r, b, l,tl, tr, br, bl { + @each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $direction}-#{"" + $key} { + @include radius($key,$direction,false) + } + }@else{ + .uni-radius-#{$direction} { + @include radius($key,$direction,false) + } + } + } +} diff --git a/uni_modules/uni-scss/styles/setting/_space.scss b/uni_modules/uni-scss/styles/setting/_space.scss new file mode 100644 index 0000000..3c89528 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_space.scss @@ -0,0 +1,56 @@ + +@mixin fn($space,$direction,$size,$n) { + @if $n { + #{$space}-#{$direction}: #{$size*$uni-space-root}px + } @else { + #{$space}-#{$direction}: #{-$size*$uni-space-root}px + } +} +@mixin get-styles($direction,$i,$space,$n){ + @if $direction == t { + @include fn($space, top,$i,$n); + } + @if $direction == r { + @include fn($space, right,$i,$n); + } + @if $direction == b { + @include fn($space, bottom,$i,$n); + } + @if $direction == l { + @include fn($space, left,$i,$n); + } + @if $direction == x { + @include fn($space, left,$i,$n); + @include fn($space, right,$i,$n); + } + @if $direction == y { + @include fn($space, top,$i,$n); + @include fn($space, bottom,$i,$n); + } + @if $direction == a { + @if $n { + #{$space}:#{$i*$uni-space-root}px; + } @else { + #{$space}:#{-$i*$uni-space-root}px; + } + } +} + +@each $orientation in m,p { + $space: margin; + @if $orientation == m { + $space: margin; + } @else { + $space: padding; + } + @for $i from 0 through 16 { + @each $direction in t, r, b, l, x, y, a { + .uni-#{$orientation}#{$direction}-#{$i} { + @include get-styles($direction,$i,$space,true); + } + .uni-#{$orientation}#{$direction}-n#{$i} { + @include get-styles($direction,$i,$space,false); + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_styles.scss b/uni_modules/uni-scss/styles/setting/_styles.scss new file mode 100644 index 0000000..689afec --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_styles.scss @@ -0,0 +1,167 @@ +/* #ifndef APP-NVUE */ + +$-color-white:#fff; +$-color-black:#000; +@mixin base-style($color) { + color: #fff; + background-color: $color; + border-color: mix($-color-black, $color, 8%); + &:not([hover-class]):active { + background: mix($-color-black, $color, 10%); + border-color: mix($-color-black, $color, 20%); + color: $-color-white; + outline: none; + } +} +@mixin is-color($color) { + @include base-style($color); + &[loading] { + @include base-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &[loading], + &:not([hover-class]):active { + color: $-color-white; + border-color: mix(darken($color,10%), $-color-white); + background-color: mix($color, $-color-white); + } + } + +} +@mixin base-plain-style($color) { + color:$color; + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 70%); + &:not([hover-class]):active { + background: mix($-color-white, $color, 80%); + color: $color; + outline: none; + border-color: mix($-color-white, $color, 50%); + } +} +@mixin is-plain($color){ + &[plain] { + @include base-plain-style($color); + &[loading] { + @include base-plain-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &:active { + color: mix($-color-white, $color, 40%); + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 80%); + } + } + } +} + + +.uni-btn { + margin: 5px; + color: #393939; + border:1px solid #ccc; + font-size: 16px; + font-weight: 200; + background-color: #F9F9F9; + // TODO 暂时处理边框隐藏一边的问题 + overflow: visible; + &::after{ + border: none; + } + + &:not([type]),&[type=default] { + color: #999; + &[loading] { + background: none; + &::before { + margin-right:5px; + } + } + + + + &[disabled]{ + color: mix($-color-white, #999, 60%); + &, + &[loading], + &:active { + color: mix($-color-white, #999, 60%); + background-color: mix($-color-white,$-color-black , 98%); + border-color: mix($-color-white, #999, 85%); + } + } + + &[plain] { + color: #999; + background: none; + border-color: $uni-border-1; + &:not([hover-class]):active { + background: none; + color: mix($-color-white, $-color-black, 80%); + border-color: mix($-color-white, $-color-black, 90%); + outline: none; + } + &[disabled]{ + &, + &[loading], + &:active { + background: none; + color: mix($-color-white, #999, 60%); + border-color: mix($-color-white, #999, 85%); + } + } + } + } + + &:not([hover-class]):active { + color: mix($-color-white, $-color-black, 50%); + } + + &[size=mini] { + font-size: 16px; + font-weight: 200; + border-radius: 8px; + } + + + + &.uni-btn-small { + font-size: 14px; + } + &.uni-btn-mini { + font-size: 12px; + } + + &.uni-btn-radius { + border-radius: 999px; + } + &[type=primary] { + @include is-color($uni-primary); + @include is-plain($uni-primary) + } + &[type=success] { + @include is-color($uni-success); + @include is-plain($uni-success) + } + &[type=error] { + @include is-color($uni-error); + @include is-plain($uni-error) + } + &[type=warning] { + @include is-color($uni-warning); + @include is-plain($uni-warning) + } + &[type=info] { + @include is-color($uni-info); + @include is-plain($uni-info) + } +} +/* #endif */ diff --git a/uni_modules/uni-scss/styles/setting/_text.scss b/uni_modules/uni-scss/styles/setting/_text.scss new file mode 100644 index 0000000..a34d08f --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_text.scss @@ -0,0 +1,24 @@ +@mixin get-styles($k,$c) { + @if $k == size or $k == weight{ + font-#{$k}:#{$c} + }@else{ + #{$k}:#{$c} + } +} + +@each $key, $child in $uni-headings { + /* #ifndef APP-NVUE */ + .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ + /* #ifdef APP-NVUE */ + .container .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ +} diff --git a/uni_modules/uni-scss/styles/setting/_variables.scss b/uni_modules/uni-scss/styles/setting/_variables.scss new file mode 100644 index 0000000..557d3d7 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_variables.scss @@ -0,0 +1,146 @@ +// @use "sass:math"; +@import '../tools/functions.scss'; +// 间距基础倍数 +$uni-space-root: 2 !default; +// 边框半径默认值 +$uni-radius-root:5px !default; +$uni-radius: () !default; +// 边框半径断点 +$uni-radius: map-deep-merge( + ( + 0: 0, + // TODO 当前版本暂时不支持 sm 属性 + // 'sm': math.div($uni-radius-root, 2), + null: $uni-radius-root, + 'lg': $uni-radius-root * 2, + 'xl': $uni-radius-root * 6, + 'pill': 9999px, + 'circle': 50% + ), + $uni-radius +); +// 字体家族 +$body-font-family: 'Roboto', sans-serif !default; +// 文本 +$heading-font-family: $body-font-family !default; +$uni-headings: () !default; +$letterSpacing: -0.01562em; +$uni-headings: map-deep-merge( + ( + 'h1': ( + size: 32px, + weight: 300, + line-height: 50px, + // letter-spacing:-0.01562em + ), + 'h2': ( + size: 28px, + weight: 300, + line-height: 40px, + // letter-spacing: -0.00833em + ), + 'h3': ( + size: 24px, + weight: 400, + line-height: 32px, + // letter-spacing: normal + ), + 'h4': ( + size: 20px, + weight: 400, + line-height: 30px, + // letter-spacing: 0.00735em + ), + 'h5': ( + size: 16px, + weight: 400, + line-height: 24px, + // letter-spacing: normal + ), + 'h6': ( + size: 14px, + weight: 500, + line-height: 18px, + // letter-spacing: 0.0125em + ), + 'subtitle': ( + size: 12px, + weight: 400, + line-height: 20px, + // letter-spacing: 0.00937em + ), + 'body': ( + font-size: 14px, + font-weight: 400, + line-height: 22px, + // letter-spacing: 0.03125em + ), + 'caption': ( + 'size': 12px, + 'weight': 400, + 'line-height': 20px, + // 'letter-spacing': 0.03333em, + // 'text-transform': false + ) + ), + $uni-headings +); + + + +// 主色 +$uni-primary: #2979ff !default; +$uni-primary-disable:lighten($uni-primary,20%) !default; +$uni-primary-light: lighten($uni-primary,25%) !default; + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37 !default; +$uni-success-disable:lighten($uni-success,20%) !default; +$uni-success-light: lighten($uni-success,25%) !default; + +$uni-warning: #f3a73f !default; +$uni-warning-disable:lighten($uni-warning,20%) !default; +$uni-warning-light: lighten($uni-warning,25%) !default; + +$uni-error: #e43d33 !default; +$uni-error-disable:lighten($uni-error,20%) !default; +$uni-error-light: lighten($uni-error,25%) !default; + +$uni-info: #8f939c !default; +$uni-info-disable:lighten($uni-info,20%) !default; +$uni-info-light: lighten($uni-info,25%) !default; + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a !default; // 主要文字 +$uni-base-color: #6a6a6a !default; // 常规文字 +$uni-secondary-color: #909399 !default; // 次要文字 +$uni-extra-color: #c7c7c7 !default; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0 !default; +$uni-border-2: #EDEDED !default; +$uni-border-3: #DCDCDC !default; +$uni-border-4: #B9B9B9 !default; + +// 常规色 +$uni-black: #000000 !default; +$uni-white: #ffffff !default; +$uni-transparent: rgba($color: #000000, $alpha: 0) !default; + +// 背景色 +$uni-bg-color: #f7f7f7 !default; + +/* 水平间距 */ +$uni-spacing-sm: 8px !default; +$uni-spacing-base: 15px !default; +$uni-spacing-lg: 30px !default; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default; +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default; +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default; + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4) !default; diff --git a/uni_modules/uni-scss/styles/tools/functions.scss b/uni_modules/uni-scss/styles/tools/functions.scss new file mode 100644 index 0000000..ac6f63e --- /dev/null +++ b/uni_modules/uni-scss/styles/tools/functions.scss @@ -0,0 +1,19 @@ +// 合并 map +@function map-deep-merge($parent-map, $child-map){ + $result: $parent-map; + @each $key, $child in $child-map { + $parent-has-key: map-has-key($result, $key); + $parent-value: map-get($result, $key); + $parent-type: type-of($parent-value); + $child-type: type-of($child); + $parent-is-map: $parent-type == map; + $child-is-map: $child-type == map; + + @if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){ + $result: map-merge($result, ( $key: $child )); + }@else { + $result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) )); + } + } + @return $result; +}; diff --git a/uni_modules/uni-scss/theme.scss b/uni_modules/uni-scss/theme.scss new file mode 100644 index 0000000..80ee62f --- /dev/null +++ b/uni_modules/uni-scss/theme.scss @@ -0,0 +1,31 @@ +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; +// 主色 +$uni-primary: #2979ff; +// 辅助色 +$uni-success: #4cd964; +// 警告色 +$uni-warning: #f0ad4e; +// 错误色 +$uni-error: #dd524d; +// 描述色 +$uni-info: #909399; +// 中性色 +$uni-main-color: #303133; +$uni-base-color: #606266; +$uni-secondary-color: #909399; +$uni-extra-color: #C0C4CC; +// 背景色 +$uni-bg-color: #f5f5f5; +// 边框颜色 +$uni-border-1: #DCDFE6; +$uni-border-2: #E4E7ED; +$uni-border-3: #EBEEF5; +$uni-border-4: #F2F6FC; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); diff --git a/uni_modules/uni-scss/variables.scss b/uni_modules/uni-scss/variables.scss new file mode 100644 index 0000000..1c062d4 --- /dev/null +++ b/uni_modules/uni-scss/variables.scss @@ -0,0 +1,62 @@ +@import './styles/setting/_variables.scss'; +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; + +// 主色 +$uni-primary: #2979ff; +$uni-primary-disable:mix(#fff,$uni-primary,50%); +$uni-primary-light: mix(#fff,$uni-primary,80%); + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37; +$uni-success-disable:mix(#fff,$uni-success,50%); +$uni-success-light: mix(#fff,$uni-success,80%); + +$uni-warning: #f3a73f; +$uni-warning-disable:mix(#fff,$uni-warning,50%); +$uni-warning-light: mix(#fff,$uni-warning,80%); + +$uni-error: #e43d33; +$uni-error-disable:mix(#fff,$uni-error,50%); +$uni-error-light: mix(#fff,$uni-error,80%); + +$uni-info: #8f939c; +$uni-info-disable:mix(#fff,$uni-info,50%); +$uni-info-light: mix(#fff,$uni-info,80%); + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a; // 主要文字 +$uni-base-color: #6a6a6a; // 常规文字 +$uni-secondary-color: #909399; // 次要文字 +$uni-extra-color: #c7c7c7; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0; +$uni-border-2: #EDEDED; +$uni-border-3: #DCDCDC; +$uni-border-4: #B9B9B9; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); + +// 背景色 +$uni-bg-color: #f7f7f7; + +/* 水平间距 */ +$uni-spacing-sm: 8px; +$uni-spacing-base: 15px; +$uni-spacing-lg: 30px; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5); +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2); +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5); + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4); diff --git a/uni_modules/uni-transition/changelog.md b/uni_modules/uni-transition/changelog.md new file mode 100644 index 0000000..70c1cd4 --- /dev/null +++ b/uni_modules/uni-transition/changelog.md @@ -0,0 +1,22 @@ +## 1.3.2(2023-05-04) +- 修复 NVUE 平台报错的问题 +## 1.3.1(2021-11-23) +- 修复 init 方法初始化问题 +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-transition](https://uniapp.dcloud.io/component/uniui/uni-transition) +## 1.2.1(2021-09-27) +- 修复 init 方法不生效的 Bug +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.1(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的 Bug +## 1.1.0(2021-04-22) +- 新增 通过方法自定义动画 +- 新增 custom-class 非 NVUE 平台支持自定义 class 定制样式 +- 优化 动画触发逻辑,使动画更流畅 +- 优化 支持单独的动画类型 +- 优化 文档示例 +## 1.0.2(2021-02-05) +- 调整为 uni_modules 目录规范 diff --git a/uni_modules/uni-transition/components/uni-transition/createAnimation.js b/uni_modules/uni-transition/components/uni-transition/createAnimation.js new file mode 100644 index 0000000..8f89b18 --- /dev/null +++ b/uni_modules/uni-transition/components/uni-transition/createAnimation.js @@ -0,0 +1,131 @@ +// const defaultOption = { +// duration: 300, +// timingFunction: 'linear', +// delay: 0, +// transformOrigin: '50% 50% 0' +// } +// #ifdef APP-NVUE +const nvueAnimation = uni.requireNativePlugin('animation') +// #endif +class MPAnimation { + constructor(options, _this) { + this.options = options + // 在iOS10+QQ小程序平台下,传给原生的对象一定是个普通对象而不是Proxy对象,否则会报parameter should be Object instead of ProxyObject的错误 + this.animation = uni.createAnimation({ + ...options + }) + this.currentStepAnimates = {} + this.next = 0 + this.$ = _this + + } + + _nvuePushAnimates(type, args) { + let aniObj = this.currentStepAnimates[this.next] + let styles = {} + if (!aniObj) { + styles = { + styles: {}, + config: {} + } + } else { + styles = aniObj + } + if (animateTypes1.includes(type)) { + if (!styles.styles.transform) { + styles.styles.transform = '' + } + let unit = '' + if(type === 'rotate'){ + unit = 'deg' + } + styles.styles.transform += `${type}(${args+unit}) ` + } else { + styles.styles[type] = `${args}` + } + this.currentStepAnimates[this.next] = styles + } + _animateRun(styles = {}, config = {}) { + let ref = this.$.$refs['ani'].ref + if (!ref) return + return new Promise((resolve, reject) => { + nvueAnimation.transition(ref, { + styles, + ...config + }, res => { + resolve() + }) + }) + } + + _nvueNextAnimate(animates, step = 0, fn) { + let obj = animates[step] + if (obj) { + let { + styles, + config + } = obj + this._animateRun(styles, config).then(() => { + step += 1 + this._nvueNextAnimate(animates, step, fn) + }) + } else { + this.currentStepAnimates = {} + typeof fn === 'function' && fn() + this.isEnd = true + } + } + + step(config = {}) { + // #ifndef APP-NVUE + this.animation.step(config) + // #endif + // #ifdef APP-NVUE + this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config) + this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin + this.next++ + // #endif + return this + } + + run(fn) { + // #ifndef APP-NVUE + this.$.animationData = this.animation.export() + this.$.timer = setTimeout(() => { + typeof fn === 'function' && fn() + }, this.$.durationTime) + // #endif + // #ifdef APP-NVUE + this.isEnd = false + let ref = this.$.$refs['ani'] && this.$.$refs['ani'].ref + if(!ref) return + this._nvueNextAnimate(this.currentStepAnimates, 0, fn) + this.next = 0 + // #endif + } +} + + +const animateTypes1 = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d', + 'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY', + 'translateZ' +] +const animateTypes2 = ['opacity', 'backgroundColor'] +const animateTypes3 = ['width', 'height', 'left', 'right', 'top', 'bottom'] +animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => { + MPAnimation.prototype[type] = function(...args) { + // #ifndef APP-NVUE + this.animation[type](...args) + // #endif + // #ifdef APP-NVUE + this._nvuePushAnimates(type, args) + // #endif + return this + } +}) + +export function createAnimation(option, _this) { + if(!_this) return + clearTimeout(_this.timer) + return new MPAnimation(option, _this) +} diff --git a/uni_modules/uni-transition/components/uni-transition/uni-transition.vue b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue new file mode 100644 index 0000000..bfbba93 --- /dev/null +++ b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue @@ -0,0 +1,286 @@ + + + + + diff --git a/uni_modules/uni-transition/package.json b/uni_modules/uni-transition/package.json new file mode 100644 index 0000000..ea995a2 --- /dev/null +++ b/uni_modules/uni-transition/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-transition", + "displayName": "uni-transition 过渡动画", + "version": "1.3.2", + "description": "元素的简单过渡动画", + "keywords": [ + "uni-ui", + "uniui", + "动画", + "过渡", + "过渡动画" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-transition/readme.md b/uni_modules/uni-transition/readme.md new file mode 100644 index 0000000..2f8a77e --- /dev/null +++ b/uni_modules/uni-transition/readme.md @@ -0,0 +1,11 @@ + + +## Transition 过渡动画 +> **组件名:uni-transition** +> 代码块: `uTransition` + + +元素过渡动画 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-transition) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/utils/index.js b/utils/index.js new file mode 100644 index 0000000..4f17dc7 --- /dev/null +++ b/utils/index.js @@ -0,0 +1,81 @@ +import config from '../config'; +export default { + // 控制字符长度 + controlLength: (str, len = 10) => { + if (!str) return ""; + if (str.length > len) return str.slice(0, len) + "..." + return str; + }, + uploadFile:(chooseImageRes) => { + const tempFilePaths = chooseImageRes.tempFilePaths; + uni.uploadFile({ + url:`${config.baseUrl}/upload`, + filePath: tempFilePaths[0], + name: 'file', + header:{ + 'Authorization':token.value, + 'x-token':token.value + }, + success: (res) => { + var f_res = JSON.parse(res.data) + // if(f_res.code === 0){ + // userInfo.value.avatar = f_res.data + // } + } + }); + }, + timestampToDate(stamp) { // 时间戳转日期 + var time = new Date(stamp); + var y = time.getFullYear(); + var m = time.getMonth()+1; + var d = time.getDate(); + const date = `${y}-${m}-${d}` + return date + }, + datatime(time){ // 获取近五天的日期数组 + var myDate = new Date(); //获取当天日期 + myDate.setDate(myDate.getDate()); + // console.log(myDate.getFullYear())//年 + // console.log(myDate.getMonth())//月0-11 + // console.log(myDate.getDate())//日 + var dateArray = []; + var dateTemp; + var flag = 1; + // 日期格式化 + for (var i = 0; i < time; i++) { + let month = 0; + // 月小于10,在前面加‘0’;因为月从0开始,故需+1 + if (myDate.getMonth() + 1 < 10) { + month = '0' + (myDate.getMonth() + 1); + } else { + month = myDate.getMonth() + 1; + } + let day = 0; + // 日小于10,在前加0 + if (myDate.getDate() < 10) { + day = '0' + myDate.getDate(); + } else { + day = myDate.getDate(); + } + // YY-MM-DD + dateTemp = myDate.getFullYear() + '-' + month + '-' + day; + dateArray.push(dateTemp); + // console.log(dateArray) + //若不加flag则结果都是一个日期(当前日期减time天) + //日期 +1 天,此日期为减time天后的日期 + myDate.setDate(myDate.getDate() + flag); + } + return dateArray + }, + getDistances(lat1, lng1, lat2, lng2) { // 根据经纬度计算距离,参数分别为第一点的纬度,经度;第二点的纬度,经度 + let EARTH_RADIUS = 6378.137;// 地球半径 + let radLat1 = lat1 * Math.PI / 180.0; //lat1 * Math.PI / 180.0=>弧度计算 + let radLat2 = lat2 * Math.PI / 180.0; + let a = radLat1 - radLat2; + let b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0; + let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2))); + s = s * EARTH_RADIUS; + s = Math.round(s * 10000) / 10000;// 输出为公里 + return { m: s * 1000, km: Number(s.toFixed(2)) } + } +} \ No newline at end of file

+ +
+
npm +