papayaui 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  - 💪 Vue 3 Composition API
6
6
  - 🔥 Written in TypeScript
7
+ - 🧀 [Document](https://jiangwei58.github.io/papayaui)
7
8
 
8
9
  ## 准备工作
9
10
 
@@ -83,8 +84,6 @@ pnpm install async-validator dayjs
83
84
  // ...
84
85
  "types": ["papayaui/global"]
85
86
  },
86
- // 防止组件props类型识别错误
87
- "include": ["node_modules/papayaui/components/*/*.vue"]
88
87
  }
89
88
  ```
90
89
 
@@ -9,8 +9,9 @@
9
9
  :bg-color="bgColor"
10
10
  :closeable="closeable"
11
11
  :round="round"
12
- :close-on-click-overlay="maskCloseAble"
12
+ :close-on-click-overlay="closeOnClickOverlay ?? maskCloseAble"
13
13
  :safe-area-inset-bottom="false"
14
+ :duration="duration"
14
15
  @update:show="emit('update:show', !!$event)"
15
16
  @open="emit('open')"
16
17
  @opened="emit('opened')"
@@ -3,7 +3,15 @@ import { pick } from '../../utils'
3
3
  import { popupEmits, popupProps } from '../popup/props'
4
4
 
5
5
  export const bottomPopupProps = {
6
- ...pick(popupProps, ['show', 'zIndex', 'overlay', 'bgColor', 'safeAreaInsetBottom']),
6
+ ...pick(popupProps, [
7
+ 'show',
8
+ 'zIndex',
9
+ 'overlay',
10
+ 'bgColor',
11
+ 'safeAreaInsetBottom',
12
+ 'closeOnClickOverlay',
13
+ 'duration',
14
+ ]),
7
15
  /**
8
16
  * 标题
9
17
  */
@@ -31,6 +39,7 @@ export const bottomPopupProps = {
31
39
  },
32
40
  /**
33
41
  * 是否可以点击空白处关闭
42
+ * @deprecated 即将移除,统一使用 `closeOnClickOverlay`属性
34
43
  */
35
44
  maskCloseAble: popupProps.closeOnClickOverlay,
36
45
  }
@@ -3,7 +3,14 @@
3
3
  :show="show"
4
4
  :title="title"
5
5
  :height="height"
6
+ :round="round"
7
+ :z-index="zIndex"
8
+ :overlay="overlay"
9
+ :bg-color="bgColor"
10
+ :closeable="closeable"
11
+ :close-on-click-overlay="closeOnClickOverlay"
6
12
  :safe-area-inset-bottom="false"
13
+ :duration="duration"
7
14
  @update:show="emit('update:show', $event as boolean)"
8
15
  @open="emit('open')"
9
16
  @opened="emit('opened')"
@@ -1,7 +1,7 @@
1
- import type { ExtractPropTypes, CSSProperties, PropType } from 'vue'
1
+ import type { CSSProperties, ExtractPropTypes, PropType } from 'vue'
2
2
  import type { TreeNode, UseTreeFieldNames } from '../../core/useTree'
3
3
  import { defaultFieldNames } from '../../core/useTree'
4
- import { isArray, isObject, pick } from '../../utils'
4
+ import { isArray, isObject } from '../../utils'
5
5
  import { bottomPopupEmits, bottomPopupProps } from '../bottom-popup/props'
6
6
 
7
7
  export interface CascaderNode<T = any> {
@@ -13,7 +13,7 @@ export type CascaderOption = any
13
13
  export type CascaderValue = any
14
14
 
15
15
  export const cascaderProps = {
16
- ...pick(bottomPopupProps, ['show', 'height', 'title', 'safeAreaInsetBottom']),
16
+ ...bottomPopupProps,
17
17
  /**
18
18
  * 值
19
19
  */
@@ -0,0 +1,19 @@
1
+ @import '../../styles/vars.scss';
2
+
3
+ .#{$prefix}-circle {
4
+ position: relative;
5
+ display: inline-block;
6
+ text-align: center;
7
+
8
+ &__text {
9
+ position: absolute;
10
+ top: 50%;
11
+ left: 0;
12
+ width: 100%;
13
+ color: _var(circle-text-color, _var(color-black));
14
+ font-weight: _var(circle-font-weight, 500);
15
+ font-size: _var(circle-font-size, 14px);
16
+ line-height: _var(circle-text-line-height, 20px);
17
+ transform: translateY(-50%);
18
+ }
19
+ }
@@ -0,0 +1,163 @@
1
+ <template>
2
+ <view :class="ns.b()">
3
+ <canvas
4
+ :id="id"
5
+ :canvas-id="id"
6
+ type="2d"
7
+ :style="{
8
+ width: getUnitValue(size, 'px'),
9
+ height: getUnitValue(size, 'px'),
10
+ }"
11
+ />
12
+ <view v-if="!text" :class="ns.e('text')">
13
+ <slot></slot>
14
+ </view>
15
+ <cover-view v-else :class="ns.e('text')">{{ text }}</cover-view>
16
+ </view>
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import { getCurrentInstance, onMounted, watch } from 'vue'
21
+ import { useNamespace } from '../../core'
22
+ import { getUnitValue } from '../../utils'
23
+ import { circleProps } from './props'
24
+
25
+ const ns = useNamespace('circle')
26
+
27
+ const props = defineProps(circleProps)
28
+
29
+ const instance = getCurrentInstance()
30
+ const id = ns.e('canvas') + Date.now()
31
+
32
+ const BEGIN_ANGLE = -Math.PI / 2
33
+ const PERIMETER = 2 * Math.PI
34
+ const STEP = 1
35
+
36
+ let context: CanvasRenderingContext2D | null = null
37
+ let currentValue = 0
38
+
39
+ onMounted(() => {
40
+ // #ifdef H5
41
+ initH5()
42
+ // #endif
43
+ // #ifndef H5
44
+ initMP()
45
+ // #endif
46
+ })
47
+
48
+ watch(
49
+ () => props.modelValue,
50
+ () => {
51
+ if (context) {
52
+ renderCircle(context)
53
+ }
54
+ },
55
+ )
56
+
57
+ const initMP = () => {
58
+ const ratio = uni.getSystemInfoSync().pixelRatio
59
+ const query = uni.createSelectorQuery()
60
+ query
61
+ .in(instance)
62
+ .select('#' + id)
63
+ .node(() => {})
64
+ .exec((res) => {
65
+ const canvas = res[0].node as HTMLCanvasElement
66
+ const canvasSize = props.size * ratio
67
+ canvas.width = canvasSize
68
+ canvas.height = canvasSize
69
+ context = canvas.getContext('2d')
70
+ if (!context) return
71
+
72
+ context.scale(ratio, ratio)
73
+ renderCircle(context)
74
+ })
75
+ }
76
+
77
+ const initH5 = () => {
78
+ const ratio = window.devicePixelRatio
79
+ const canvasSize = props.size * ratio
80
+ const canvas = document.querySelector(`#${id} canvas`) as HTMLCanvasElement
81
+ canvas.width = canvasSize
82
+ canvas.height = canvasSize
83
+ context = canvas.getContext('2d')
84
+ if (!context) return
85
+
86
+ context.scale(ratio, ratio)
87
+ renderCircle(context)
88
+ }
89
+
90
+ const renderCircle = (ctx: CanvasRenderingContext2D) => {
91
+ if (props.speed <= 0 || props.speed > 1000) {
92
+ drawCircle(ctx, props.modelValue)
93
+ return
94
+ }
95
+
96
+ let interval: number | null
97
+ currentValue = currentValue ?? 0
98
+ const run = () => {
99
+ interval = setTimeout(() => {
100
+ if (currentValue === props.modelValue) {
101
+ stop()
102
+ return
103
+ }
104
+ if (Math.abs(currentValue - props.modelValue) < STEP) {
105
+ currentValue = props.modelValue
106
+ } else if (currentValue < props.modelValue) {
107
+ currentValue += STEP
108
+ } else {
109
+ currentValue -= STEP
110
+ }
111
+ drawCircle(ctx, currentValue)
112
+ run()
113
+ }, 1000 / props.speed) as unknown as number | null
114
+ }
115
+
116
+ const stop = () => {
117
+ if (interval) {
118
+ clearTimeout(interval)
119
+ interval = null
120
+ }
121
+ }
122
+
123
+ stop()
124
+ run()
125
+ }
126
+
127
+ const drawLayerCircle = (ctx: CanvasRenderingContext2D) => {
128
+ drawCanvas(ctx, BEGIN_ANGLE, PERIMETER, props.layerColor)
129
+ }
130
+
131
+ const drawCircle = (ctx: CanvasRenderingContext2D, value: number) => {
132
+ const progress = PERIMETER * (value / 100)
133
+ const endAngle = props.clockwise ? BEGIN_ANGLE + progress : 3 * Math.PI - (BEGIN_ANGLE + progress)
134
+ ctx.clearRect(0, 0, props.size, props.size)
135
+ drawLayerCircle(ctx)
136
+ if (value !== 0) {
137
+ drawCanvas(ctx, BEGIN_ANGLE, endAngle, props.color, props.clockwise)
138
+ }
139
+ }
140
+
141
+ const drawCanvas = (
142
+ ctx: CanvasRenderingContext2D,
143
+ sRadian: number,
144
+ eRadian: number,
145
+ color: string,
146
+ clockwise = true,
147
+ ) => {
148
+ const position = props.size / 2
149
+ const lineWidth = Number(props.strokeWidth)
150
+ const radius = position - lineWidth / 2
151
+
152
+ ctx.beginPath()
153
+ ctx.lineCap = 'round'
154
+ ctx.strokeStyle = color
155
+ ctx.lineWidth = lineWidth
156
+ ctx.arc(position, position, radius, sRadian, eRadian, !clockwise)
157
+ ctx.stroke()
158
+ }
159
+ </script>
160
+
161
+ <style lang="scss" scoped>
162
+ @import './circle.scss';
163
+ </style>
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <DocDemoBlock title="基础用法" card>
3
+ <Demo1 />
4
+ </DocDemoBlock>
5
+ <DocDemoBlock title="样式定制" card>
6
+ <Demo2 />
7
+ </DocDemoBlock>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import DocDemoBlock from '../../doc/doc-demo-block.vue'
12
+ import Demo1 from '../../demos/circle/demo-1.vue'
13
+ import Demo2 from '../../demos/circle/demo-2.vue'
14
+ </script>
15
+
16
+ <style lang="scss" scoped></style>
17
+ <style lang="scss">
18
+ page {
19
+ background-color: var(--pa-color-gray);
20
+ }
21
+ </style>
@@ -0,0 +1,4 @@
1
+ import type Circle from './circle.vue'
2
+
3
+ export type CircleInstance = InstanceType<typeof Circle>
4
+ export * from './props'
@@ -0,0 +1,59 @@
1
+ import type { ExtractPropTypes } from 'vue'
2
+
3
+ export const circleProps = {
4
+ /**
5
+ * 目标进度
6
+ */
7
+ modelValue: {
8
+ type: Number,
9
+ default: 0,
10
+ },
11
+ /**
12
+ * 圆环直径,单位px
13
+ */
14
+ size: {
15
+ type: Number,
16
+ default: 100,
17
+ },
18
+ /**
19
+ * 进度条颜色
20
+ */
21
+ color: {
22
+ type: String,
23
+ default: '#009c5d',
24
+ },
25
+ /**
26
+ * 轨道颜色
27
+ */
28
+ layerColor: {
29
+ type: String,
30
+ default: '#fff',
31
+ },
32
+ /**
33
+ * 文字
34
+ */
35
+ text: String,
36
+ /**
37
+ * 进度条宽度,单位px
38
+ */
39
+ strokeWidth: {
40
+ type: [Number, String],
41
+ default: 4,
42
+ },
43
+ /**
44
+ * 是否顺时针
45
+ */
46
+ clockwise: {
47
+ type: Boolean,
48
+ default: true,
49
+ },
50
+ /**
51
+ * 动画速度(单位为 value/s)
52
+ */
53
+ speed: {
54
+ type: Number,
55
+ default: 50,
56
+ },
57
+ }
58
+
59
+ export type CircleProps = ExtractPropTypes<typeof circleProps>
@@ -8,6 +8,7 @@ export * from './cell-group'
8
8
  export * from './checkbox'
9
9
  export * from './checkbox-btns'
10
10
  export * from './checkbox-group'
11
+ export * from './circle'
11
12
  export * from './collapse'
12
13
  export * from './collapse-item'
13
14
  export * from './container'
@@ -4,7 +4,14 @@
4
4
  :show="show"
5
5
  :title="title"
6
6
  :height="height"
7
+ :round="round"
8
+ :z-index="zIndex"
9
+ :overlay="overlay"
10
+ :bg-color="bgColor"
11
+ :closeable="closeable"
12
+ :close-on-click-overlay="closeOnClickOverlay"
7
13
  :safe-area-inset-bottom="false"
14
+ :duration="duration"
8
15
  @update:show="emit('update:show', $event as boolean)"
9
16
  @open="emit('open')"
10
17
  @opened="emit('opened')"
@@ -1,13 +1,13 @@
1
- import type { ExtractPropTypes, CSSProperties, PropType } from 'vue'
1
+ import type { CSSProperties, ExtractPropTypes, PropType } from 'vue'
2
2
  import type { UseListProps } from '../../core/useList'
3
- import { isArray, isNumber, isObject, isString, pick } from '../../utils'
3
+ import { isArray, isNumber, isObject, isString } from '../../utils'
4
4
  import { bottomPopupEmits, bottomPopupProps } from '../bottom-popup/props'
5
5
 
6
6
  export type Option = any
7
7
  export type OptionValue = number | string
8
8
 
9
9
  export const pickerPopupProps = {
10
- ...pick(bottomPopupProps, ['show', 'height', 'title', 'safeAreaInsetBottom']),
10
+ ...bottomPopupProps,
11
11
  /**
12
12
  * 选择的值
13
13
  */
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <pa-circle :model-value="80" />
3
+ </template>
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <view>
3
+ <pa-circle :model-value="progress" stroke-width="8" text="设置宽度" />
4
+ <pa-circle :model-value="progress" color="#ff2b2b" text="设置颜色" />
5
+ <pa-circle :model-value="progress" :clockwise="false" text="逆时针" />
6
+ <pa-circle :model-value="progress" :size="150" text="设置大小" />
7
+ </view>
8
+ <view class="mt-15">
9
+ <pa-button type="primary" @click="add">增加</pa-button>
10
+ <pa-button type="danger" class="ml-15" @click="subtract">减少</pa-button>
11
+ </view>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { ref } from 'vue'
16
+
17
+ const STEP = 10
18
+ const progress = ref(80)
19
+
20
+ const add = () => {
21
+ if (progress.value >= 100) return
22
+ progress.value += STEP
23
+ }
24
+
25
+ const subtract = () => {
26
+ if (progress.value <= 0) return
27
+ progress.value -= STEP
28
+ }
29
+ </script>
30
+
31
+ <style lang="scss" scoped>
32
+ :deep(.pa-circle) {
33
+ margin-right: 15px;
34
+ }
35
+ </style>
package/global.d.ts CHANGED
@@ -10,6 +10,7 @@ declare module '@vue/runtime-core' {
10
10
  PaCheckbox: typeof import('papayaui/components/checkbox/checkbox.vue')['default']
11
11
  PaCheckboxBtns: typeof import('papayaui/components/checkbox-btns/checkbox-btns.vue')['default']
12
12
  PaCheckboxGroup: typeof import('papayaui/components/checkbox-group/checkbox-group.vue')['default']
13
+ PaCircle: typeof import('papayaui/components/circle/circle.vue')['default']
13
14
  PaCollapse: typeof import('papayaui/components/collapse/collapse.vue')['default']
14
15
  PaCollapseItem: typeof import('papayaui/components/collapse-item/collapse-item.vue')['default']
15
16
  PaContainer: typeof import('papayaui/components/container/container.vue')['default']
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "papayaui",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "适用于uniapp的ui扩展库",
5
5
  "packageManager": "pnpm@8.6.0",
6
6
  "dependencies": {
@@ -18,7 +18,7 @@
18
18
  "bugs": {
19
19
  "url": "https://github.com/jiangwei58/papayaui/issues"
20
20
  },
21
- "homepage": "https://github.com/jiangwei58/papayaui",
21
+ "homepage": "https://jiangwei58.github.io/papayaui",
22
22
  "author": "jiangw",
23
23
  "license": "MIT",
24
24
  "main": "index.ts",
@@ -60,9 +60,15 @@
60
60
  // 定义圆角
61
61
  @for $i from 3 through 35 {
62
62
  .rounded-#{$i} {
63
- border-radius: #{$i}rpx;
63
+ border-radius: $i + $pixelUnit;
64
64
  }
65
65
  }
66
+ .rounded-none {
67
+ border-radius: 0;
68
+ }
69
+ .rounded-full {
70
+ border-radius: 9999px;
71
+ }
66
72
 
67
73
  // 盒子模型
68
74
  .box-border {
@@ -1,14 +1,14 @@
1
- // 定义字体(rpx单位)
1
+ // 定义字体大小
2
2
  @for $i from 20 through 65 {
3
3
  .text-#{$i} {
4
- font-size: #{$i}rpx;
4
+ font-size: $i + $pixelUnit;
5
5
  }
6
6
  }
7
7
 
8
8
  // 定义字体行高
9
9
  @for $i from 10 through 65 {
10
10
  .leading-#{$i} {
11
- line-height: #{$i}rpx;
11
+ line-height: $i + $pixelUnit;
12
12
  }
13
13
  }
14
14
 
@@ -62,13 +62,13 @@
62
62
  // 只要双数和能被5除尽的数
63
63
  @if $i % 2 == 0 or $i % 5 == 0 {
64
64
  .gap-#{$i} {
65
- gap: $i + rpx;
65
+ gap: $i + $pixelUnit;
66
66
  }
67
67
  .gap-x-#{$i} {
68
- column-gap: $i + rpx;
68
+ column-gap: $i + $pixelUnit;
69
69
  }
70
70
  .gap-y-#{$i} {
71
- row-gap: $i + rpx;
71
+ row-gap: $i + $pixelUnit;
72
72
  }
73
73
  }
74
74
  }
@@ -3,37 +3,37 @@
3
3
  // 只要双数和能被5除尽的数
4
4
  @if $i % 2 == 0 or $i % 5 == 0 {
5
5
  .m-#{$i} {
6
- margin: $i + rpx !important;
6
+ margin: $i + $pixelUnit !important;
7
7
  }
8
8
 
9
9
  .p-#{$i} {
10
- padding: $i + rpx !important;
10
+ padding: $i + $pixelUnit !important;
11
11
  }
12
12
 
13
13
  .mx-#{$i} {
14
- margin-left: $i + rpx;
15
- margin-right: $i + rpx;
14
+ margin-left: $i + $pixelUnit;
15
+ margin-right: $i + $pixelUnit;
16
16
  }
17
17
  .my-#{$i} {
18
- margin-top: $i + rpx;
19
- margin-bottom: $i + rpx;
18
+ margin-top: $i + $pixelUnit;
19
+ margin-bottom: $i + $pixelUnit;
20
20
  }
21
21
  .px-#{$i} {
22
- padding-left: $i + rpx;
23
- padding-right: $i + rpx;
22
+ padding-left: $i + $pixelUnit;
23
+ padding-right: $i + $pixelUnit;
24
24
  }
25
25
  .py-#{$i} {
26
- padding-top: $i + rpx;
27
- padding-bottom: $i + rpx;
26
+ padding-top: $i + $pixelUnit;
27
+ padding-bottom: $i + $pixelUnit;
28
28
  }
29
29
 
30
30
  @each $short, $long in l left, t top, r right, b bottom {
31
31
  .m#{$short}-#{$i} {
32
- margin-#{$long}: $i + rpx !important;
32
+ margin-#{$long}: $i + $pixelUnit !important;
33
33
  }
34
34
 
35
35
  .p#{$short}-#{$i} {
36
- padding-#{$long}: $i + rpx !important;
36
+ padding-#{$long}: $i + $pixelUnit !important;
37
37
  }
38
38
  }
39
39
  }
package/styles/vars.scss CHANGED
@@ -1,4 +1,5 @@
1
- $prefix: pa;
1
+ $prefix: pa !default;
2
+ $pixelUnit: rpx !default;
2
3
 
3
4
  @function _var($varName, $default: null) {
4
5
  @if ($default == null) {
package/.DS_Store DELETED
Binary file
@@ -1,14 +0,0 @@
1
- import { defaultNamespace } from '../../core'
2
-
3
- const Dialog = () => {
4
- const node = uni
5
- .createSelectorQuery()
6
- .select(`#${defaultNamespace}-dialog`)
7
- .node((result) => {
8
- console.log('result', result)
9
- })
10
- .exec()
11
- console.log(node)
12
- }
13
-
14
- export default Dialog
package/fonts/.DS_Store DELETED
Binary file
package/images/.DS_Store DELETED
Binary file