reborn-ui 0.1.76 → 0.1.78

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.
Files changed (50) hide show
  1. package/dist/index.js +182 -240
  2. package/dist/index.js.map +1 -1
  3. package/package.json +53 -53
  4. package/registry/components/reborn-affix.json +8 -3
  5. package/registry/components/reborn-back-top.json +9 -4
  6. package/registry/components/reborn-badge.json +11 -5
  7. package/registry/components/reborn-button.json +5 -5
  8. package/registry/components/reborn-card.json +18 -0
  9. package/registry/components/reborn-cascader.json +18 -0
  10. package/registry/components/reborn-checkbox.json +4 -4
  11. package/registry/components/reborn-chip.json +11 -5
  12. package/registry/components/reborn-collapse.json +11 -5
  13. package/registry/components/reborn-color-picker.json +50 -0
  14. package/registry/components/reborn-draggable.json +32 -0
  15. package/registry/components/reborn-drawer.json +17 -0
  16. package/registry/components/reborn-dropdown-select.json +18 -0
  17. package/registry/components/reborn-footer.json +40 -0
  18. package/registry/components/reborn-form.json +11 -6
  19. package/registry/components/reborn-image.json +10 -5
  20. package/registry/components/reborn-input-number.json +12 -6
  21. package/registry/components/reborn-input-otp.json +40 -0
  22. package/registry/components/reborn-input.json +4 -4
  23. package/registry/components/reborn-loading.json +23 -0
  24. package/registry/components/reborn-loadmore.json +23 -0
  25. package/registry/components/reborn-overlay.json +38 -0
  26. package/registry/components/reborn-page.json +18 -0
  27. package/registry/components/reborn-picker-view.json +26 -0
  28. package/registry/components/reborn-popover.json +58 -0
  29. package/registry/components/reborn-popup.json +23 -0
  30. package/registry/components/reborn-qrcode.json +45 -0
  31. package/registry/components/reborn-radio.json +45 -0
  32. package/registry/components/reborn-rate.json +40 -0
  33. package/registry/components/reborn-root-portal.json +26 -0
  34. package/registry/components/reborn-select-date.json +40 -0
  35. package/registry/components/reborn-select-trigger.json +25 -0
  36. package/registry/components/reborn-select.json +41 -0
  37. package/registry/components/reborn-slider.json +40 -0
  38. package/registry/components/reborn-sticky.json +12 -6
  39. package/registry/components/reborn-switch.json +13 -7
  40. package/registry/components/reborn-tabbar.json +38 -0
  41. package/registry/components/reborn-tabs copy.json +46 -0
  42. package/registry/components/reborn-tabs-test.json +46 -0
  43. package/registry/components/reborn-tabs.json +12 -6
  44. package/registry/components/reborn-text.json +34 -0
  45. package/registry/components/reborn-textarea.json +5 -5
  46. package/registry/components/reborn-toast.json +38 -0
  47. package/registry/components/reborn-transition.json +38 -0
  48. package/registry/components/reborn-waterfall.json +18 -0
  49. package/registry/components/scroll-island.json +2 -2
  50. package/registry/registry.json +1101 -97
package/package.json CHANGED
@@ -1,53 +1,53 @@
1
- {
2
- "name": "reborn-ui",
3
- "version": "0.1.76",
4
- "description": "A CLI for Reborn UI",
5
- "author": "1997liuyh-boop",
6
- "license": "MIT",
7
- "repository": {
8
- "type": "git",
9
- "url": "https://github.com/1997liuyh-boop/Reborn-UI.git"
10
- },
11
- "type": "module",
12
- "bin": {
13
- "reborn-ui": "dist/index.js"
14
- },
15
- "files": [
16
- "dist",
17
- "registry",
18
- "README.md"
19
- ],
20
- "publishConfig": {
21
- "access": "public"
22
- },
23
- "scripts": {
24
- "cli": "tsx src/index.ts",
25
- "build": "tsup",
26
- "dev": "tsx src/index.ts",
27
- "clean": "rimraf dist",
28
- "prepare": "tsup",
29
- "templates:sync": "tsx src/scripts/sync-templates.ts",
30
- "registry:build": "tsx src/index.ts build --root ../.. --uniapp-source packages/uniapp-project/src/components",
31
- "prepack": "npm run templates:sync && npm run build && npm run registry:build",
32
- "prepublishOnly": "npm run templates:sync && npm run build && npm run registry:build"
33
- },
34
- "dependencies": {
35
- "chalk": "^5.6.2",
36
- "cli-progress": "^3.12.0",
37
- "commander": "^14.0.0",
38
- "execa": "^9.6.0",
39
- "figlet": "^1.9.4",
40
- "ora": "^9.0.0",
41
- "prompts": "^2.4.2"
42
- },
43
- "devDependencies": {
44
- "@types/cli-progress": "^3.11.6",
45
- "@types/figlet": "^1.7.0",
46
- "@types/node": "^22.10.7",
47
- "@types/prompts": "^2.4.9",
48
- "rimraf": "^6.0.1",
49
- "tsup": "^8.5.0",
50
- "tsx": "^4.20.0",
51
- "typescript": "^5.8.3"
52
- }
53
- }
1
+ {
2
+ "name": "reborn-ui",
3
+ "version": "0.1.78",
4
+ "description": "A CLI for Reborn UI",
5
+ "author": "1997liuyh-boop",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/1997liuyh-boop/Reborn-UI.git"
10
+ },
11
+ "type": "module",
12
+ "bin": {
13
+ "reborn-ui": "dist/index.js"
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "registry",
18
+ "README.md"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "cli": "tsx src/index.ts",
25
+ "build": "tsup",
26
+ "dev": "tsx src/index.ts",
27
+ "clean": "rimraf dist",
28
+ "prepare": "tsup",
29
+ "templates:sync": "tsx src/scripts/sync-templates.ts",
30
+ "registry:build": "tsx src/index.ts build --root ../.. --uniapp-source packages/uniapp-project/src/components",
31
+ "prepack": "npm run templates:sync && npm run build && npm run registry:build",
32
+ "prepublishOnly": "npm run templates:sync && npm run build && npm run registry:build"
33
+ },
34
+ "dependencies": {
35
+ "chalk": "^5.6.2",
36
+ "cli-progress": "^3.12.0",
37
+ "commander": "^14.0.0",
38
+ "execa": "^9.6.0",
39
+ "figlet": "^1.9.4",
40
+ "ora": "^9.0.0",
41
+ "prompts": "^2.4.2"
42
+ },
43
+ "devDependencies": {
44
+ "@types/cli-progress": "^3.11.6",
45
+ "@types/figlet": "^1.7.0",
46
+ "@types/node": "^22.10.7",
47
+ "@types/prompts": "^2.4.9",
48
+ "rimraf": "^6.0.1",
49
+ "tsup": "^8.5.0",
50
+ "tsx": "^4.20.0",
51
+ "typescript": "^5.8.3"
52
+ }
53
+ }
@@ -14,12 +14,17 @@
14
14
  "content": "<template>\r\n <div class=\"fixed touch-none z-[9999]\" :style=\"viewStyle\" @pointerdown=\"onPointerDown\"\r\n @pointermove.stop.prevent=\"onPointerMove\" @pointerup=\"onPointerUp\" @pointercancel=\"onPointerUp\">\r\n <slot></slot>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, nextTick, reactive, type CSSProperties, onMounted } from \"vue\";\r\nimport { useWindowSize } from '@vueuse/core'\r\n\r\ndefineOptions({\r\n name: \"RebornAffix\"\r\n});\r\n\r\nexport interface FloatViewProps {\r\n zIndex?: number;\r\n size?: number;\r\n left?: number;\r\n right?: number;\r\n top?: number;\r\n bottom?: number;\r\n gap?: number;\r\n disabled?: boolean;\r\n noSnapping?: boolean;\r\n // Web 端通常不需要 manifest 的 safeArea,但保留 API 兼容\r\n safeArea?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<FloatViewProps>(), {\r\n zIndex: 500,\r\n size: 40,\r\n left: 10,\r\n bottom: 10,\r\n gap: 10,\r\n disabled: false,\r\n noSnapping: false,\r\n safeArea: true\r\n});\r\n\r\n// 使用 VueUse 获取响应式窗口大小\r\nconst { width: screenWidth, height: screenHeight } = useWindowSize()\r\n\r\n// Web 端安全区域通常为 0,除非是 PWA standalone 模式\r\n// 这里简化处理,Web 端一般默认为 0\r\nconst safeAreaBottom = 0;\r\nconst safeAreaTop = 0;\r\n\r\nconst position = reactive({\r\n x: props.right !== undefined ? (screenWidth.value - props.size - props.right) : props.left,\r\n y: props.top !== undefined\r\n ? (screenHeight.value - props.size - props.top - safeAreaTop)\r\n : (props.bottom + safeAreaBottom),\r\n isDragging: false\r\n});\r\n\r\n// 监听窗口大小变化修正位置 (防止 resize 后按钮消失)\r\nwatch([screenWidth, screenHeight], () => {\r\n performEdgeSnapping()\r\n})\r\n\r\nonMounted(() => {\r\n // 修正初始位置:如果是 right 定位,确保根据当前屏幕宽度计算\r\n // 避免 SSR/初始 width 为 0 导致被 snap 到左边\r\n if (props.right !== undefined) {\r\n position.x = screenWidth.value - props.size - props.right;\r\n }\r\n nextTick(() => {\r\n performEdgeSnapping();\r\n })\r\n})\r\n\r\nconst dragState = reactive({\r\n startX: 0,\r\n startY: 0\r\n});\r\n\r\n// 动态样式计算\r\nconst viewStyle = computed<CSSProperties>(() => {\r\n const style: CSSProperties = {\r\n left: `${position.x}px`,\r\n bottom: `${position.y}px`,\r\n zIndex: props.zIndex,\r\n width: `${props.size}px`,\r\n height: `${props.size}px`,\r\n position: \"fixed\",\r\n touchAction: \"none\", // 关键:禁用浏览器默认手势\r\n userSelect: \"none\"\r\n };\r\n\r\n if (position.isDragging) {\r\n style.transition = \"none\";\r\n } else {\r\n style.transition = \"left 300ms, bottom 300ms\";\r\n }\r\n\r\n return style;\r\n});\r\n\r\nfunction onPointerDown(e: PointerEvent) {\r\n if (props.disabled) return;\r\n if (e.isPrimary === false) return;\r\n\r\n // 捕获指针\r\n (e.target as Element).setPointerCapture(e.pointerId);\r\n\r\n dragState.startX = e.clientX;\r\n dragState.startY = e.clientY;\r\n position.isDragging = true;\r\n}\r\n\r\nfunction onPointerMove(e: PointerEvent) {\r\n if (props.disabled || !position.isDragging) return;\r\n\r\n const deltaX = e.clientX - dragState.startX;\r\n // Y轴逻辑:Web 坐标系 Y 轴向下,clientX/Y 也是左上角为原点\r\n // 但是我们的 CSS bottom 是相对于底部的。\r\n // 当鼠标 Y 变大 (向下移),e.clientY 变大,diff > 0\r\n // 此时距离底部应该变小 (position.y 变小)\r\n // 所以 deltaY = startY - clientY 没问题\r\n const deltaY = dragState.startY - e.clientY;\r\n\r\n let newX = position.x + deltaX;\r\n let newY = position.y + deltaY;\r\n\r\n // --- 水平边界限制 ---\r\n newX = Math.max(0, Math.min(screenWidth.value - props.size, newX));\r\n\r\n // --- 垂直边界限制 ---\r\n const minY = safeAreaBottom;\r\n const maxY = screenHeight.value - props.size - safeAreaTop;\r\n\r\n newY = Math.max(minY, Math.min(maxY, newY));\r\n\r\n position.x = newX;\r\n position.y = newY;\r\n\r\n dragState.startX = e.clientX;\r\n dragState.startY = e.clientY;\r\n}\r\n\r\nfunction onPointerUp(e: PointerEvent) {\r\n if (props.disabled || !position.isDragging) return;\r\n\r\n (e.target as Element).releasePointerCapture(e.pointerId);\r\n\r\n nextTick(() => {\r\n position.isDragging = false;\r\n if (!props.noSnapping) {\r\n performEdgeSnapping();\r\n }\r\n });\r\n}\r\n\r\nfunction performEdgeSnapping() {\r\n const { size, gap } = props;\r\n const edgeThreshold = 60;\r\n const centerX = screenWidth.value / 2;\r\n\r\n // 水平吸附\r\n if (position.x < edgeThreshold) {\r\n position.x = gap;\r\n } else if (position.x > screenWidth.value - size - edgeThreshold) {\r\n position.x = screenWidth.value - size - gap;\r\n } else {\r\n position.x = position.x < centerX ? gap : screenWidth.value - size - gap;\r\n }\r\n\r\n // 垂直吸附修正\r\n const maxY = screenHeight.value - size - safeAreaTop;\r\n const minSafeY = gap + safeAreaBottom;\r\n\r\n if (position.y > maxY - gap) position.y = maxY - gap;\r\n if (position.y < minSafeY) position.y = minSafeY;\r\n}\r\n</script>\r\n",
15
15
  "target": "web"
16
16
  },
17
+ {
18
+ "path": "index.ts",
19
+ "content": "export { default as RebornAffix } from './RebornAffix.vue'\r\n",
20
+ "target": "uniapp"
21
+ },
17
22
  {
18
23
  "path": "RebornAffix.vue",
19
- "content": "<template>\r\n <view class=\"fixed touch-none\" :style=\"viewStyle\" @touchstart=\"onTouchStart\" @touchmove.stop.prevent=\"onTouchMove\"\r\n @touchend=\"onTouchEnd\" @touchcancel=\"onTouchEnd\">\r\n <slot></slot>\r\n </view>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, nextTick, reactive, type CSSProperties } from \"vue\";\r\n\r\ndefineOptions({\r\n name: \"reborn-affix\"\r\n});\r\n\r\nexport interface FloatViewProps {\r\n zIndex?: number;\r\n size?: number;\r\n left?: number;\r\n right?: number;\r\n top?: number;\r\n bottom?: number;\r\n gap?: number;\r\n disabled?: boolean;\r\n noSnapping?: boolean;\r\n // 新增:是否考虑安全区域(默认为 true)\r\n safeArea?: boolean;\r\n}\r\n\r\nconst props = withDefaults(defineProps<FloatViewProps>(), {\r\n zIndex: 500,\r\n size: 40,\r\n left: 10,\r\n bottom: 10,\r\n gap: 10,\r\n disabled: false,\r\n noSnapping: false,\r\n safeArea: true\r\n});\r\n\r\n// 获取屏幕信息和安全区域\r\n// 获取屏幕信息和安全区域\r\nconst windowInfo = uni.getWindowInfo() || {};\r\nconst screenWidth = windowInfo.screenWidth || 0;\r\nconst screenHeight = windowInfo.screenHeight || 0;\r\n\r\n// 获取底部安全区域高度 (iPhone X+ 的底部黑条)\r\nconst safeAreaBottom = props.safeArea ? (windowInfo.safeAreaInsets?.bottom || 0) : 0;\r\n// 获取顶部安全区域高度 (状态栏/刘海屏)\r\nconst safeAreaTop = props.safeArea ? (windowInfo.safeAreaInsets?.top || 0) : 0;\r\n\r\nconst position = reactive({\r\n x: props.right !== undefined ? (screenWidth - props.size - props.right) : props.left,\r\n // 初始位置:\r\n // 如果指定了 top,则 y = 屏幕高度 - size - top - 顶部安全区域\r\n // 否则使用 bottom + 底部安全区域\r\n y: props.top !== undefined\r\n ? (screenHeight - props.size - props.top - safeAreaTop)\r\n : (props.bottom + safeAreaBottom),\r\n isDragging: false\r\n});\r\n\r\nconst dragState = reactive({\r\n startX: 0,\r\n startY: 0\r\n});\r\n\r\n// 动态样式计算\r\nconst viewStyle = computed<CSSProperties>(() => {\r\n const style: CSSProperties = {\r\n left: `${position.x}px`,\r\n bottom: `${position.y}px`, // 直接使用 position.y,逻辑在内部处理\r\n zIndex: props.zIndex,\r\n width: `${props.size}px`,\r\n height: `${props.size}px`,\r\n position: \"fixed\"\r\n };\r\n\r\n if (position.isDragging) {\r\n style.transitionProperty = \"none\";\r\n } else {\r\n style.transitionProperty = \"left, bottom\";\r\n style.transitionDuration = \"300ms\";\r\n }\r\n\r\n return style;\r\n});\r\n\r\nfunction onTouchStart(e: TouchEvent) {\r\n if (props.disabled) return;\r\n if (e.touches.length > 0) {\r\n const touch = e.touches[0];\r\n dragState.startX = touch.clientX;\r\n dragState.startY = touch.clientY;\r\n position.isDragging = true;\r\n }\r\n}\r\n\r\nfunction onTouchMove(e: TouchEvent) {\r\n if (props.disabled || !position.isDragging || e.touches.length === 0) return;\r\n e.preventDefault();\r\n\r\n const touch = e.touches[0];\r\n const deltaX = touch.clientX - dragState.startX;\r\n // Y轴逻辑:手指往上滑(clientY变小),bottom值应该变大\r\n const deltaY = dragState.startY - touch.clientY;\r\n\r\n let newX = position.x + deltaX;\r\n let newY = position.y + deltaY;\r\n\r\n // --- 水平边界限制 ---\r\n newX = Math.max(0, Math.min(screenWidth - props.size, newX));\r\n\r\n // --- 垂直边界限制 ---\r\n // 最小值:如果有安全区域,则不能拖到安全区域以下\r\n let minY = safeAreaBottom;\r\n // 最大值:屏幕高度减去自身高度 - 顶部安全区域\r\n const maxY = screenHeight - props.size - safeAreaTop;\r\n\r\n newY = Math.max(minY, Math.min(maxY, newY));\r\n\r\n position.x = newX;\r\n position.y = newY;\r\n dragState.startX = touch.clientX;\r\n dragState.startY = touch.clientY;\r\n}\r\n\r\nfunction performEdgeSnapping() {\r\n const { size, gap } = props;\r\n const edgeThreshold = 60;\r\n const centerX = screenWidth / 2;\r\n\r\n // 水平吸附\r\n if (position.x < edgeThreshold) {\r\n position.x = gap;\r\n } else if (position.x > screenWidth - size - edgeThreshold) {\r\n position.x = screenWidth - size - gap;\r\n } else {\r\n position.x = position.x < centerX ? gap : screenWidth - size - gap;\r\n }\r\n\r\n // 垂直吸附修正\r\n const maxY = screenHeight - size - safeAreaTop;\r\n // 底部最小值:Gap + 安全区域高度\r\n const minSafeY = gap + safeAreaBottom;\r\n\r\n if (position.y > maxY - gap) position.y = maxY - gap;\r\n if (position.y < minSafeY) position.y = minSafeY;\r\n}\r\n\r\nfunction onTouchEnd() {\r\n if (props.disabled || !position.isDragging) return;\r\n nextTick(() => {\r\n position.isDragging = false;\r\n if (!props.noSnapping) {\r\n performEdgeSnapping();\r\n }\r\n });\r\n}\r\n</script>\r\n<style></style>",
24
+ "content": "<script setup lang=\"ts\">\r\nimport type { CSSProperties } from 'vue'\r\nimport { computed, nextTick, reactive } from 'vue'\r\n\r\ndefineOptions({\r\n name: 'RebornAffix',\r\n})\r\n\r\nconst props = withDefaults(defineProps<FloatViewProps>(), {\r\n zIndex: 500,\r\n size: 40,\r\n left: 10,\r\n bottom: 10,\r\n gap: 10,\r\n disabled: false,\r\n noSnapping: false,\r\n safeArea: true,\r\n})\r\n\r\nexport interface FloatViewProps {\r\n zIndex?: number\r\n size?: number\r\n left?: number\r\n right?: number\r\n top?: number\r\n bottom?: number\r\n gap?: number\r\n disabled?: boolean\r\n noSnapping?: boolean\r\n // 新增:是否考虑安全区域(默认为 true)\r\n safeArea?: boolean\r\n}\r\n\r\n// 获取屏幕信息和安全区域\r\n// 获取屏幕信息和安全区域\r\nconst windowInfo = uni.getWindowInfo() || {}\r\nconst screenWidth = windowInfo.screenWidth || 0\r\nconst screenHeight = windowInfo.screenHeight || 0\r\n\r\n// 获取底部安全区域高度 (iPhone X+ 的底部黑条)\r\nconst safeAreaBottom = props.safeArea ? (windowInfo.safeAreaInsets?.bottom || 0) : 0\r\n// 获取顶部安全区域高度 (状态栏/刘海屏)\r\nconst safeAreaTop = props.safeArea ? (windowInfo.safeAreaInsets?.top || 0) : 0\r\n\r\nconst position = reactive({\r\n x: props.right !== undefined ? (screenWidth - props.size - props.right) : props.left,\r\n // 初始位置:\r\n // 如果指定了 top,则 y = 屏幕高度 - size - top - 顶部安全区域\r\n // 否则使用 bottom + 底部安全区域\r\n y: props.top !== undefined\r\n ? (screenHeight - props.size - props.top - safeAreaTop)\r\n : (props.bottom + safeAreaBottom),\r\n isDragging: false,\r\n})\r\n\r\nconst dragState = reactive({\r\n startX: 0,\r\n startY: 0,\r\n})\r\n\r\n// 动态样式计算\r\nconst viewStyle = computed<CSSProperties>(() => {\r\n const style: CSSProperties = {\r\n left: `${position.x}px`,\r\n bottom: `${position.y}px`, // 直接使用 position.y,逻辑在内部处理\r\n zIndex: props.zIndex,\r\n width: `${props.size}px`,\r\n height: `${props.size}px`,\r\n position: 'fixed',\r\n }\r\n\r\n if (position.isDragging) {\r\n style.transitionProperty = 'none'\r\n }\r\n else {\r\n style.transitionProperty = 'left, bottom'\r\n style.transitionDuration = '300ms'\r\n }\r\n\r\n return style\r\n})\r\n\r\nfunction onTouchStart(e: TouchEvent) {\r\n if (props.disabled) { return }\r\n if (e.touches.length > 0) {\r\n const touch = e.touches[0]\r\n dragState.startX = touch.clientX\r\n dragState.startY = touch.clientY\r\n position.isDragging = true\r\n }\r\n}\r\n\r\nfunction onTouchMove(e: TouchEvent) {\r\n if (props.disabled || !position.isDragging || e.touches.length === 0) { return }\r\n\r\n const touch = e.touches[0]\r\n const deltaX = touch.clientX - dragState.startX\r\n // Y轴逻辑:手指往上滑(clientY变小),bottom值应该变大\r\n const deltaY = dragState.startY - touch.clientY\r\n\r\n // 增加拖拽阈值判断,避免误触点击事件\r\n if (Math.abs(deltaX) < 5 && Math.abs(deltaY) < 5) { return }\r\n\r\n // 确认为拖拽行为,阻止默认事件\r\n if (e.cancelable) {\r\n e.preventDefault()\r\n }\r\n\r\n let newX = position.x + deltaX\r\n let newY = position.y + deltaY\r\n\r\n // --- 水平边界限制 ---\r\n newX = Math.max(0, Math.min(screenWidth - props.size, newX))\r\n\r\n // --- 垂直边界限制 ---\r\n // 最小值:如果有安全区域,则不能拖到安全区域以下\r\n const minY = safeAreaBottom\r\n // 最大值:屏幕高度减去自身高度 - 顶部安全区域\r\n const maxY = screenHeight - props.size - safeAreaTop\r\n\r\n newY = Math.max(minY, Math.min(maxY, newY))\r\n\r\n position.x = newX\r\n position.y = newY\r\n dragState.startX = touch.clientX\r\n dragState.startY = touch.clientY\r\n}\r\n\r\nfunction performEdgeSnapping() {\r\n const { size, gap } = props\r\n const edgeThreshold = 60\r\n const centerX = screenWidth / 2\r\n\r\n // 水平吸附\r\n if (position.x < edgeThreshold) {\r\n position.x = gap\r\n }\r\n else if (position.x > screenWidth - size - edgeThreshold) {\r\n position.x = screenWidth - size - gap\r\n }\r\n else {\r\n position.x = position.x < centerX ? gap : screenWidth - size - gap\r\n }\r\n\r\n // 垂直吸附修正\r\n const maxY = screenHeight - size - safeAreaTop\r\n // 底部最小值:Gap + 安全区域高度\r\n const minSafeY = gap + safeAreaBottom\r\n\r\n if (position.y > maxY - gap) { position.y = maxY - gap }\r\n if (position.y < minSafeY) { position.y = minSafeY }\r\n}\r\n\r\nfunction onTouchEnd() {\r\n if (props.disabled || !position.isDragging) { return }\r\n nextTick(() => {\r\n position.isDragging = false\r\n if (!props.noSnapping) {\r\n performEdgeSnapping()\r\n }\r\n })\r\n}\r\n</script>\r\n\r\n<template>\r\n <view\r\n class=\"fixed touch-none\" :style=\"viewStyle\" @touchstart=\"onTouchStart\" @touchmove=\"onTouchMove\"\r\n @touchend=\"onTouchEnd\" @touchcancel=\"onTouchEnd\"\r\n >\r\n <slot />\r\n </view>\r\n</template>\r\n\r\n<style></style>\r\n",
20
25
  "target": "uniapp"
21
26
  }
22
27
  ],
23
- "fileCount": 3,
24
- "contentHash": "eb9f1ac7f8cefec0973cc03e77ac8d64396f0f86"
28
+ "fileCount": 4,
29
+ "contentHash": "fc6fdfbe39bcce7f9fc542241aca54391c0e3a5b"
25
30
  }
@@ -15,17 +15,22 @@
15
15
  "content": "<template>\r\n <div :class=\"ui.wrapper()\"\r\n :style=\"{ bottom: viewBottom, opacity: visible ? 1 : 0, pointerEvents: visible ? 'auto' : 'none' }\"\r\n @click.stop=\"toTop\">\r\n <slot>\r\n <div :class=\"[\r\n ui.base(),\r\n visible ? '-translate-x-3' : 'translate-x-20'\r\n ]\">\r\n <span :class=\"ui.icon()\">↑</span>\r\n </div>\r\n </slot>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport type { ClassValue } from \"clsx\"\r\nimport { tv } from '@/lib/tv'\r\nimport { cn } from '@/lib/utils'\r\nimport { useWindowScroll } from '@vueuse/core'\r\nimport theme, { backTopColors, backTopSizes } from \"./reborn-back-top.config\";\r\n\r\ndefineOptions({\r\n name: \"RebornBackTop\"\r\n});\r\n\r\nexport interface BackTopProps {\r\n // Web: 也可以传入自定义的 scrollTop,如果不传则自动监听 window\r\n scrollTop?: number;\r\n // 滚动多少距离后显示\r\n threshold?: number;\r\n // 底部距离 (px)\r\n bottom?: number;\r\n // 滚动动画时长 (ms) - Web 使用 CSS scroll-behavior: smooth,此参数作为兼容保留\r\n duration?: number;\r\n // 是否是 TabBar 页面 (Web 通常不需要)\r\n isTab?: boolean;\r\n // 是否适配安全区域\r\n safeArea?: boolean;\r\n color?: typeof backTopColors[number]\r\n size?: typeof backTopSizes[number]\r\n ui?: {\r\n wrapper?: ClassValue,\r\n base?: ClassValue,\r\n icon?: ClassValue\r\n }\r\n}\r\n\r\nconst props = withDefaults(defineProps<BackTopProps>(), {\r\n threshold: 300,\r\n bottom: 20,\r\n duration: 300,\r\n isTab: false,\r\n safeArea: true,\r\n color: 'primary',\r\n size: 'md'\r\n});\r\n\r\nconst b = tv(theme)\r\n\r\nconst emit = defineEmits([\"click\"]);\r\n\r\n// 自动获取 window 滚动\r\nconst { y: windowY } = useWindowScroll()\r\n\r\n// 优先使用 props.scrollTop (如果外部手动控制),否则使用 windowY\r\nconst currentScrollTop = computed(() => {\r\n return props.scrollTop !== undefined ? props.scrollTop : windowY.value\r\n})\r\n\r\n// Web 端安全区域通常为 0\r\nconst getSafeAreaBottom = () => 0\r\n\r\n// 计算最终底部距离\r\nconst viewBottom = computed(() => {\r\n let h = props.bottom;\r\n\r\n if (props.safeArea) {\r\n h += getSafeAreaBottom();\r\n }\r\n\r\n if (props.isTab) {\r\n h += 50;\r\n }\r\n\r\n return `${h}px`;\r\n});\r\n\r\n// 是否显示\r\nconst visible = computed(() => currentScrollTop.value > props.threshold);\r\n\r\nconst uiOverrides = computed(() => props.ui || {});\r\n\r\nconst ui = computed(() => {\r\n const styles = b({\r\n color: props.color,\r\n size: props.size,\r\n })\r\n\r\n return {\r\n wrapper: (opts?: { class?: any }) => styles.wrapper({ class: cn(opts?.class, uiOverrides.value.wrapper) }),\r\n base: (opts?: { class?: any }) => styles.base({ class: cn(opts?.class, uiOverrides.value.base) }),\r\n icon: (opts?: { class?: any }) => styles.icon({ class: cn(opts?.class, uiOverrides.value.icon) }),\r\n }\r\n})\r\n\r\n// 回到顶部\r\nfunction toTop() {\r\n window.scrollTo({\r\n top: 0,\r\n behavior: 'smooth'\r\n });\r\n emit(\"click\");\r\n}\r\n</script>\r\n",
16
16
  "target": "web"
17
17
  },
18
+ {
19
+ "path": "index.ts",
20
+ "content": "export { default as RebornBackTop } from './RebornBackTop.vue'\r\n",
21
+ "target": "uniapp"
22
+ },
18
23
  {
19
24
  "path": "reborn-back-top.config.ts",
20
- "content": "const color = ['primary', 'secondary', 'success', 'info', 'warning', 'error', 'neutral'] as const\r\nconst sizes = [\"sm\", \"md\", \"lg\"] as const;\r\nexport { color as backTopColors, sizes as backTopSizes };\r\nexport default {\r\n slots: {\r\n wrapper: \"fixed right-0 z-50 overflow-visible pointer-none transition-all duration-300 active:scale-95\",\r\n base: \"flex flex-row items-center justify-center text-white shadow-lg rounded-full pointer-events-auto cursor-pointer transition-transform duration-300\",\r\n icon: \"text-white\"\r\n },\r\n variants: {\r\n color: {\r\n primary: { base: 'bg-primary' },\r\n secondary: { base: 'bg-secondary' },\r\n success: { base: 'bg-success' },\r\n info: { base: 'bg-info' },\r\n warning: { base: 'bg-warning' },\r\n error: { base: 'bg-error' },\r\n neutral: { base: 'bg-neutral' }\r\n },\r\n size: {\r\n sm: { base: 'size-8', icon: 'text-26' },\r\n md: { base: 'size-10', icon: 'text-28' },\r\n lg: { base: 'size-12', icon: 'text-30' }\r\n },\r\n },\r\n defaultVariants: {\r\n color: 'primary' as const,\r\n size: 'md' as const\r\n }\r\n}",
25
+ "content": "const color = ['primary', 'secondary', 'success', 'info', 'warning', 'error', 'neutral'] as const\r\nconst sizes = ['sm', 'md', 'lg'] as const\r\nexport { color as backTopColors, sizes as backTopSizes }\r\nexport default {\r\n slots: {\r\n wrapper: 'fixed right-0 z-50 overflow-visible pointer-none transition-all duration-300 active:scale-95',\r\n base: 'flex flex-row items-center justify-center text-white shadow-lg rounded-full pointer-events-auto cursor-pointer transition-transform duration-300',\r\n icon: 'text-white',\r\n },\r\n variants: {\r\n color: {\r\n primary: { base: 'bg-primary' },\r\n secondary: { base: 'bg-secondary' },\r\n success: { base: 'bg-success' },\r\n info: { base: 'bg-info' },\r\n warning: { base: 'bg-warning' },\r\n error: { base: 'bg-error' },\r\n neutral: { base: 'bg-neutral' },\r\n },\r\n size: {\r\n sm: { base: 'size-8', icon: 'text-26' },\r\n md: { base: 'size-10', icon: 'text-28' },\r\n lg: { base: 'size-12', icon: 'text-30' },\r\n },\r\n },\r\n defaultVariants: {\r\n color: 'primary' as const,\r\n size: 'md' as const,\r\n },\r\n}\r\n",
21
26
  "target": "uniapp"
22
27
  },
23
28
  {
24
29
  "path": "RebornBackTop.vue",
25
- "content": "<template>\r\n <view :class=\"ui.wrapper()\" :style=\"{ bottom: viewBottom, opacity: visible ? 1 : 0 }\" @tap.stop=\"toTop\">\r\n <slot>\r\n <view :class=\"[\r\n ui.base(),\r\n visible ? '-translate-x-3' : 'translate-x-20'\r\n ]\">\r\n <text :class=\"ui.icon()\">↑</text>\r\n </view>\r\n </slot>\r\n </view>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed } from \"vue\";\r\nimport type { ClassValue } from \"clsx\"\r\nimport { tv } from '@/lib/tv'\r\nimport { cn } from '@/lib/utils'\r\nimport theme, { backTopColors, backTopSizes } from \"./reborn-back-top.config\";\r\n\r\ndefineOptions({\r\n name: \"reborn-back-top\"\r\n});\r\n\r\nexport interface BackTopProps {\r\n // 当前页面的滚动距离\r\n scrollTop?: number;\r\n // 滚动多少距离后显示\r\n threshold?: number;\r\n // 底部距离 (px)\r\n bottom?: number;\r\n // 滚动动画时长 (ms)\r\n duration?: number;\r\n // 是否是 TabBar 页面 (如果是,会自动抬高 50px)\r\n isTab?: boolean;\r\n // 是否适配安全区域\r\n safeArea?: boolean;\r\n color?: typeof backTopColors[number]\r\n size?: typeof backTopSizes[number]\r\n ui?: {\r\n wrapper?: ClassValue,\r\n base?: ClassValue,\r\n icon?: ClassValue\r\n }\r\n}\r\n\r\nconst props = withDefaults(defineProps<BackTopProps>(), {\r\n scrollTop: 0,\r\n threshold: 300,\r\n bottom: 20,\r\n duration: 300,\r\n isTab: false,\r\n safeArea: true,\r\n color: 'primary',\r\n size: 'md'\r\n});\r\n\r\nconst b = tv(theme)\r\n\r\nconst emit = defineEmits([\"click\"]);\r\n\r\n// 获取安全区域高度\r\nfunction getSafeAreaBottom(): number {\r\n const windowInfo = uni.getWindowInfo();\r\n return windowInfo?.safeAreaInsets?.bottom || 0;\r\n}\r\n\r\n// 计算最终底部距离\r\nconst viewBottom = computed(() => {\r\n let h = props.bottom;\r\n\r\n // 1. 如果开启了安全区域适配 (通常非 Tab 页需要避开底部黑条)\r\n if (props.safeArea) {\r\n h += getSafeAreaBottom();\r\n }\r\n\r\n // 2. 如果是 Tab 页,额外抬高 50px (标准 TabBar 高度)\r\n // 这样你就不用手动写 bottom=\"70\" 了\r\n if (props.isTab) {\r\n h += 50;\r\n }\r\n\r\n return `${h}px`;\r\n});\r\n\r\n// 是否显示\r\nconst visible = computed(() => props.scrollTop > props.threshold);\r\n\r\nconst uiOverrides = computed(() => props.ui || {});\r\n\r\nconst ui = computed(() => {\r\n const styles = b({\r\n color: props.color,\r\n size: props.size,\r\n })\r\n\r\n return {\r\n wrapper: (opts?: { class?: any }) => styles.wrapper({ class: cn(opts?.class, uiOverrides.value.wrapper) }),\r\n base: (opts?: { class?: any }) => styles.base({ class: cn(opts?.class, uiOverrides.value.base) }),\r\n icon: (opts?: { class?: any }) => styles.icon({ class: cn(opts?.class, uiOverrides.value.icon) }),\r\n }\r\n})\r\n\r\n// 回到顶部\r\nfunction toTop() {\r\n uni.pageScrollTo({\r\n scrollTop: 0,\r\n duration: props.duration\r\n });\r\n emit(\"click\");\r\n}\r\n</script>\r\n",
30
+ "content": "<script setup lang=\"ts\">\r\nimport type { ClassValue } from 'clsx'\r\nimport type { backTopColors, backTopSizes } from './reborn-back-top.config'\r\nimport { computed } from 'vue'\r\nimport { tv } from '@/lib/tv'\r\nimport { cn } from '@/lib/utils'\r\nimport theme from './reborn-back-top.config'\r\n\r\ndefineOptions({\r\n name: 'RebornBackTop',\r\n})\r\n\r\nconst props = withDefaults(defineProps<BackTopProps>(), {\r\n scrollTop: 0,\r\n threshold: 300,\r\n bottom: 20,\r\n duration: 300,\r\n isTab: false,\r\n safeArea: true,\r\n color: 'primary',\r\n size: 'md',\r\n})\r\n\r\nconst emit = defineEmits(['click'])\r\n\r\nexport interface BackTopProps {\r\n // 当前页面的滚动距离\r\n scrollTop?: number\r\n // 滚动多少距离后显示\r\n threshold?: number\r\n // 底部距离 (px)\r\n bottom?: number\r\n // 滚动动画时长 (ms)\r\n duration?: number\r\n // 是否是 TabBar 页面 (如果是,会自动抬高 50px)\r\n isTab?: boolean\r\n // 是否适配安全区域\r\n safeArea?: boolean\r\n color?: typeof backTopColors[number]\r\n size?: typeof backTopSizes[number]\r\n ui?: {\r\n wrapper?: ClassValue\r\n base?: ClassValue\r\n icon?: ClassValue\r\n }\r\n}\r\n\r\nconst b = tv(theme)\r\n\r\n// 获取安全区域高度\r\nfunction getSafeAreaBottom(): number {\r\n const windowInfo = uni.getWindowInfo()\r\n return windowInfo?.safeAreaInsets?.bottom || 0\r\n}\r\n\r\n// 计算最终底部距离\r\nconst viewBottom = computed(() => {\r\n let h = props.bottom\r\n\r\n // 1. 如果开启了安全区域适配 (通常非 Tab 页需要避开底部黑条)\r\n if (props.safeArea) {\r\n h += getSafeAreaBottom()\r\n }\r\n\r\n // 2. 如果是 Tab 页,额外抬高 50px (标准 TabBar 高度)\r\n // 这样你就不用手动写 bottom=\"70\" 了\r\n if (props.isTab) {\r\n h += 50\r\n }\r\n\r\n return `${h}px`\r\n})\r\n\r\n// 是否显示\r\nconst visible = computed(() => props.scrollTop > props.threshold)\r\n\r\nconst uiOverrides = computed(() => props.ui || {})\r\n\r\nconst ui = computed(() => {\r\n const styles = b({\r\n color: props.color,\r\n size: props.size,\r\n })\r\n\r\n return {\r\n wrapper: (opts?: { class?: any }) => styles.wrapper({ class: cn(opts?.class, uiOverrides.value.wrapper) }),\r\n base: (opts?: { class?: any }) => styles.base({ class: cn(opts?.class, uiOverrides.value.base) }),\r\n icon: (opts?: { class?: any }) => styles.icon({ class: cn(opts?.class, uiOverrides.value.icon) }),\r\n }\r\n})\r\n\r\n// 回到顶部\r\nfunction toTop() {\r\n uni.pageScrollTo({\r\n scrollTop: 0,\r\n duration: props.duration,\r\n })\r\n emit('click')\r\n}\r\n</script>\r\n\r\n<template>\r\n <view :class=\"ui.wrapper()\" :style=\"{ bottom: viewBottom, opacity: visible ? 1 : 0 }\" @tap.stop=\"toTop\">\r\n <slot>\r\n <view :class=\"[\r\n ui.base(),\r\n visible ? '-translate-x-3' : 'translate-x-20',\r\n ]\">\r\n <text :class=\"ui.icon()\">↑</text>\r\n </view>\r\n </slot>\r\n </view>\r\n</template>\r\n",
26
31
  "target": "uniapp"
27
32
  }
28
33
  ],
29
- "fileCount": 4,
30
- "contentHash": "085dd87abba4fcd861e36374a9011d8644997339"
34
+ "fileCount": 5,
35
+ "contentHash": "dd969cbe3dfbd4f4e09202580deb85c9c84fe3a4"
31
36
  }
@@ -10,7 +10,8 @@
10
10
  },
11
11
  {
12
12
  "path": "index.ts",
13
- "content": "export { default as Badge } from \"./RebornBadge.vue\";\r\n"
13
+ "content": "export { default as Badge } from \"./RebornBadge.vue\";\r\n",
14
+ "target": "web"
14
15
  },
15
16
  {
16
17
  "path": "reborn-badge.config.ts",
@@ -22,17 +23,22 @@
22
23
  "content": "<script setup lang=\"ts\">\r\nimport { computed } from 'vue'\r\nimport theme from './badge'\r\nimport { useFieldGroup } from '~/composables/useFieldGroup'\r\nimport { tv } from '~/lib/tv'\r\n\r\n// Define the variant builder\r\nconst b = tv({ extend: tv(theme) })\r\n\r\n// Derive types directly from the theme object to ensure static analysis works\r\ntype Theme = typeof theme\r\ntype BadgeColor = keyof Theme['variants']['color']\r\ntype BadgeVariant = keyof Theme['variants']['variant']\r\ntype BadgeSize = keyof Theme['variants']['size']\r\n\r\nexport interface BadgeProps {\r\n /**\r\n * The element or component this component should render as.\r\n * @defaultValue 'span'\r\n */\r\n as?: any\r\n label?: string | number\r\n /**\r\n * @defaultValue 'primary'\r\n */\r\n color?: BadgeColor | (string & {})\r\n /**\r\n * @defaultValue 'solid'\r\n */\r\n variant?: BadgeVariant | (string & {})\r\n /**\r\n * @defaultValue 'md'\r\n */\r\n size?: BadgeSize | (string & {})\r\n /** Render the badge with equal padding on all sides. */\r\n square?: boolean\r\n /** Whether the badge is closable. */\r\n closable?: boolean\r\n /** The icon for the close button. */\r\n closeIcon?: string\r\n class?: any\r\n ui?: any\r\n}\r\n\r\nexport interface BadgeSlots {\r\n leading(props: { ui: any }): any\r\n default(props: { ui: any }): any\r\n trailing(props: { ui: any }): any\r\n close(props: { ui: any; close: (e: MouseEvent) => void }): any\r\n}\r\n\r\nconst props = withDefaults(defineProps<BadgeProps>(), {\r\n as: 'span',\r\n color: 'primary',\r\n variant: 'solid',\r\n size: 'md',\r\n closeIcon: 'i-lucide-x'\r\n})\r\n\r\nconst slots = defineSlots<BadgeSlots>()\r\n\r\nconst emit = defineEmits<{\r\n close: [payload: MouseEvent]\r\n}>()\r\n\r\nconst show = defineModel<boolean>('show', { default: true })\r\n\r\nconst { orientation, size: fieldGroupSize } = useFieldGroup(props)\r\n\r\nconst ui = computed(() => b({\r\n color: props.color as BadgeColor,\r\n variant: props.variant as BadgeVariant,\r\n size: (fieldGroupSize.value || props.size) as BadgeSize,\r\n square: props.square || (!slots.default && !props.label),\r\n fieldGroup: orientation.value\r\n}))\r\n\r\nconst handleClose = (e: MouseEvent) => {\r\n show.value = false\r\n emit('close', e)\r\n}\r\n</script>\r\n\r\n<template>\r\n <component :is=\"props.as\" v-if=\"show\" :class=\"ui.base({ class: props.class })\">\r\n <slot name=\"leading\" :ui=\"ui\" />\r\n\r\n <slot :ui=\"ui\">\r\n <span v-if=\"label\" :class=\"ui.label()\">\r\n {{ label }}\r\n </span>\r\n </slot>\r\n\r\n <slot name=\"trailing\" :ui=\"ui\" />\r\n\r\n <span v-if=\"closable\" @click.stop=\"handleClose\" :class=\"ui.closeButton()\">\r\n <slot name=\"close\" :ui=\"ui\" :close=\"handleClose\">\r\n <Icon :name=\"closeIcon\" class=\"size-3\" />\r\n </slot>\r\n </span>\r\n </component>\r\n</template>\r\n",
23
24
  "target": "web"
24
25
  },
26
+ {
27
+ "path": "index.ts",
28
+ "content": "export { default as RebornBadge } from './RebornBadge.vue'\r\n",
29
+ "target": "uniapp"
30
+ },
25
31
  {
26
32
  "path": "reborn-badge.config.ts",
27
- "content": "const size = ['xs', 'sm', 'md', 'lg', 'xl'] as const\r\nconst color = ['primary', 'secondary', 'success', 'info', 'warning', 'error', 'neutral'] as const\r\nconst variant = ['solid', 'outline', 'soft', 'subtle'] as const\r\n\r\nexport { size as badgeSizes, color as badgeColors, variant as badgeVariants }\r\n\r\nconst compoundVariants = [\r\n {\r\n color: \"primary\",\r\n variant: \"solid\",\r\n class: { base: \"bg-primary text-primary-foreground\" }\r\n },\r\n {\r\n color: \"secondary\",\r\n variant: \"solid\",\r\n class: { base: \"bg-secondary text-secondary-foreground\" }\r\n },\r\n {\r\n color: \"success\",\r\n variant: \"solid\",\r\n class: { base: \"bg-success text-success-foreground\" }\r\n },\r\n {\r\n color: \"info\",\r\n variant: \"solid\",\r\n class: { base: \"bg-info text-info-foreground\" }\r\n },\r\n {\r\n color: \"warning\",\r\n variant: \"solid\",\r\n class: { base: \"bg-warning text-warning-foreground\" }\r\n },\r\n {\r\n color: \"error\",\r\n variant: \"solid\",\r\n class: { base: \"bg-error text-error-foreground\" }\r\n },\r\n {\r\n color: \"neutral\",\r\n variant: \"solid\",\r\n class: { base: \"bg-neutral text-neutral-foreground\" }\r\n },\r\n // outline\r\n {\r\n color: \"primary\",\r\n variant: \"outline\",\r\n class: { base: \"text-primary border border-primary/50\" }\r\n },\r\n {\r\n color: \"secondary\",\r\n variant: \"outline\",\r\n class: { base: \"text-secondary border border-secondary/50\" }\r\n },\r\n {\r\n color: \"error\",\r\n variant: \"outline\",\r\n class: { base: \"text-error border border-error/50\" }\r\n },\r\n {\r\n color: \"success\",\r\n variant: \"outline\",\r\n class: { base: \"text-success border border-success/50\" }\r\n },\r\n {\r\n color: \"warning\",\r\n variant: \"outline\",\r\n class: { base: \"text-warning border border-warning/50\" }\r\n },\r\n {\r\n color: \"info\",\r\n variant: \"outline\",\r\n class: { base: \"text-info border border-info/50\" }\r\n },\r\n {\r\n color: \"neutral\",\r\n variant: \"outline\",\r\n class: { base: \"text-neutral border border-neutral/50\" }\r\n },\r\n // soft\r\n {\r\n color: \"primary\",\r\n variant: \"soft\",\r\n class: { base: \"bg-primary/10 text-primary\" }\r\n },\r\n {\r\n color: \"secondary\",\r\n variant: \"soft\",\r\n class: { base: \"bg-secondary/10 text-secondary\" }\r\n },\r\n {\r\n color: \"error\",\r\n variant: \"soft\",\r\n class: { base: \"bg-error/10 text-error\" }\r\n },\r\n {\r\n color: \"success\",\r\n variant: \"soft\",\r\n class: { base: \"bg-success/10 text-success\" }\r\n },\r\n {\r\n color: \"warning\",\r\n variant: \"soft\",\r\n class: { base: \"bg-warning/10 text-warning\" }\r\n },\r\n {\r\n color: \"info\",\r\n variant: \"soft\",\r\n class: { base: \"bg-info/10 text-info\" }\r\n },\r\n {\r\n color: \"neutral\",\r\n variant: \"soft\",\r\n class: { base: \"bg-neutral/10 text-neutral\" }\r\n },\r\n // subtle\r\n {\r\n color: \"primary\",\r\n variant: \"subtle\",\r\n class: { base: \"bg-primary/10 border border-primary/50 text-primary\" }\r\n },\r\n {\r\n color: \"secondary\",\r\n variant: \"subtle\",\r\n class: { base: \"bg-secondary/10 border border-secondary/50 text-secondary\" }\r\n },\r\n {\r\n color: \"error\",\r\n variant: \"subtle\",\r\n class: { base: \"bg-error/10 border border-error/50 text-error\" }\r\n },\r\n {\r\n color: \"success\",\r\n variant: \"subtle\",\r\n class: { base: \"bg-success/10 border border-success/50 text-success\" }\r\n },\r\n {\r\n color: \"warning\",\r\n variant: \"subtle\",\r\n class: { base: \"bg-warning/10 border border-warning/50 text-warning\" }\r\n },\r\n {\r\n color: \"info\",\r\n variant: \"subtle\",\r\n class: { base: \"bg-info/10 border border-info/50 text-info\" }\r\n },\r\n {\r\n color: \"neutral\",\r\n variant: \"subtle\",\r\n class: { base: \"bg-neutral/10 border border-neutral/50 text-neutral\" }\r\n },\r\n // square\r\n {\r\n size: \"xs\",\r\n square: true,\r\n class: { base: \"w-4 h-4 p-0 items-center justify-center\" }\r\n },\r\n {\r\n size: \"sm\",\r\n square: true,\r\n class: { base: \"w-5 h-5 p-0 items-center justify-center\" }\r\n },\r\n {\r\n size: \"md\",\r\n square: true,\r\n class: { base: \"w-6 h-6 p-0 items-center justify-center\" }\r\n },\r\n {\r\n size: \"lg\",\r\n square: true,\r\n class: { base: \"w-7 h-7 p-0 items-center justify-center\" }\r\n },\r\n] as const\r\n\r\nconst config = {\r\n slots: {\r\n base: \"font-medium inline-flex items-center justify-center\", // Added justify-center\r\n label: \"truncate\",\r\n leadingIcon: \"shrink-0\",\r\n trailingIcon: \"shrink-0\",\r\n closeButton: \"ml-1 inline-flex items-center justify-center rounded-full transition-colors hover:bg-black/10 dark:hover:bg-white/10 cursor-pointer\",\r\n closeIcon: \"shrink-0\"\r\n },\r\n variants: {\r\n color: {\r\n primary: \"\",\r\n secondary: \"\",\r\n success: \"\",\r\n info: \"\",\r\n warning: \"\",\r\n error: \"\",\r\n neutral: \"\"\r\n },\r\n variant: {\r\n solid: \"\",\r\n outline: \"\",\r\n soft: \"\",\r\n subtle: \"\"\r\n },\r\n size: {\r\n xs: {\r\n base: \"text-[20rpx] px-1 py-0.5 gap-1 rounded-sm\",\r\n leadingIcon: \"size-3\",\r\n trailingIcon: \"size-3\",\r\n closeIcon: \"size-3\"\r\n },\r\n sm: {\r\n base: \"text-[22rpx] px-1.5 py-1 gap-1 rounded-sm\",\r\n leadingIcon: \"size-3\",\r\n trailingIcon: \"size-3\",\r\n closeIcon: \"size-3\"\r\n },\r\n md: {\r\n base: \"text-[24rpx] px-2 py-1 gap-1 rounded-md\",\r\n leadingIcon: \"size-4\",\r\n trailingIcon: \"size-4\",\r\n closeIcon: \"size-4\"\r\n },\r\n lg: {\r\n base: \"text-[28rpx] px-2 py-1 gap-1.5 rounded-md\",\r\n leadingIcon: \"size-5\",\r\n trailingIcon: \"size-5\",\r\n closeIcon: \"size-5\"\r\n },\r\n xl: {\r\n base: \"text-[32rpx] px-2.5 py-1 gap-1.5 rounded-md\",\r\n leadingIcon: \"size-6\",\r\n trailingIcon: \"size-6\",\r\n closeIcon: \"size-6\"\r\n }\r\n },\r\n square: {\r\n true: {\r\n base: \"px-1\" // Override padding for square aspect\r\n }\r\n }\r\n },\r\n compoundVariants: compoundVariants as unknown as (typeof compoundVariants)[number][],\r\n defaultVariants: {\r\n color: \"primary\",\r\n variant: \"solid\",\r\n size: \"md\"\r\n } as const\r\n}\r\n\r\nexport default config\r\n",
33
+ "content": "const badgeSizes = ['sm', 'md', 'lg'] as const\r\nconst badgeColors = ['primary', 'secondary', 'success', 'info', 'warning', 'error', 'neutral'] as const\r\nconst badgeVariants = ['solid', 'outline', 'soft', 'subtle'] as const\r\n\r\nexport { badgeColors, badgeSizes, badgeVariants }\r\n\r\nexport type BadgeColor = (typeof badgeColors)[number]\r\nexport type BadgeSize = (typeof badgeSizes)[number]\r\nexport type BadgeVariant = (typeof badgeVariants)[number]\r\n\r\nconst config = {\r\n slots: {\r\n base: 'font-medium inline-flex items-center justify-center p-1 gap-1 transition-all duration-200',\r\n label: 'truncate',\r\n leadingIcon: 'shrink-0',\r\n trailingIcon: 'shrink-0',\r\n closeButton: 'ml-1 inline-flex items-center justify-center rounded-full transition-colors hover:bg-black/10 dark:hover:bg-white/10 cursor-pointer',\r\n closeIcon: 'shrink-0',\r\n },\r\n variants: {\r\n color: {\r\n primary: '',\r\n secondary: '',\r\n success: '',\r\n info: '',\r\n warning: '',\r\n error: '',\r\n neutral: '',\r\n },\r\n variant: {\r\n solid: '',\r\n outline: '',\r\n soft: '',\r\n subtle: '',\r\n },\r\n size: {\r\n sm: {\r\n base: 'h-[28rpx] min-w-[28rpx] text-20 rounded-[6rpx] px-[8rpx]',\r\n leadingIcon: 'size-2',\r\n trailingIcon: 'size-2',\r\n closeIcon: 'size-2',\r\n },\r\n md: {\r\n base: 'h-[36rpx] min-w-[36rpx] leading-1.5 text-22 rounded-[8rpx] px-[12rpx]',\r\n leadingIcon: 'size-3',\r\n trailingIcon: 'size-3',\r\n closeIcon: 'size-3',\r\n },\r\n lg: {\r\n base: 'h-[44rpx] min-w-[44rpx] leading-1.5 text-24 rounded-[12rpx] px-[16rpx]',\r\n leadingIcon: 'size-4',\r\n trailingIcon: 'size-4',\r\n closeIcon: 'size-4',\r\n },\r\n },\r\n square: {\r\n true: {\r\n base: 'px-0 aspect-square',\r\n },\r\n },\r\n },\r\n compoundVariants: [\r\n // solid\r\n { color: 'primary' as BadgeColor, variant: 'solid' as BadgeVariant, class: 'bg-primary text-white' },\r\n { color: 'secondary' as BadgeColor, variant: 'solid' as BadgeVariant, class: 'bg-secondary text-secondary-foreground' },\r\n { color: 'success' as BadgeColor, variant: 'solid' as BadgeVariant, class: 'bg-success text-white' },\r\n { color: 'info' as BadgeColor, variant: 'solid' as BadgeVariant, class: 'bg-info text-white' },\r\n { color: 'warning' as BadgeColor, variant: 'solid' as BadgeVariant, class: 'bg-warning text-white' },\r\n { color: 'error' as BadgeColor, variant: 'solid' as BadgeVariant, class: 'bg-error text-white' },\r\n { color: 'neutral' as BadgeColor, variant: 'solid' as BadgeVariant, class: 'bg-neutral text-white' },\r\n // outline\r\n { color: 'primary' as BadgeColor, variant: 'outline' as BadgeVariant, class: 'text-primary border border-primary/50' },\r\n { color: 'secondary' as BadgeColor, variant: 'outline' as BadgeVariant, class: 'text-secondary border border-secondary/50' },\r\n { color: 'success' as BadgeColor, variant: 'outline' as BadgeVariant, class: 'text-success border border-success/50' },\r\n { color: 'info' as BadgeColor, variant: 'outline' as BadgeVariant, class: 'text-info border border-info/50' },\r\n { color: 'warning' as BadgeColor, variant: 'outline' as BadgeVariant, class: 'text-warning border border-warning/50' },\r\n { color: 'error' as BadgeColor, variant: 'outline' as BadgeVariant, class: 'text-error border border-error/50' },\r\n { color: 'neutral' as BadgeColor, variant: 'outline' as BadgeVariant, class: 'text-neutral border border-neutral/50' },\r\n // soft\r\n { color: 'primary' as BadgeColor, variant: 'soft' as BadgeVariant, class: 'bg-primary/10 text-primary' },\r\n { color: 'secondary' as BadgeColor, variant: 'soft' as BadgeVariant, class: 'bg-secondary/10 text-secondary' },\r\n { color: 'success' as BadgeColor, variant: 'soft' as BadgeVariant, class: 'bg-success/10 text-success' },\r\n { color: 'info' as BadgeColor, variant: 'soft' as BadgeVariant, class: 'bg-info/10 text-info' },\r\n { color: 'warning' as BadgeColor, variant: 'soft' as BadgeVariant, class: 'bg-warning/10 text-warning' },\r\n { color: 'error' as BadgeColor, variant: 'soft' as BadgeVariant, class: 'bg-error/10 text-error' },\r\n { color: 'neutral' as BadgeColor, variant: 'soft' as BadgeVariant, class: 'bg-neutral/10 text-neutral' },\r\n // subtle\r\n { color: 'primary' as BadgeColor, variant: 'subtle' as BadgeVariant, class: 'bg-primary/10 border border-primary/50 text-primary' },\r\n { color: 'secondary' as BadgeColor, variant: 'subtle' as BadgeVariant, class: 'bg-secondary/10 border border-secondary/50 text-secondary' },\r\n { color: 'success' as BadgeColor, variant: 'subtle' as BadgeVariant, class: 'bg-success/10 border border-success/50 text-success' },\r\n { color: 'info' as BadgeColor, variant: 'subtle' as BadgeVariant, class: 'bg-info/10 border border-info/50 text-info' },\r\n { color: 'warning' as BadgeColor, variant: 'subtle' as BadgeVariant, class: 'bg-warning/10 border border-warning/50 text-warning' },\r\n { color: 'error' as BadgeColor, variant: 'subtle' as BadgeVariant, class: 'bg-error/10 border border-error/50 text-error' },\r\n { color: 'neutral' as BadgeColor, variant: 'subtle' as BadgeVariant, class: 'bg-neutral/10 border border-neutral/50 text-neutral' },\r\n ],\r\n defaultVariants: {\r\n color: 'primary' as BadgeColor,\r\n variant: 'solid' as BadgeVariant,\r\n size: 'md' as BadgeSize,\r\n },\r\n}\r\n\r\nexport default config\r\n",
28
34
  "target": "uniapp"
29
35
  },
30
36
  {
31
37
  "path": "RebornBadge.vue",
32
- "content": "<script setup lang=\"ts\">\r\nimport { computed, useSlots, ref } from 'vue'\r\nimport { tv } from '@/lib/tv'\r\nimport { cn } from '@/lib/utils'\r\nimport theme, { badgeColors, badgeSizes, badgeVariants } from './reborn-badge.config'\r\n\r\ndefineOptions({\r\n name: 'reborn-badge',\r\n inheritAttrs: false,\r\n})\r\n\r\nconst b = tv(theme)\r\n\r\nexport interface BadgeProps {\r\n label?: string | number\r\n color?: typeof badgeColors[number]\r\n variant?: typeof badgeVariants[number]\r\n size?: typeof badgeSizes[number]\r\n icon?: string\r\n square?: boolean\r\n closable?: boolean\r\n closeIcon?: string\r\n customClass?: any\r\n ui?: {\r\n base?: string\r\n label?: string\r\n leadingIcon?: string\r\n trailingIcon?: string\r\n closeButton?: string\r\n closeIcon?: string\r\n }\r\n}\r\n\r\nconst props = withDefaults(defineProps<BadgeProps>(), {\r\n color: 'primary',\r\n variant: 'solid',\r\n size: 'md',\r\n closeIcon: 'i-mdi-close-circle', // Standard icon name, change if using SVG/Lucide\r\n})\r\n\r\nconst emit = defineEmits(['close', 'click'])\r\n\r\nconst slots = useSlots()\r\nconst isClosing = ref(false)\r\n\r\nconst uiOverrides = computed(() => props.ui || {});\r\n\r\nconst ui = computed(() => {\r\n const styles = b({\r\n color: props.color,\r\n variant: props.variant,\r\n size: props.size,\r\n square: props.square || (!props.label && !props.icon && !slots.default),\r\n })\r\n\r\n return {\r\n base: (opts?: { class?: any }) => styles.base({ class: cn(opts?.class, uiOverrides.value.base) }),\r\n label: (opts?: { class?: any }) => styles.label({ class: cn(opts?.class, uiOverrides.value.label) }),\r\n leadingIcon: (opts?: { class?: any }) => styles.leadingIcon({ class: cn(opts?.class, uiOverrides.value.leadingIcon) }),\r\n trailingIcon: (opts?: { class?: any }) => styles.trailingIcon({ class: cn(opts?.class, uiOverrides.value.trailingIcon) }),\r\n closeButton: (opts?: { class?: any }) => styles.closeButton({ class: cn(opts?.class, uiOverrides.value.closeButton) }),\r\n closeIcon: (opts?: { class?: any }) => styles.closeIcon({ class: cn(opts?.class, uiOverrides.value.closeIcon) }),\r\n }\r\n})\r\n\r\nconst onClick = (e: any) => {\r\n emit('click', e)\r\n}\r\n\r\nconst handleClose = (e: any) => {\r\n // Only stop propagation if we are handling close\r\n // In UniApp we might default stop\r\n // e.stopPropagation() // Standard Vue\r\n isClosing.value = true\r\n setTimeout(() => {\r\n emit('close', e)\r\n // Optional: reset isClosing if the component is not destroyed (e.g. parent doesn't hide it)\r\n // But usually it is hidden. If not, it stays invisible.\r\n // Let's reset it just in case? No, if we reset, it pops back in.\r\n // If the parent doesn't hide it, it stays invisible (closing state).\r\n }, 200)\r\n}\r\n</script>\r\n\r\n<template>\r\n <view\r\n :class=\"ui.base({ class: cn(props.customClass, 'transition-all duration-200 ease-in-out', isClosing && 'opacity-0 scale-90') })\"\r\n @tap=\"onClick\">\r\n <slot name=\"leading\">\r\n <view v-if=\"props.icon\" :class=\"cn(props.icon, ui.leadingIcon())\"></view>\r\n </slot>\r\n\r\n <slot>\r\n <text v-if=\"props.label\" :class=\"ui.label()\">{{ props.label }}</text>\r\n </slot>\r\n\r\n <slot name=\"trailing\"></slot>\r\n\r\n <view v-if=\"props.closable\" @tap.stop=\"handleClose\" :class=\"ui.closeButton()\">\r\n <slot name=\"close\">\r\n <!-- Using simple text x or check if icon component exists -->\r\n <!-- <text>×</text> -->\r\n <view :class=\"cn(props.closeIcon, ui.closeIcon())\" /> <!-- Assuming icon class -->\r\n </slot>\r\n </view>\r\n </view>\r\n</template>\r\n\r\n<style scoped></style>\r\n",
38
+ "content": "<script setup lang=\"ts\">\r\nimport type { badgeColors, badgeSizes, badgeVariants } from './reborn-badge.config'\r\nimport { computed, ref, useSlots } from 'vue'\r\nimport { tv } from '@/lib/tv'\r\nimport { cn } from '@/lib/utils'\r\nimport theme from './reborn-badge.config'\r\n\r\ndefineOptions({\r\n name: 'RebornBadge',\r\n inheritAttrs: false,\r\n})\r\n\r\nimport type { BadgeColor, BadgeSize, BadgeVariant } from './reborn-badge.config'\r\n\r\nexport interface BadgeProps {\r\n label?: string | number\r\n color?: BadgeColor\r\n variant?: BadgeVariant\r\n size?: BadgeSize\r\n icon?: string\r\n square?: boolean\r\n closable?: boolean\r\n closeIcon?: string\r\n customClass?: any\r\n ui?: {\r\n base?: string\r\n label?: string\r\n leadingIcon?: string\r\n trailingIcon?: string\r\n closeButton?: string\r\n closeIcon?: string\r\n }\r\n}\r\n\r\nconst props = withDefaults(defineProps<BadgeProps>(), {\r\n color: 'primary',\r\n variant: 'solid',\r\n size: 'md',\r\n closeIcon: 'i-mdi-close-circle',\r\n})\r\n\r\nconst emit = defineEmits(['close', 'click'])\r\n\r\nconst b = tv(theme)\r\n\r\nconst slots = useSlots()\r\nconst isClosing = ref(false)\r\n\r\nconst uiOverrides = computed(() => props.ui || {})\r\n\r\nconst ui = computed(() => {\r\n const styles = b({\r\n color: props.color,\r\n variant: props.variant,\r\n size: props.size,\r\n square: props.square || (!props.label && !props.icon && !slots.default),\r\n })\r\n\r\n return {\r\n base: (opts?: { class?: any }) => styles.base({ class: cn(opts?.class, uiOverrides.value.base) }),\r\n label: (opts?: { class?: any }) => styles.label({ class: cn(opts?.class, uiOverrides.value.label) }),\r\n leadingIcon: (opts?: { class?: any }) => styles.leadingIcon({ class: cn(opts?.class, uiOverrides.value.leadingIcon) }),\r\n trailingIcon: (opts?: { class?: any }) => styles.trailingIcon({ class: cn(opts?.class, uiOverrides.value.trailingIcon) }),\r\n closeButton: (opts?: { class?: any }) => styles.closeButton({ class: cn(opts?.class, uiOverrides.value.closeButton) }),\r\n closeIcon: (opts?: { class?: any }) => styles.closeIcon({ class: cn(opts?.class, uiOverrides.value.closeIcon) }),\r\n }\r\n})\r\n\r\nfunction onClick(e: any) {\r\n emit('click', e)\r\n}\r\n\r\nfunction handleClose(e: any) {\r\n isClosing.value = true\r\n nextTick(() => {\r\n emit('close', e)\r\n })\r\n}\r\n</script>\r\n\r\n<template>\r\n <view :class=\"ui.base({\r\n class: cn(props.customClass, `\r\n transition-all duration-200 ease-in-out\r\n `, isClosing && 'scale-90 opacity-0')\r\n })\" @tap=\"onClick\">\r\n <slot name=\"leading\">\r\n <view v-if=\"props.icon\" :class=\"cn(props.icon, ui.leadingIcon())\" />\r\n </slot>\r\n\r\n <slot>\r\n <text v-if=\"props.label\" :class=\"ui.label()\">{{ props.label }}</text>\r\n </slot>\r\n\r\n <slot name=\"trailing\" />\r\n\r\n <view v-if=\"props.closable\" :class=\"ui.closeButton()\" @tap.stop=\"handleClose\">\r\n <slot name=\"close\">\r\n <view :class=\"cn(props.closeIcon, ui.closeIcon())\" />\r\n </slot>\r\n </view>\r\n </view>\r\n</template>\r\n\r\n<style scoped></style>\r\n",
33
39
  "target": "uniapp"
34
40
  }
35
41
  ],
36
- "fileCount": 6,
37
- "contentHash": "36f03b5674547ca8ede7a1ed491667f5140dd754"
42
+ "fileCount": 7,
43
+ "contentHash": "34fb4a79768efa20066fd5e2b9d7d2eb65e56e39"
38
44
  }
@@ -14,25 +14,25 @@
14
14
  },
15
15
  {
16
16
  "path": "RebornButton.vue",
17
- "content": "<script setup lang=\"ts\">\r\nimport { computed, toRef } from 'vue'\r\nimport theme, { buttonColors, buttonVariants, buttonSizes } from './reborn-button.config'\r\nimport { useFieldGroup } from '~/composables/useFieldGroup'\r\nimport { tv } from '~/lib/tv'\r\n\r\nconst b = tv(theme)\r\n\r\nexport interface ButtonProps {\r\n label?: string\r\n color?: typeof buttonColors[number]\r\n variant?: typeof buttonVariants[number]\r\n size?: typeof buttonSizes[number]\r\n loading?: boolean\r\n disabled?: boolean\r\n square?: boolean\r\n class?: any\r\n ui?: any\r\n}\r\n\r\nconst props = withDefaults(defineProps<ButtonProps>(), {\r\n color: 'primary',\r\n variant: 'solid',\r\n size: 'md',\r\n loading: false,\r\n disabled: false,\r\n square: false\r\n})\r\n\r\nconst slots = defineSlots<{\r\n leading(props: { ui: any }): any\r\n default(props: { ui: any }): any\r\n trailing(props: { ui: any }): any\r\n}>()\r\n\r\nconst { orientation, size: fieldGroupSize } = useFieldGroup(props)\r\n\r\nconst isDisabled = computed(() => props.disabled || props.loading)\r\n\r\nconst color = toRef(props, 'color')\r\nconst variant = toRef(props, 'variant')\r\nconst size = toRef(props, 'size')\r\nconst square = toRef(props, 'square')\r\n\r\nconst ui = computed(() => b({\r\n color: color.value,\r\n variant: variant.value,\r\n size: (fieldGroupSize.value || size.value) as any,\r\n square: square.value,\r\n fieldGroup: orientation.value\r\n}))\r\n</script>\r\n\r\n<template>\r\n <button :disabled=\"isDisabled\" :class=\"ui.base({ class: props.class })\" v-bind=\"$attrs\">\r\n <slot name=\"leading\" :ui=\"ui\">\r\n <Icon name=\"svg-spinners:270-ring\" v-if=\"props.loading\" :class=\"ui.leadingIcon()\" />\r\n </slot>\r\n\r\n <slot :ui=\"ui\">\r\n <span v-if=\"label\" :class=\"ui.base()\">\r\n {{ label }}\r\n </span>\r\n <slot v-else :ui=\"ui\" />\r\n </slot>\r\n\r\n\r\n <slot name=\"trailing\" :ui=\"ui\" />\r\n </button>\r\n</template>\r\n",
17
+ "content": "<script setup lang=\"ts\">\r\nimport { computed, toRef } from 'vue'\r\nimport theme, { buttonColors, buttonVariants, buttonSizes } from './reborn-button.config'\r\nimport { useFieldGroup } from '~/composables/useFieldGroup'\r\nimport { tv } from '~/lib/tv'\r\nimport { cn } from '~/lib/utils'\r\n\r\n\r\nexport interface ButtonProps {\r\n label?: string\r\n color?: typeof buttonColors[number]\r\n variant?: typeof buttonVariants[number]\r\n size?: typeof buttonSizes[number]\r\n loading?: boolean\r\n disabled?: boolean\r\n square?: boolean\r\n class?: any\r\n ui?: any\r\n}\r\n\r\nconst props = withDefaults(defineProps<ButtonProps>(), {\r\n color: 'primary',\r\n variant: 'solid',\r\n size: 'md',\r\n loading: false,\r\n disabled: false,\r\n square: false\r\n})\r\n\r\nconst slots = defineSlots<{\r\n leading(props: { ui: any }): any\r\n default(props: { ui: any }): any\r\n trailing(props: { ui: any }): any\r\n}>()\r\n\r\nconst { orientation, size: fieldGroupSize } = useFieldGroup(props)\r\n\r\nconst isDisabled = computed(() => props.disabled || props.loading)\r\n\r\nconst color = toRef(props, 'color')\r\nconst variant = toRef(props, 'variant')\r\nconst size = toRef(props, 'size')\r\nconst square = toRef(props, 'square')\r\n\r\nconst b = tv(theme)\r\nconst uiOverrides = computed(() => props.ui || {})\r\n\r\nconst ui = computed(() => {\r\n const styles = b({\r\n color: color.value,\r\n variant: variant.value,\r\n size: (fieldGroupSize.value || size.value) as any,\r\n square: square.value,\r\n fieldGroup: orientation.value,\r\n })\r\n\r\n return {\r\n base: (opts?: { class?: any }) => styles.base({ class: cn(opts?.class, uiOverrides.value.base) }),\r\n label: (opts?: { class?: any }) => styles.label({ class: cn(opts?.class, uiOverrides.value.label) }),\r\n leadingIcon: (opts?: { class?: any }) => styles.leadingIcon({ class: cn(opts?.class, uiOverrides.value.leadingIcon) }),\r\n leadingAvatar: (opts?: { class?: any }) => styles.leadingAvatar({ class: cn(opts?.class, uiOverrides.value.leadingAvatar) }),\r\n leadingAvatarSize: (opts?: { class?: any }) => styles.leadingAvatarSize({ class: cn(opts?.class, uiOverrides.value.leadingAvatarSize) }),\r\n trailingIcon: (opts?: { class?: any }) => styles.trailingIcon({ class: cn(opts?.class, uiOverrides.value.trailingIcon) }),\r\n }\r\n})\r\n</script>\r\n\r\n<template>\r\n <button :disabled=\"isDisabled\" :class=\"ui.base({ class: props.class })\" v-bind=\"$attrs\">\r\n <slot name=\"leading\" :ui=\"ui\">\r\n <Icon name=\"svg-spinners:270-ring\" v-if=\"props.loading\" :class=\"ui.leadingIcon()\" />\r\n </slot>\r\n\r\n <slot :ui=\"ui\">\r\n <span v-if=\"label\" :class=\"ui.label()\">\r\n {{ label }}\r\n </span>\r\n <slot v-else :ui=\"ui\" />\r\n </slot>\r\n\r\n\r\n <slot name=\"trailing\" :ui=\"ui.trailingIcon()\" />\r\n </button>\r\n</template>\r\n",
18
18
  "target": "web"
19
19
  },
20
20
  {
21
21
  "path": "index.ts",
22
- "content": "export { default as RebornButton } from \"./RebornButton.vue\";\r\n",
22
+ "content": "export { default as RebornButton } from './RebornButton.vue'\r\n",
23
23
  "target": "uniapp"
24
24
  },
25
25
  {
26
26
  "path": "reborn-button.config.ts",
27
- "content": "export const buttonColors = [\"primary\", \"secondary\", \"success\", \"info\", \"warning\", \"error\", \"neutral\"] as const;\r\nexport const buttonVariants = [\"solid\", \"outline\", \"soft\", \"subtle\"] as const;\r\n\r\nexport const buttonSizes = [\r\n \"xs\",\r\n \"sm\",\r\n \"default\", // Mapped to md\r\n \"md\",\r\n \"lg\",\r\n \"xl\",\r\n \"2xl\",\r\n \"icon-xs\",\r\n \"icon-sm\",\r\n \"icon\", // Mapped to icon-md\r\n \"icon-md\",\r\n \"icon-lg\",\r\n \"icon-xl\",\r\n \"icon-2xl\",\r\n] as const;\r\n\r\nexport default {\r\n slots: {\r\n base: \"inline-flex items-center justify-center gap-2 whitespace-nowrap transition-all cursor-pointer disabled:cursor-not-allowed disabled:opacity-70 disabled:bg-gdray-4 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\r\n label: \"truncate\",\r\n leadingIcon: \"shrink-0\",\r\n leadingAvatar: \"shrink-0\",\r\n leadingAvatarSize: \"\",\r\n trailingIcon: \"shrink-0\",\r\n },\r\n variants: {\r\n fieldGroup: {\r\n horizontal:\r\n \"not-only:first:rounded-e-none not-only:last:rounded-s-none not-last:not-first:rounded-none focus-visible:z-[1]\",\r\n vertical:\r\n \"not-only:first:rounded-b-none not-only:last:rounded-t-none not-last:not-first:rounded-none focus-visible:z-[1]\",\r\n },\r\n color: {\r\n primary: \"\",\r\n secondary: \"\",\r\n success: \"\",\r\n info: \"\",\r\n warning: \"\",\r\n error: \"\",\r\n neutral: \"\",\r\n },\r\n variant: {\r\n solid: \"\",\r\n outline: \"\",\r\n soft: \"\",\r\n subtle: \"\",\r\n },\r\n size: {\r\n xs: {\r\n base: \"h-[var(--button-xs-height)] text-24 gap-1.5 px-3 has-[>svg]:px-2.5\",\r\n },\r\n sm: {\r\n base: \"h-[var(--button-sm-height)] text-24 gap-1.5 px-3 has-[>svg]:px-2.5\",\r\n },\r\n default: {\r\n base: \"h-[var(--button-base-height)] text-26 px-4 py-4 has-[>svg]:px-3\",\r\n },\r\n md: { base: \"h-[var(--button-base-height)] text-26 px-4 py-4 has-[>svg]:px-3\" },\r\n lg: { base: \"h-[var(--button-lg-height)] text-28 px-6 has-[>svg]:px-4\" },\r\n xl: { base: \"h-[var(--button-xl-height)] text-30 px-6 has-[>svg]:px-4\" },\r\n \"2xl\": { base: \"h-[var(--button-2xl-height)] text-32 px-6 has-[>svg]:px-4\" },\r\n \"icon-xs\": { base: \"\" },\r\n \"icon-sm\": { base: \"size-[var(--button-sm-height)] p-1\" },\r\n icon: { base: \"size-[var(--button-base-height)] p-2\" },\r\n \"icon-md\": { base: \"size-[var(--button-base-height)] p-2\" },\r\n \"icon-lg\": { base: \"size-[var(--button-lg-height)] p-2.5\" },\r\n \"icon-xl\": { base: \"size-[var(--button-xl-height)] p-2.5\" },\r\n \"icon-2xl\": { base: \"size-[var(--button-2xl-height)] p-2.5\" },\r\n },\r\n square: {\r\n true: { base: \"p-0\" },\r\n },\r\n },\r\n compoundVariants: [\r\n // Solid Variants\r\n {\r\n color: \"primary\" as (typeof buttonColors)[number],\r\n variant: \"solid\" as (typeof buttonVariants)[number],\r\n class: \"bg-primary text-white hover:bg-primary/75\",\r\n },\r\n {\r\n color: \"secondary\" as (typeof buttonColors)[number],\r\n variant: \"solid\" as (typeof buttonVariants)[number],\r\n class: \"bg-secondary text-white hover:bg-secondary/75\",\r\n },\r\n {\r\n color: \"success\" as (typeof buttonColors)[number],\r\n variant: \"solid\" as (typeof buttonVariants)[number],\r\n class: \"bg-success text-white hover:bg-success/75\",\r\n },\r\n {\r\n color: \"info\" as (typeof buttonColors)[number],\r\n variant: \"solid\" as (typeof buttonVariants)[number],\r\n class: \"bg-info text-white hover:bg-info/75\",\r\n },\r\n {\r\n color: \"warning\" as (typeof buttonColors)[number],\r\n variant: \"solid\" as (typeof buttonVariants)[number],\r\n class: \"bg-warning text-white hover:bg-warning/75\",\r\n },\r\n {\r\n color: \"error\" as (typeof buttonColors)[number],\r\n variant: \"solid\" as (typeof buttonVariants)[number],\r\n class: \"bg-error text-white hover:bg-error/75\",\r\n },\r\n {\r\n color: \"neutral\" as (typeof buttonColors)[number],\r\n variant: \"solid\" as (typeof buttonVariants)[number],\r\n class: \"bg-neutral text-white hover:bg-neutral/75\",\r\n },\r\n\r\n // Outline Variants\r\n {\r\n color: \"primary\" as (typeof buttonColors)[number],\r\n variant: \"outline\" as (typeof buttonVariants)[number],\r\n class:\r\n \"bg-transparent text-primary border border-primary hover:bg-primary/10 disabled:bg-gray-2 disabled:border-gray-4 disabled:text-gray-6\",\r\n },\r\n {\r\n color: \"secondary\" as (typeof buttonColors)[number],\r\n variant: \"outline\" as (typeof buttonVariants)[number],\r\n class:\r\n \"bg-transparent text-secondary border border-secondary hover:bg-secondary/10 disabled:bg-gray-2 disabled:border-gray-4 disabled:text-gray-6\",\r\n },\r\n {\r\n color: \"success\" as (typeof buttonColors)[number],\r\n variant: \"outline\" as (typeof buttonVariants)[number],\r\n class:\r\n \"bg-transparent text-success border border-success hover:bg-success/10 disabled:bg-gray-2 disabled:border-gray-4 disabled:text-gray-6\",\r\n },\r\n {\r\n color: \"info\" as (typeof buttonColors)[number],\r\n variant: \"outline\" as (typeof buttonVariants)[number],\r\n class:\r\n \"bg-transparent text-info border border-info hover:bg-info/10 disabled:bg-gray-2 disabled:border-gray-4 disabled:text-gray-6\",\r\n },\r\n {\r\n color: \"warning\" as (typeof buttonColors)[number],\r\n variant: \"outline\" as (typeof buttonVariants)[number],\r\n class:\r\n \"bg-transparent text-warning border border-warning hover:bg-warning/10 disabled:bg-gray-2 disabled:border-gray-4 disabled:text-gray-6\",\r\n },\r\n {\r\n color: \"error\" as (typeof buttonColors)[number],\r\n variant: \"outline\" as (typeof buttonVariants)[number],\r\n class:\r\n \"bg-transparent text-error border border-error hover:bg-error/10 disabled:bg-gray-2 disabled:border-gray-4 disabled:text-gray-6\",\r\n },\r\n {\r\n color: \"neutral\" as (typeof buttonColors)[number],\r\n variant: \"outline\" as (typeof buttonVariants)[number],\r\n class:\r\n \"bg-transparent text-neutral border border-neutral hover:bg-neutral/10 disabled:bg-gray-2 disabled:border-gray-4 disabled:text-gray-6\",\r\n },\r\n\r\n // Soft Variants\r\n {\r\n color: \"primary\" as (typeof buttonColors)[number],\r\n variant: \"soft\" as (typeof buttonVariants)[number],\r\n class: \"bg-primary/10 text-primary hover:bg-primary/20\",\r\n },\r\n {\r\n color: \"secondary\" as (typeof buttonColors)[number],\r\n variant: \"soft\" as (typeof buttonVariants)[number],\r\n class: \"bg-secondary/10 text-secondary hover:bg-secondary/20\",\r\n },\r\n {\r\n color: \"success\" as (typeof buttonColors)[number],\r\n variant: \"soft\" as (typeof buttonVariants)[number],\r\n class: \"bg-success/10 text-success hover:bg-success/20\",\r\n },\r\n {\r\n color: \"info\" as (typeof buttonColors)[number],\r\n variant: \"soft\" as (typeof buttonVariants)[number],\r\n class: \"bg-info/10 text-info hover:bg-info/20\",\r\n },\r\n {\r\n color: \"warning\" as (typeof buttonColors)[number],\r\n variant: \"soft\" as (typeof buttonVariants)[number],\r\n class: \"bg-warning/10 text-warning hover:bg-warning/20\",\r\n },\r\n {\r\n color: \"error\" as (typeof buttonColors)[number],\r\n variant: \"soft\" as (typeof buttonVariants)[number],\r\n class: \"bg-error/10 text-error hover:bg-error/20\",\r\n },\r\n {\r\n color: \"neutral\" as (typeof buttonColors)[number],\r\n variant: \"soft\" as (typeof buttonVariants)[number],\r\n class: \"bg-neutral/10 text-neutral hover:bg-neutral/20\",\r\n },\r\n\r\n // Subtle Variants\r\n {\r\n color: \"primary\" as (typeof buttonColors)[number],\r\n variant: \"subtle\" as (typeof buttonVariants)[number],\r\n class: \"bg-primary/10 border border-primary text-primary hover:bg-primary/20\",\r\n },\r\n {\r\n color: \"secondary\" as (typeof buttonColors)[number],\r\n variant: \"subtle\" as (typeof buttonVariants)[number],\r\n class:\r\n \"bg-secondary/10 border border-secondary text-secondary hover:bg-secondary/20\",\r\n },\r\n {\r\n color: \"success\" as (typeof buttonColors)[number],\r\n variant: \"subtle\" as (typeof buttonVariants)[number],\r\n class: \"bg-success/10 border border-success text-success hover:bg-success/20\",\r\n },\r\n {\r\n color: \"info\" as (typeof buttonColors)[number],\r\n variant: \"subtle\" as (typeof buttonVariants)[number],\r\n class: \"bg-info/10 border border-info text-info hover:bg-info/20\",\r\n },\r\n {\r\n color: \"warning\" as (typeof buttonColors)[number],\r\n variant: \"subtle\" as (typeof buttonVariants)[number],\r\n class: \"bg-warning/10 border border-warning text-warning hover:bg-warning/20\",\r\n },\r\n {\r\n color: \"error\" as (typeof buttonColors)[number],\r\n variant: \"subtle\" as (typeof buttonVariants)[number],\r\n class: \"bg-error/10 border border-error text-error hover:bg-error/20\",\r\n },\r\n {\r\n color: \"neutral\" as (typeof buttonColors)[number],\r\n variant: \"subtle\" as (typeof buttonVariants)[number],\r\n class: \"bg-neutral/10 border border-neutral text-neutral hover:bg-neutral/20\",\r\n },\r\n ],\r\n defaultVariants: {\r\n color: \"primary\" as (typeof buttonColors)[number],\r\n variant: \"solid\" as (typeof buttonVariants)[number],\r\n size: \"md\" as (typeof buttonSizes)[number],\r\n },\r\n};\r\n",
27
+ "content": "export const buttonColors = ['primary', 'secondary', 'success', 'info', 'warning', 'error', 'neutral'] as const\r\nexport const buttonVariants = ['solid', 'outline', 'soft', 'subtle'] as const\r\n\r\nexport const buttonSizes = [\r\n 'xs',\r\n 'sm',\r\n 'md',\r\n 'lg',\r\n 'xl',\r\n '2xl',\r\n] as const\r\n\r\nexport default {\r\n slots: {\r\n base: 'reborn-button flex flex-row items-center justify-center relative box-border border-transparent border border-solid transition-[background-color,border-color,opacity] duration-300 overflow-visible',\r\n inner: 'reborn-button-clicker absolute inset-0 z-10 m-0 size-full p-0 opacity-0',\r\n label: 'truncate',\r\n loading: 'border-2 border-current border-t-transparent rounded-full animate-spin',\r\n leadingIcon: 'shrink-0',\r\n leadingAvatar: 'shrink-0',\r\n leadingAvatarSize: '',\r\n trailingIcon: 'shrink-0',\r\n },\r\n variants: {\r\n color: {\r\n primary: '',\r\n secondary: '',\r\n success: '',\r\n info: '',\r\n warning: '',\r\n error: '',\r\n neutral: '',\r\n },\r\n block: {\r\n true: {\r\n base: 'flex'\r\n },\r\n false: {\r\n base: 'inline-flex',\r\n }\r\n },\r\n variant: {\r\n solid: '',\r\n outline: '',\r\n soft: '',\r\n subtle: '',\r\n },\r\n disabled: {\r\n true: {\r\n base: '!bg-opacity-60 !border-opacity-60 !text-opacity-60',\r\n },\r\n false: '',\r\n },\r\n size: {\r\n 'xs': {\r\n base: 'h-button-xs px-3 text-24 gap-1.5 rounded-[6px]',\r\n loading: 'size-3',\r\n },\r\n 'sm': {\r\n base: 'h-button-sm px-3 text-24 gap-1.5 rounded-[6px]',\r\n loading: 'size-3.5',\r\n },\r\n 'md': {\r\n base: 'h-button-md px-4 text-26 gap-1.5 rounded-[8px]',\r\n loading: 'size-4',\r\n },\r\n 'lg': {\r\n base: 'h-button-lg px-6 text-28 gap-1.5 rounded-[10px]',\r\n loading: 'size-5',\r\n },\r\n 'xl': {\r\n base: 'h-button-xl px-6 text-30 gap-2 rounded-[12px]',\r\n loading: 'size-6',\r\n },\r\n '2xl': {\r\n base: 'h-button-2xl px-6 text-32 gap-2 rounded-[14px]',\r\n loading: 'size-7',\r\n },\r\n },\r\n gap: {\r\n true: {\r\n base: '[.reborn-button_+_&]:ml-2',\r\n },\r\n false: '',\r\n },\r\n },\r\n compoundVariants: [\r\n // Solid Variants\r\n {\r\n color: 'primary' as (typeof buttonColors)[number],\r\n variant: 'solid' as (typeof buttonVariants)[number],\r\n class: 'bg-primary border-primary text-white hover:bg-primary/90',\r\n },\r\n {\r\n color: 'secondary' as (typeof buttonColors)[number],\r\n variant: 'solid' as (typeof buttonVariants)[number],\r\n class: 'bg-secondary border-secondary text-secondary-foreground hover:bg-secondary/90',\r\n },\r\n {\r\n color: 'success' as (typeof buttonColors)[number],\r\n variant: 'solid' as (typeof buttonVariants)[number],\r\n class: 'bg-success border-success text-white hover:bg-success/90',\r\n },\r\n {\r\n color: 'info' as (typeof buttonColors)[number],\r\n variant: 'solid' as (typeof buttonVariants)[number],\r\n class: 'bg-info border-info text-white hover:bg-info/90',\r\n },\r\n {\r\n color: 'warning' as (typeof buttonColors)[number],\r\n variant: 'solid' as (typeof buttonVariants)[number],\r\n class: 'bg-warning border-warning text-white hover:bg-warning/90',\r\n },\r\n {\r\n color: 'error' as (typeof buttonColors)[number],\r\n variant: 'solid' as (typeof buttonVariants)[number],\r\n class: 'bg-error border-error text-white hover:bg-error/90',\r\n },\r\n {\r\n color: 'neutral' as (typeof buttonColors)[number],\r\n variant: 'solid' as (typeof buttonVariants)[number],\r\n class: 'bg-neutral border-neutral text-white hover:bg-neutral/90',\r\n },\r\n\r\n // Outline Variants\r\n {\r\n color: 'primary' as (typeof buttonColors)[number],\r\n variant: 'outline' as (typeof buttonVariants)[number],\r\n class:\r\n 'bg-transparent text-primary border-primary hover:bg-primary-50',\r\n },\r\n {\r\n color: 'secondary' as (typeof buttonColors)[number],\r\n variant: 'outline' as (typeof buttonVariants)[number],\r\n class:\r\n 'bg-transparent text-secondary border-secondary hover:bg-secondary-50',\r\n },\r\n {\r\n color: 'success' as (typeof buttonColors)[number],\r\n variant: 'outline' as (typeof buttonVariants)[number],\r\n class:\r\n 'bg-transparent text-success border-success hover:bg-success-50',\r\n },\r\n {\r\n color: 'info' as (typeof buttonColors)[number],\r\n variant: 'outline' as (typeof buttonVariants)[number],\r\n class:\r\n 'bg-transparent text-info border-info hover:bg-info-50',\r\n },\r\n {\r\n color: 'warning' as (typeof buttonColors)[number],\r\n variant: 'outline' as (typeof buttonVariants)[number],\r\n class:\r\n 'bg-transparent text-warning border-warning hover:bg-warning-50',\r\n },\r\n {\r\n color: 'error' as (typeof buttonColors)[number],\r\n variant: 'outline' as (typeof buttonVariants)[number],\r\n class:\r\n 'bg-transparent text-error border-error hover:bg-error-50',\r\n },\r\n {\r\n color: 'neutral' as (typeof buttonColors)[number],\r\n variant: 'outline' as (typeof buttonVariants)[number],\r\n class:\r\n 'bg-transparent text-neutral border-neutral hover:bg-neutral-50',\r\n },\r\n\r\n // Soft Variants\r\n {\r\n color: 'primary' as (typeof buttonColors)[number],\r\n variant: 'soft' as (typeof buttonVariants)[number],\r\n class: 'bg-primary/10 border-transparent text-primary hover:bg-primary/20',\r\n },\r\n {\r\n color: 'secondary' as (typeof buttonColors)[number],\r\n variant: 'soft' as (typeof buttonVariants)[number],\r\n class: 'bg-secondary/10 border-transparent text-secondary hover:bg-secondary/20',\r\n },\r\n {\r\n color: 'success' as (typeof buttonColors)[number],\r\n variant: 'soft' as (typeof buttonVariants)[number],\r\n class: 'bg-success/10 border-transparent text-success hover:bg-success/20',\r\n },\r\n {\r\n color: 'info' as (typeof buttonColors)[number],\r\n variant: 'soft' as (typeof buttonVariants)[number],\r\n class: 'bg-info/10 border-transparent text-info hover:bg-info/20',\r\n },\r\n {\r\n color: 'warning' as (typeof buttonColors)[number],\r\n variant: 'soft' as (typeof buttonVariants)[number],\r\n class: 'bg-warning/10 border-transparent text-warning hover:bg-warning/20',\r\n },\r\n {\r\n color: 'error' as (typeof buttonColors)[number],\r\n variant: 'soft' as (typeof buttonVariants)[number],\r\n class: 'bg-error/10 border-transparent text-error hover:bg-error/20',\r\n },\r\n {\r\n color: 'neutral' as (typeof buttonColors)[number],\r\n variant: 'soft' as (typeof buttonVariants)[number],\r\n class: 'bg-neutral/10 border-transparent text-neutral hover:bg-neutral/20',\r\n },\r\n\r\n // Subtle Variants\r\n {\r\n color: 'primary' as (typeof buttonColors)[number],\r\n variant: 'subtle' as (typeof buttonVariants)[number],\r\n class: 'bg-primary/10 border-primary text-primary hover:bg-primary/20',\r\n },\r\n {\r\n color: 'secondary' as (typeof buttonColors)[number],\r\n variant: 'subtle' as (typeof buttonVariants)[number],\r\n class:\r\n 'bg-secondary/10 border-secondary text-secondary hover:bg-secondary/20',\r\n },\r\n {\r\n color: 'success' as (typeof buttonColors)[number],\r\n variant: 'subtle' as (typeof buttonVariants)[number],\r\n class: 'bg-success/10 border-success text-success hover:bg-success/20',\r\n },\r\n {\r\n color: 'info' as (typeof buttonColors)[number],\r\n variant: 'subtle' as (typeof buttonVariants)[number],\r\n class: 'bg-info/10 border-info text-info hover:bg-info/20',\r\n },\r\n {\r\n color: 'warning' as (typeof buttonColors)[number],\r\n variant: 'subtle' as (typeof buttonVariants)[number],\r\n class: 'bg-warning/10 border-warning text-warning hover:bg-warning/20',\r\n },\r\n {\r\n color: 'error' as (typeof buttonColors)[number],\r\n variant: 'subtle' as (typeof buttonVariants)[number],\r\n class: 'bg-error/10 border-error text-error hover:bg-error/20',\r\n },\r\n {\r\n color: 'neutral' as (typeof buttonColors)[number],\r\n variant: 'subtle' as (typeof buttonVariants)[number],\r\n class: 'bg-neutral/10 border-neutral text-neutral hover:bg-neutral/20',\r\n },\r\n ],\r\n defaultVariants: {\r\n color: 'primary' as (typeof buttonColors)[number],\r\n variant: 'solid' as (typeof buttonVariants)[number],\r\n size: 'md' as (typeof buttonSizes)[number],\r\n block: false\r\n },\r\n}\r\n",
28
28
  "target": "uniapp"
29
29
  },
30
30
  {
31
31
  "path": "RebornButton.vue",
32
- "content": "<script lang=\"ts\">\r\nexport interface ButtonProps {\r\n label?: string\r\n color?: typeof buttonColors[number]\r\n variant?: typeof buttonVariants[number]\r\n size?: typeof buttonSizes[number]\r\n loading?: boolean\r\n disabled?: boolean\r\n square?: boolean\r\n customClass?: any\r\n ui?: any,\r\n hoverClass?: string, // 按钮点击态样式类\r\n hoverStopPropagation?: boolean, // 是否阻止点击态冒泡\r\n hoverStartTime?: number, // 按钮点击态持续时间\r\n hoverStayTime?: number, // 按钮点击态持续时间\r\n formType?: string, // 表单提交类型\r\n openType?: string, // 开放能力类型\r\n sessionFrom?: string, // 会话来源\r\n sendMessageTitle?: string, // 会话标题\r\n sendMessagePath?: string, // 会话路径\r\n sendMessageImg?: string, // 会话图片\r\n showMessageCard?: boolean, // 显示会话卡片\r\n appParameter?: string, // 打开 APP 时,向 APP 传递的参数\r\n groupId?: string, // 群ID\r\n guildId?: string, // 公会ID\r\n publicId?: string, // 公众号ID\r\n phoneNumberNoQuotaToast?: boolean, // 手机号获取失败时是否弹出错误提示\r\n createliveactivity?: boolean, // 是否创建直播活动\r\n}\r\n\r\n</script>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, toRef, ref } from 'vue'\r\nimport { useFormInject } from '@/composables/useFieldGroup'\r\nimport { tv } from '@/lib/tv'\r\n\r\nimport theme, { buttonColors, buttonVariants, buttonSizes } from './reborn-button.config'\r\n\r\nconst b = tv(theme)\r\n\r\ninterface UniEvent {\r\n bubbles: boolean;\r\n cancelable: boolean;\r\n type: string;\r\n target: any;\r\n currentTarget: any;\r\n timeStamp: number;\r\n [key: string]: any;\r\n}\r\nconst props = withDefaults(defineProps<ButtonProps>(), {\r\n color: 'primary',\r\n variant: 'solid',\r\n size: 'md',\r\n loading: false,\r\n disabled: false,\r\n square: false,\r\n hoverStartTime: 20,\r\n hoverStayTime: 70,\r\n})\r\n\r\n// 事件定义\r\nconst emit = defineEmits([\r\n \"click\",\r\n \"tap\",\r\n \"getuserinfo\",\r\n \"contact\",\r\n \"getphonenumber\",\r\n \"error\",\r\n \"opensetting\",\r\n \"launchapp\",\r\n \"chooseavatar\",\r\n \"chooseaddress\",\r\n \"chooseinvoicetitle\",\r\n \"addgroupapp\",\r\n \"subscribe\",\r\n \"login\",\r\n \"getrealtimephonenumber\",\r\n \"agreeprivacyauthorization\"\r\n]);\r\n\r\n\r\nconst slots = defineSlots<{\r\n leading(props: { ui: any }): any\r\n default(props: { ui: any }): any\r\n trailing(props: { ui: any }): any\r\n}>()\r\n\r\nconst { orientation, size: fieldGroupSize, disabled: fieldGroupDisabled } = useFormInject(props)\r\n\r\nconst isDisabled = computed(() => fieldGroupDisabled.value || props.disabled || props.loading)\r\n\r\nconst color = toRef(props, 'color')\r\nconst variant = toRef(props, 'variant')\r\nconst size = toRef(props, 'size')\r\nconst square = toRef(props, 'square')\r\n\r\nconst tvSlots = computed(() => b({\r\n color: color.value,\r\n variant: variant.value,\r\n size: (fieldGroupSize.value || size.value) as any,\r\n square: square.value,\r\n fieldGroup: orientation.value\r\n}))\r\n\r\nconst ui = computed(() => {\r\n const slots = tvSlots.value as any\r\n const result: any = {}\r\n\r\n for (const key in slots) {\r\n result[key] = (opts?: any) => {\r\n const uiClass = props.ui?.[key]\r\n const optsClass = opts?.class\r\n return slots[key]({ class: [optsClass, uiClass] })\r\n }\r\n }\r\n\r\n return result\r\n})\r\n\r\n// 点击事件处理\r\nfunction onTap(e: UniEvent) {\r\n if (isDisabled.value) return;\r\n\r\n emit(\"click\", e);\r\n emit(\"tap\", e);\r\n}\r\n\r\n// 点击态状态\r\nconst isHover = ref(false);\r\n\r\nconst onGetUserInfo = (e: any) => emit('getuserinfo', e)\r\nconst onContact = (e: any) => emit('contact', e)\r\nconst onGetPhoneNumber = (e: any) => emit('getphonenumber', e)\r\nconst onError = (e: any) => emit('error', e)\r\nconst onOpenSetting = (e: any) => emit('opensetting', e)\r\nconst onLaunchApp = (e: any) => emit('launchapp', e)\r\nconst onChooseAvatar = (e: any) => emit('chooseavatar', e)\r\nconst onChooseAddress = (e: any) => emit('chooseaddress', e)\r\nconst onChooseInvoiceTitle = (e: any) => emit('chooseinvoicetitle', e)\r\nconst onAddGroupApp = (e: any) => emit('addgroupapp', e)\r\nconst onSubscribe = (e: any) => emit('subscribe', e)\r\nconst onLogin = (e: any) => emit('login', e)\r\nconst onGetRealtimePhoneNumber = (e: any) => emit('getrealtimephonenumber', e)\r\nconst onAgreePrivacyAuthorization = (e: any) => emit('agreeprivacyauthorization', e)\r\n\r\n// 触摸开始事件处理\r\nfunction onTouchStart() {\r\n if (!isDisabled.value) {\r\n isHover.value = true;\r\n }\r\n}\r\n\r\n// 触摸结束事件处理\r\nfunction onTouchEnd() {\r\n isHover.value = false;\r\n}\r\n\r\n// 触摸取消事件处理\r\nfunction onTouchCancel() {\r\n isHover.value = false;\r\n}\r\n</script>\r\n\r\n<template>\r\n <button :disabled=\"isDisabled\" :class=\"ui.base({ class: props.customClass })\" :hover-class=\"hoverClass\"\r\n :hover-stop-propagation=\"hoverStopPropagation\" :hover-start-time=\"hoverStartTime\"\r\n :hover-stay-time=\"hoverStayTime\" :form-type=\"formType\" :open-type=\"openType\" :session-from=\"sessionFrom\"\r\n :send-message-title=\"sendMessageTitle\" :send-message-path=\"sendMessagePath\" :send-message-img=\"sendMessageImg\"\r\n :show-message-card=\"showMessageCard\" :app-parameter=\"appParameter\" :group-id=\"groupId\" :guild-id=\"guildId\"\r\n :public-id=\"publicId\" :phone-number-no-quota-toast=\"phoneNumberNoQuotaToast\"\r\n :createliveactivity=\"createliveactivity\" @tap.stop=\"onTap\" @getuserinfo=\"onGetUserInfo\" @contact=\"onContact\"\r\n @getphonenumber=\"onGetPhoneNumber\" @error=\"onError\" @opensetting=\"onOpenSetting\" @launchapp=\"onLaunchApp\"\r\n @chooseavatar=\"onChooseAvatar\" @chooseaddress=\"onChooseAddress\" @chooseinvoicetitle=\"onChooseInvoiceTitle\"\r\n @addgroupapp=\"onAddGroupApp\" @subscribe=\"onSubscribe\" @login=\"onLogin\"\r\n @getrealtimephonenumber=\"onGetRealtimePhoneNumber\" @agreeprivacyauthorization=\"onAgreePrivacyAuthorization\"\r\n @touchstart=\"onTouchStart\" @touchend=\"onTouchEnd\" @touchcancel=\"onTouchCancel\">\r\n <slot name=\"leading\" :ui=\"ui\">\r\n <!-- <Icon name=\"svg-spinners:270-ring\" v-if=\"props.loading\" :class=\"ui.leadingIcon()\" /> -->\r\n <view v-if=\"props.loading\" :class=\"['i-svg-spinners-270-ring w-4 h-4', ui.leadingIcon()]\" />\r\n </slot>\r\n\r\n <slot :ui=\"ui\">\r\n <text v-if=\"label\" :class=\"ui.label()\">\r\n {{ label }}\r\n </text>\r\n <slot v-else :ui=\"ui\" :class=\"ui.label()\" />\r\n </slot>\r\n\r\n\r\n <slot name=\"trailing\" :ui=\"ui\" />\r\n </button>\r\n</template>\r\n",
32
+ "content": "<script setup lang=\"ts\">\r\nimport type { buttonColors, buttonSizes, buttonVariants } from './reborn-button.config'\r\nimport { computed, ref, toRef } from 'vue'\r\nimport { useFormInject } from '@/composables/useFieldGroup'\r\nimport { tv } from '@/lib/tv'\r\nimport { cn } from '@/lib/utils'\r\nimport theme from './reborn-button.config'\r\n\r\nexport interface ButtonProps {\r\n label?: string\r\n color?: typeof buttonColors[number]\r\n variant?: typeof buttonVariants[number]\r\n size?: typeof buttonSizes[number]\r\n loading?: boolean\r\n disabled?: boolean\r\n fluid?: boolean // 是否为 flex-1 布局\r\n gap?: boolean // 是否间隔按钮\r\n block?: boolean // 是否块级元素\r\n customClass?: any\r\n ui?: any\r\n hoverClass?: string // 按钮点击态样式类\r\n hoverStopPropagation?: boolean // 是否阻止点击态冒泡\r\n hoverStartTime?: number // 按钮点击态持续时间\r\n hoverStayTime?: number // 按钮点击态持续时间\r\n formType?: string // 表单提交类型\r\n openType?: string // 开放能力类型\r\n lang?: string // 语言\r\n sessionFrom?: string // 会话来源\r\n sendMessageTitle?: string // 会话标题\r\n sendMessagePath?: string // 会话路径\r\n sendMessageImg?: string // 会话图片\r\n showMessageCard?: boolean // 显示会话卡片\r\n appParameter?: string // 打开 APP 时,向 APP 传递的参数\r\n groupId?: string // 群ID\r\n guildId?: string // 公会ID\r\n publicId?: string // 公众号ID\r\n phoneNumberNoQuotaToast?: boolean // 手机号获取失败时是否弹出错误提示\r\n createliveactivity?: boolean // 是否创建直播活动\r\n}\r\n\r\nconst props = withDefaults(defineProps<ButtonProps>(), {\r\n color: 'primary',\r\n variant: 'solid',\r\n size: 'md',\r\n loading: false,\r\n disabled: false,\r\n fluid: false,\r\n gap: false,\r\n hoverStartTime: 20,\r\n hoverStayTime: 70,\r\n block: false\r\n})\r\n\r\n// 事件定义\r\nconst emit = defineEmits([\r\n 'click',\r\n 'tap',\r\n 'getuserinfo',\r\n 'contact',\r\n 'getphonenumber',\r\n 'error',\r\n 'opensetting',\r\n 'launchapp',\r\n 'chooseavatar',\r\n 'chooseaddress',\r\n 'chooseinvoicetitle',\r\n 'addgroupapp',\r\n 'subscribe',\r\n 'login',\r\n 'getrealtimephonenumber',\r\n 'agreeprivacyauthorization',\r\n])\r\n\r\nconst slots = defineSlots<{\r\n leading: (props: { ui: any, loading: boolean }) => any\r\n default: (props: { ui: any }) => any\r\n trailing: (props: { ui: any }) => any\r\n}>()\r\n\r\nconst b = tv(theme)\r\n\r\ninterface UniEvent {\r\n bubbles: boolean\r\n cancelable: boolean\r\n type: string\r\n target: any\r\n currentTarget: any\r\n timeStamp: number\r\n [key: string]: any\r\n}\r\nconst { size: fieldGroupSize, disabled: fieldGroupDisabled } = useFormInject(props)\r\n\r\nconst isDisabled = computed(() => fieldGroupDisabled.value || props.loading)\r\n\r\nconst color = toRef(props, 'color')\r\nconst variant = toRef(props, 'variant')\r\nconst size = toRef(props, 'size')\r\n\r\nconst uiOverrides = computed(() => props.ui || {})\r\n\r\nconst ui = computed(() => {\r\n const styles = b({\r\n color: color.value,\r\n variant: variant.value,\r\n size: (fieldGroupSize.value || size.value) as any,\r\n disabled: isDisabled.value,\r\n gap: props.gap,\r\n })\r\n\r\n return {\r\n base: (opts?: { class?: any }) => styles.base({ class: cn(opts?.class, uiOverrides.value.base) }),\r\n inner: (opts?: { class?: any }) => styles.inner({ class: cn(opts?.class, uiOverrides.value.inner) }),\r\n label: (opts?: { class?: any }) => styles.label({ class: cn(opts?.class, uiOverrides.value.label) }),\r\n loading: (opts?: { class?: any }) => styles.loading({ class: cn(opts?.class, uiOverrides.value.loading) }),\r\n }\r\n})\r\n\r\n// 点击事件处理\r\nfunction onTap(e: UniEvent) {\r\n if (isDisabled.value) { return }\r\n\r\n emit('click', e)\r\n emit('tap', e)\r\n}\r\n\r\n// 点击态状态\r\nconst isHover = ref(false)\r\n\r\nconst onGetUserInfo = (e: any) => emit('getuserinfo', e)\r\nconst onContact = (e: any) => emit('contact', e)\r\nconst onGetPhoneNumber = (e: any) => emit('getphonenumber', e)\r\nconst onError = (e: any) => emit('error', e)\r\nconst onOpenSetting = (e: any) => emit('opensetting', e)\r\nconst onLaunchApp = (e: any) => emit('launchapp', e)\r\nconst onChooseAvatar = (e: any) => emit('chooseavatar', e)\r\nconst onChooseAddress = (e: any) => emit('chooseaddress', e)\r\nconst onChooseInvoiceTitle = (e: any) => emit('chooseinvoicetitle', e)\r\nconst onAddGroupApp = (e: any) => emit('addgroupapp', e)\r\nconst onSubscribe = (e: any) => emit('subscribe', e)\r\nconst onLogin = (e: any) => emit('login', e)\r\nconst onGetRealtimePhoneNumber = (e: any) => emit('getrealtimephonenumber', e)\r\nconst onAgreePrivacyAuthorization = (e: any) => emit('agreeprivacyauthorization', e)\r\n\r\n// 触摸开始事件处理\r\nfunction onTouchStart() {\r\n if (!isDisabled.value) {\r\n isHover.value = true\r\n }\r\n}\r\n\r\n// 触摸结束事件处理\r\nfunction onTouchEnd() {\r\n isHover.value = false\r\n}\r\n\r\n// 触摸取消事件处理\r\nfunction onTouchCancel() {\r\n isHover.value = false\r\n}\r\n</script>\r\n\r\n<template>\r\n <view :class=\"[\r\n ui.base({ class: props.customClass }),\r\n isHover && hoverClass ? hoverClass : ''\r\n ]\" @tap=\"onTap\" @touchstart=\"onTouchStart\" @touchend=\"onTouchEnd\" @touchcancel=\"onTouchCancel\">\r\n <button :class=\"ui.inner()\" :disabled=\"isDisabled\" :hover-class=\"hoverClass\"\r\n :hover-stop-propagation=\"hoverStopPropagation\" :hover-start-time=\"hoverStartTime\" :hover-stay-time=\"hoverStayTime\"\r\n :form-type=\"formType\" :open-type=\"openType\" :lang=\"lang\" :session-from=\"sessionFrom\"\r\n :send-message-title=\"sendMessageTitle\" :send-message-path=\"sendMessagePath\" :send-message-img=\"sendMessageImg\"\r\n :show-message-card=\"showMessageCard\" :app-parameter=\"appParameter\" :group-id=\"groupId\" :guild-id=\"guildId\"\r\n :public-id=\"publicId\" :phone-number-no-quota-toast=\"phoneNumberNoQuotaToast\"\r\n :createliveactivity=\"createliveactivity\" @getuserinfo=\"onGetUserInfo\" @contact=\"onContact\"\r\n @getphonenumber=\"onGetPhoneNumber\" @error=\"onError\" @opensetting=\"onOpenSetting\" @launchapp=\"onLaunchApp\"\r\n @chooseavatar=\"onChooseAvatar\" @chooseaddress=\"onChooseAddress\" @chooseinvoicetitle=\"onChooseInvoiceTitle\"\r\n @addgroupapp=\"onAddGroupApp\" @subscribe=\"onSubscribe\" @login=\"onLogin\"\r\n @getrealtimephonenumber=\"onGetRealtimePhoneNumber\" @agreeprivacyauthorization=\"onAgreePrivacyAuthorization\" />\r\n\r\n <slot name=\"leading\" :loading=\"props.loading\" :ui=\"ui\">\r\n <view v-if=\"props.loading\" :class=\"ui.loading?.()\" />\r\n </slot>\r\n\r\n <slot :ui=\"ui\">\r\n <text v-if=\"label\" :class=\"ui.label()\">\r\n {{ label }}\r\n </text>\r\n <slot v-else :ui=\"ui\" :class=\"ui.label()\" />\r\n </slot>\r\n\r\n <slot name=\"trailing\" :ui=\"ui\" />\r\n </view>\r\n</template>\r\n\r\n<style scoped>\r\n.reborn-button-clicker {\r\n border: none;\r\n}\r\n\r\n.reborn-button-clicker::after {\r\n border: none;\r\n}\r\n</style>\r\n",
33
33
  "target": "uniapp"
34
34
  }
35
35
  ],
36
36
  "fileCount": 6,
37
- "contentHash": "fe31695ae9f7ebc20df10c3daa3e878a7a7b1548"
37
+ "contentHash": "21184526676c03c5a1c19965c0205ced62605ad0"
38
38
  }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "reborn-card",
3
+ "dependencies": [],
4
+ "files": [
5
+ {
6
+ "path": "index.ts",
7
+ "content": "export { default as RebornCard } from './RebornCard.vue'\r\n",
8
+ "target": "uniapp"
9
+ },
10
+ {
11
+ "path": "RebornCard.vue",
12
+ "content": "<script setup lang=\"ts\">\r\nwithDefaults(defineProps<{\r\n title?: string\r\n padding?: boolean\r\n customClass?: string\r\n overflowVisible?: boolean\r\n}>(), {\r\n padding: true,\r\n customClass: '',\r\n overflowVisible: false,\r\n})\r\n</script>\r\n\r\n<template>\r\n <view class=\"flex flex-col gap-3\">\r\n <slot name=\"title\">\r\n <view v-if=\"title\" class=\"\r\n text-sm font-medium uppercase tracking-wider text-slate-500\r\n dark:text-slate-200\r\n \">\r\n {{ title }}\r\n </view>\r\n </slot>\r\n <view class=\"\r\n rounded-xl border border-slate-200 bg-white shadow-sm\r\n dark:border-gray-700 dark:bg-gray-800 flex flex-col gap-3\r\n \" :class=\"[padding ? 'p-4' : '', customClass, overflowVisible ? '' : 'overflow-hidden']\">\r\n <slot />\r\n </view>\r\n </view>\r\n</template>\r\n",
13
+ "target": "uniapp"
14
+ }
15
+ ],
16
+ "fileCount": 2,
17
+ "contentHash": "2eb65d14d8308f17b82df89b14bd3843104b2c5d"
18
+ }