yanzhi-ui 0.1.3 → 0.1.5

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.
@@ -1,11 +1,12 @@
1
- interface ButtonProps {
2
- type?: 'default' | 'primary' | 'success' | 'warning' | 'error';
3
- size?: 'small' | 'medium' | 'large';
4
- color?: string;
5
- textColor?: string;
6
- disabled?: boolean;
1
+ export type ButtonType = 'default' | 'primary' | 'danger';
2
+ export type Size = 'small' | 'medium' | 'large';
3
+ type __VLS_Props = {
4
+ label: string;
5
+ type?: ButtonType;
6
+ size?: Size;
7
7
  loading?: boolean;
8
- }
8
+ disabled?: boolean;
9
+ };
9
10
  declare function __VLS_template(): {
10
11
  attrs: Partial<{}>;
11
12
  slots: {
@@ -15,7 +16,16 @@ declare function __VLS_template(): {
15
16
  rootEl: HTMLButtonElement;
16
17
  };
17
18
  type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
18
- declare const __VLS_component: import('vue').DefineComponent<ButtonProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<ButtonProps> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLButtonElement>;
19
+ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
20
+ click: (event: MouseEvent) => any;
21
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
22
+ onClick?: ((event: MouseEvent) => any) | undefined;
23
+ }>, {
24
+ type: ButtonType;
25
+ size: Size;
26
+ loading: boolean;
27
+ disabled: boolean;
28
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLButtonElement>;
19
29
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
20
30
  export default _default;
21
31
  type __VLS_WithTemplateSlots<T, S> = T & {
@@ -0,0 +1,37 @@
1
+ export declare class ImagePreview {
2
+ private container;
3
+ private img;
4
+ private prevBtn;
5
+ private nextBtn;
6
+ private closeBtn;
7
+ private zoomInBtn;
8
+ private zoomOutBtn;
9
+ private resetBtn;
10
+ private zoomLabel;
11
+ private indexLabel;
12
+ private images;
13
+ private currentIndex;
14
+ private scale;
15
+ private position;
16
+ private isDragging;
17
+ private dragStart;
18
+ private startPos;
19
+ private zoomTimeout;
20
+ constructor(images: string[], initialIndex?: number);
21
+ private createBtn;
22
+ private updateImage;
23
+ private updateIndex;
24
+ private showZoomLabel;
25
+ private startDrag;
26
+ private onDrag;
27
+ private endDrag;
28
+ private handleWheel;
29
+ private zoomIn;
30
+ private zoomOut;
31
+ private reset;
32
+ private prev;
33
+ private next;
34
+ close(): void;
35
+ private handleKeydown;
36
+ open(index?: number): void;
37
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { App } from 'vue';
2
2
  import { default as IButton } from './button/Button.vue';
3
- export { IButton };
3
+ import { default as ISelect } from './select/Select.vue';
4
+ import { ImagePreview } from './image-preview/ImagePreview';
5
+ export { IButton, ISelect, ImagePreview };
4
6
  declare const _default: {
5
7
  install: (app: App) => void;
6
8
  };
@@ -0,0 +1,15 @@
1
+ interface OptionItem {
2
+ label: string;
3
+ value: string | number;
4
+ }
5
+ type __VLS_Props = {
6
+ modelValue?: string | number;
7
+ options: OptionItem[];
8
+ disabled?: boolean;
9
+ };
10
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
11
+ "update:modelValue": (value: string | number) => any;
12
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
13
+ "onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
14
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLSelectElement>;
15
+ export default _default;
@@ -1 +1 @@
1
- .i-button[data-v-63e0e36c]{border-radius:4px;padding:0 12px;height:32px;border:none;cursor:pointer;transition:all .2s}.i-button.small[data-v-63e0e36c]{height:24px}.i-button.medium[data-v-63e0e36c]{height:32px}.i-button.large[data-v-63e0e36c]{height:40px}.i-button.disabled[data-v-63e0e36c]{cursor:not-allowed;opacity:.6}.i-button.loading[data-v-63e0e36c]{opacity:.8}
1
+ .i-button{display:inline-flex;align-items:center;gap:6px;cursor:pointer;-webkit-user-select:none;user-select:none;border:none;border-radius:.25rem}.i-button--default{background:#f5f5f5}.i-button--default:hover{background:#d1d1d1}.i-button--primary{background:#409eff;color:#fff}.i-button--primary:hover{background:#398adb;color:#fff}.i-button--danger{background:#f56c6c;color:#fff}.i-button--danger:hover{background:#e05a5a;color:#fff}.i-button--small{height:1.4rem;padding:0 .5rem;font-size:12px}.i-button--medium{height:24px;padding:0 .75rem;font-size:14px}.i-button--large{height:32px;padding:0 1rem;font-size:15px}.i-button.is-disabled{cursor:not-allowed;opacity:.6}
package/dist/yanzhi-ui.js CHANGED
@@ -1 +1,30 @@
1
- "use strict";var c=Object.defineProperty;var u=(e,o,s)=>o in e?c(e,o,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[o]=s;var l=(e,o,s)=>u(e,typeof o!="symbol"?o+"":o,s);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const i=require("vue"),b=["disabled"],h=i.defineComponent({__name:"Button",props:{type:{},size:{},color:{},textColor:{},disabled:{type:Boolean},loading:{type:Boolean}},setup(e){class o{constructor(t){l(this,"type");l(this,"size");l(this,"color");l(this,"textColor");l(this,"disabled");l(this,"loading");this.type=t.type||"default",this.size=t.size||"medium",this.color=t.color,this.textColor=t.textColor,this.disabled=t.disabled??!1,this.loading=t.loading??!1}get classes(){const t=["i-button",this.type,this.size];return this.disabled&&t.push("disabled"),this.loading&&t.push("loading"),t.join(" ")}get styles(){return{backgroundColor:this.color||"",color:this.textColor||""}}}const s=e,n=i.reactive(new o(s));return(a,t)=>(i.openBlock(),i.createElementBlock("button",{class:i.normalizeClass(n.classes),style:i.normalizeStyle(n.styles),disabled:n.disabled,onClick:t[0]||(t[0]=r=>a.$emit("click",r))},[i.renderSlot(a.$slots,"default",{},void 0,!0)],14,b))}}),y=(e,o)=>{const s=e.__vccOpts||e;for(const[n,a]of o)s[n]=a;return s},d=y(h,[["__scopeId","data-v-63e0e36c"]]),f=e=>{e.component("IButton",d)},g={install:f};exports.IButton=d;exports.default=g;
1
+ "use strict";var m=Object.defineProperty;var u=(n,t,e)=>t in n?m(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var s=(n,t,e)=>u(n,typeof t!="symbol"?t+"":t,e);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const i=require("vue"),p=["disabled"],g={class:"i-button__label"},h=i.defineComponent({name:"IButton",__name:"Button",props:{label:{},type:{default:"default"},size:{default:"medium"},loading:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1}},emits:["click"],setup(n,{emit:t}){const e=n,a=t,o=i.computed(()=>e.disabled||e.loading);function l(r){o.value||a("click",r)}const d=i.computed(()=>["i-button",`i-button--${e.type}`,`i-button--${e.size}`,o.value&&"is-disabled",e.loading&&"is-loading"]);return(r,z)=>(i.openBlock(),i.createElementBlock("button",i.mergeProps({type:"button",disabled:o.value,class:d.value,onClick:l},r.$attrs),[i.createElementVNode("span",g,[i.renderSlot(r.$slots,"default")])],16,p))}}),b=["value","disabled"],x=["value"],f=i.defineComponent({__name:"Select",props:{modelValue:{},options:{},disabled:{type:Boolean}},emits:["update:modelValue"],setup(n,{emit:t}){const e=n,a=t;function o(l){const d=l.target;a("update:modelValue",d.value)}return(l,d)=>(i.openBlock(),i.createElementBlock("select",{value:n.modelValue,onChange:o,disabled:e.disabled},[(i.openBlock(!0),i.createElementBlock(i.Fragment,null,i.renderList(n.options,r=>(i.openBlock(),i.createElementBlock("option",{key:r.value,value:r.value},i.toDisplayString(r.label),9,x))),128))],40,b))}}),y=(n,t)=>{const e=n.__vccOpts||n;for(const[a,o]of t)e[a]=o;return e},c=y(f,[["__scopeId","data-v-1c19bb1f"]]);class v{constructor(t,e=0){s(this,"container");s(this,"img");s(this,"prevBtn");s(this,"nextBtn");s(this,"closeBtn");s(this,"zoomInBtn");s(this,"zoomOutBtn");s(this,"resetBtn");s(this,"zoomLabel");s(this,"indexLabel");s(this,"images");s(this,"currentIndex",0);s(this,"scale",1);s(this,"position",{x:0,y:0});s(this,"isDragging",!1);s(this,"dragStart",{x:0,y:0});s(this,"startPos",{x:0,y:0});s(this,"zoomTimeout",null);this.images=t,this.currentIndex=e,this.container=document.createElement("div"),this.container.className="ip-overlay",this.container.style.cssText=`
2
+ position: fixed;
3
+ inset: 0;
4
+ background: rgba(0,0,0,0.8);
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: center;
8
+ z-index: 9999;
9
+ `,this.container.addEventListener("click",a=>{a.target===this.container&&this.close()}),this.img=document.createElement("img"),this.img.className="ip-image",this.img.draggable=!1,this.img.style.maxWidth="100%",this.img.style.maxHeight="100%",this.img.style.userSelect="none",this.img.style.pointerEvents="none",this.updateImage(),this.img.addEventListener("mousedown",this.startDrag.bind(this)),document.addEventListener("mousemove",this.onDrag.bind(this)),document.addEventListener("mouseup",this.endDrag.bind(this)),this.img.addEventListener("wheel",this.handleWheel.bind(this)),this.prevBtn=this.createBtn("‹",{left:"16px",top:"50%",transform:"translateY(-50%)"},()=>this.prev()),this.nextBtn=this.createBtn("›",{right:"16px",top:"50%",transform:"translateY(-50%)"},()=>this.next()),this.closeBtn=this.createBtn("×",{right:"16px",top:"16px"},()=>this.close()),this.zoomInBtn=this.createBtn("+",{bottom:"20px",left:"50%",marginLeft:"40px"},()=>this.zoomIn()),this.zoomOutBtn=this.createBtn("-",{bottom:"20px",left:"50%",marginRight:"40px"},()=>this.zoomOut()),this.resetBtn=this.createBtn("0",{bottom:"20px",left:"50%"},()=>this.reset()),this.zoomLabel=document.createElement("div"),this.zoomLabel.style.cssText=`
10
+ position: absolute;
11
+ top: 16px;
12
+ left: 50%;
13
+ transform: translateX(-50%);
14
+ color: #fff;
15
+ background: rgba(0,0,0,0.6);
16
+ padding: 4px 8px;
17
+ border-radius: 4px;
18
+ font-size: 14px;
19
+ display: none;
20
+ `,this.indexLabel=document.createElement("div"),this.indexLabel.style.cssText=`
21
+ position: absolute;
22
+ bottom: 8px;
23
+ left: 50%;
24
+ transform: translateX(-50%);
25
+ color: #fff;
26
+ background: rgba(0,0,0,0.6);
27
+ padding: 2px 6px;
28
+ border-radius: 4px;
29
+ font-size: 14px;
30
+ `,this.container.appendChild(this.img),this.container.appendChild(this.prevBtn),this.container.appendChild(this.nextBtn),this.container.appendChild(this.closeBtn),this.container.appendChild(this.zoomInBtn),this.container.appendChild(this.zoomOutBtn),this.container.appendChild(this.resetBtn),this.container.appendChild(this.zoomLabel),this.container.appendChild(this.indexLabel),document.body.appendChild(this.container),document.addEventListener("keydown",this.handleKeydown.bind(this)),this.updateIndex()}createBtn(t,e,a){const o=document.createElement("button");return o.textContent=t,Object.assign(o.style,{position:"absolute",width:"36px",height:"36px",border:"none",borderRadius:"50%",background:"rgba(0,0,0,0.6)",color:"#fff",cursor:"pointer",fontSize:"18px",...e}),o.addEventListener("click",a),o.addEventListener("mouseover",()=>o.style.background="rgba(0,0,0,0.8)"),o.addEventListener("mouseout",()=>o.style.background="rgba(0,0,0,0.6)"),o}updateImage(){this.img.src=this.images[this.currentIndex],this.img.style.transform=`scale(${this.scale}) translate(${this.position.x}px, ${this.position.y}px)`}updateIndex(){this.indexLabel.textContent=`${this.currentIndex+1} / ${this.images.length}`}showZoomLabel(){this.zoomLabel.textContent=`${Math.round(this.scale*100)}%`,this.zoomLabel.style.display="block",this.zoomTimeout&&clearTimeout(this.zoomTimeout),this.zoomTimeout=window.setTimeout(()=>{this.zoomLabel.style.display="none"},800)}startDrag(t){this.isDragging=!0,this.dragStart={x:t.clientX,y:t.clientY},this.startPos={...this.position}}onDrag(t){if(!this.isDragging)return;const e=(t.clientX-this.dragStart.x)/this.scale,a=(t.clientY-this.dragStart.y)/this.scale;this.position.x=this.startPos.x+e,this.position.y=this.startPos.y+a,this.updateImage()}endDrag(){this.isDragging=!1}handleWheel(t){t.deltaY<0?this.zoomIn():this.zoomOut()}zoomIn(){this.scale=Math.min(this.scale+.1,3),this.updateImage(),this.showZoomLabel()}zoomOut(){this.scale=Math.max(this.scale-.1,.2),this.updateImage(),this.showZoomLabel()}reset(){this.scale=1,this.position={x:0,y:0},this.updateImage(),this.showZoomLabel()}prev(){this.currentIndex>0&&(this.currentIndex--,this.reset(),this.updateImage(),this.updateIndex())}next(){this.currentIndex<this.images.length-1&&(this.currentIndex++,this.reset(),this.updateImage(),this.updateIndex())}close(){this.container.style.display="none",document.removeEventListener("keydown",this.handleKeydown.bind(this))}handleKeydown(t){switch(t.key){case"Escape":this.close();break;case"ArrowLeft":this.prev();break;case"ArrowRight":this.next();break;case"+":case"=":this.zoomIn();break;case"-":this.zoomOut();break;case"0":this.reset();break}}open(t=0){this.currentIndex=t,this.reset(),this.updateImage(),this.updateIndex(),this.container.style.display="flex"}}const B=[h,c],I=n=>{B.forEach(t=>{n.component(t.name,t)})},k={install:I};exports.IButton=h;exports.ISelect=c;exports.ImagePreview=v;exports.default=k;
@@ -1,58 +1,220 @@
1
- var d = Object.defineProperty;
2
- var c = (e, o, s) => o in e ? d(e, o, { enumerable: !0, configurable: !0, writable: !0, value: s }) : e[o] = s;
3
- var l = (e, o, s) => c(e, typeof o != "symbol" ? o + "" : o, s);
4
- import { defineComponent as r, reactive as u, createElementBlock as h, openBlock as b, normalizeStyle as f, normalizeClass as m, renderSlot as p } from "vue";
5
- const y = ["disabled"], g = /* @__PURE__ */ r({
1
+ var u = Object.defineProperty;
2
+ var p = (i, t, e) => t in i ? u(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
3
+ var s = (i, t, e) => p(i, typeof t != "symbol" ? t + "" : t, e);
4
+ import { defineComponent as m, computed as c, createElementBlock as d, openBlock as h, mergeProps as g, createElementVNode as b, renderSlot as x, Fragment as f, renderList as y, toDisplayString as v } from "vue";
5
+ const I = ["disabled"], B = { class: "i-button__label" }, z = /* @__PURE__ */ m({
6
+ name: "IButton",
6
7
  __name: "Button",
7
8
  props: {
8
- type: {},
9
- size: {},
10
- color: {},
11
- textColor: {},
12
- disabled: { type: Boolean },
13
- loading: { type: Boolean }
9
+ label: {},
10
+ type: { default: "default" },
11
+ size: { default: "medium" },
12
+ loading: { type: Boolean, default: !1 },
13
+ disabled: { type: Boolean, default: !1 }
14
14
  },
15
- setup(e) {
16
- class o {
17
- constructor(t) {
18
- l(this, "type");
19
- l(this, "size");
20
- l(this, "color");
21
- l(this, "textColor");
22
- l(this, "disabled");
23
- l(this, "loading");
24
- this.type = t.type || "default", this.size = t.size || "medium", this.color = t.color, this.textColor = t.textColor, this.disabled = t.disabled ?? !1, this.loading = t.loading ?? !1;
25
- }
26
- get classes() {
27
- const t = ["i-button", this.type, this.size];
28
- return this.disabled && t.push("disabled"), this.loading && t.push("loading"), t.join(" ");
29
- }
30
- get styles() {
31
- return {
32
- backgroundColor: this.color || "",
33
- color: this.textColor || ""
34
- };
35
- }
15
+ emits: ["click"],
16
+ setup(i, { emit: t }) {
17
+ const e = i, a = t, n = c(
18
+ () => e.disabled || e.loading
19
+ );
20
+ function r(o) {
21
+ n.value || a("click", o);
36
22
  }
37
- const s = e, i = u(new o(s));
38
- return (n, t) => (b(), h("button", {
39
- class: m(i.classes),
40
- style: f(i.styles),
41
- disabled: i.disabled,
42
- onClick: t[0] || (t[0] = (a) => n.$emit("click", a))
23
+ const l = c(() => [
24
+ "i-button",
25
+ `i-button--${e.type}`,
26
+ `i-button--${e.size}`,
27
+ n.value && "is-disabled",
28
+ e.loading && "is-loading"
29
+ ]);
30
+ return (o, D) => (h(), d("button", g({
31
+ type: "button",
32
+ disabled: n.value,
33
+ class: l.value,
34
+ onClick: r
35
+ }, o.$attrs), [
36
+ b("span", B, [
37
+ x(o.$slots, "default")
38
+ ])
39
+ ], 16, I));
40
+ }
41
+ }), L = ["value", "disabled"], k = ["value"], _ = /* @__PURE__ */ m({
42
+ __name: "Select",
43
+ props: {
44
+ modelValue: {},
45
+ options: {},
46
+ disabled: { type: Boolean }
47
+ },
48
+ emits: ["update:modelValue"],
49
+ setup(i, { emit: t }) {
50
+ const e = i, a = t;
51
+ function n(r) {
52
+ const l = r.target;
53
+ a("update:modelValue", l.value);
54
+ }
55
+ return (r, l) => (h(), d("select", {
56
+ value: i.modelValue,
57
+ onChange: n,
58
+ disabled: e.disabled
43
59
  }, [
44
- p(n.$slots, "default", {}, void 0, !0)
45
- ], 14, y));
46
- }
47
- }), _ = (e, o) => {
48
- const s = e.__vccOpts || e;
49
- for (const [i, n] of o)
50
- s[i] = n;
51
- return s;
52
- }, C = /* @__PURE__ */ _(g, [["__scopeId", "data-v-63e0e36c"]]), B = (e) => {
53
- e.component("IButton", C);
54
- }, k = { install: B };
60
+ (h(!0), d(f, null, y(i.options, (o) => (h(), d("option", {
61
+ key: o.value,
62
+ value: o.value
63
+ }, v(o.label), 9, k))), 128))
64
+ ], 40, L));
65
+ }
66
+ }), E = (i, t) => {
67
+ const e = i.__vccOpts || i;
68
+ for (const [a, n] of t)
69
+ e[a] = n;
70
+ return e;
71
+ }, w = /* @__PURE__ */ E(_, [["__scopeId", "data-v-1c19bb1f"]]);
72
+ class T {
73
+ constructor(t, e = 0) {
74
+ s(this, "container");
75
+ s(this, "img");
76
+ s(this, "prevBtn");
77
+ s(this, "nextBtn");
78
+ s(this, "closeBtn");
79
+ s(this, "zoomInBtn");
80
+ s(this, "zoomOutBtn");
81
+ s(this, "resetBtn");
82
+ s(this, "zoomLabel");
83
+ s(this, "indexLabel");
84
+ s(this, "images");
85
+ s(this, "currentIndex", 0);
86
+ s(this, "scale", 1);
87
+ s(this, "position", { x: 0, y: 0 });
88
+ s(this, "isDragging", !1);
89
+ s(this, "dragStart", { x: 0, y: 0 });
90
+ s(this, "startPos", { x: 0, y: 0 });
91
+ s(this, "zoomTimeout", null);
92
+ this.images = t, this.currentIndex = e, this.container = document.createElement("div"), this.container.className = "ip-overlay", this.container.style.cssText = `
93
+ position: fixed;
94
+ inset: 0;
95
+ background: rgba(0,0,0,0.8);
96
+ display: flex;
97
+ align-items: center;
98
+ justify-content: center;
99
+ z-index: 9999;
100
+ `, this.container.addEventListener("click", (a) => {
101
+ a.target === this.container && this.close();
102
+ }), this.img = document.createElement("img"), this.img.className = "ip-image", this.img.draggable = !1, this.img.style.maxWidth = "100%", this.img.style.maxHeight = "100%", this.img.style.userSelect = "none", this.img.style.pointerEvents = "none", this.updateImage(), this.img.addEventListener("mousedown", this.startDrag.bind(this)), document.addEventListener("mousemove", this.onDrag.bind(this)), document.addEventListener("mouseup", this.endDrag.bind(this)), this.img.addEventListener("wheel", this.handleWheel.bind(this)), this.prevBtn = this.createBtn("‹", { left: "16px", top: "50%", transform: "translateY(-50%)" }, () => this.prev()), this.nextBtn = this.createBtn("›", { right: "16px", top: "50%", transform: "translateY(-50%)" }, () => this.next()), this.closeBtn = this.createBtn("×", { right: "16px", top: "16px" }, () => this.close()), this.zoomInBtn = this.createBtn("+", { bottom: "20px", left: "50%", marginLeft: "40px" }, () => this.zoomIn()), this.zoomOutBtn = this.createBtn("-", { bottom: "20px", left: "50%", marginRight: "40px" }, () => this.zoomOut()), this.resetBtn = this.createBtn("0", { bottom: "20px", left: "50%" }, () => this.reset()), this.zoomLabel = document.createElement("div"), this.zoomLabel.style.cssText = `
103
+ position: absolute;
104
+ top: 16px;
105
+ left: 50%;
106
+ transform: translateX(-50%);
107
+ color: #fff;
108
+ background: rgba(0,0,0,0.6);
109
+ padding: 4px 8px;
110
+ border-radius: 4px;
111
+ font-size: 14px;
112
+ display: none;
113
+ `, this.indexLabel = document.createElement("div"), this.indexLabel.style.cssText = `
114
+ position: absolute;
115
+ bottom: 8px;
116
+ left: 50%;
117
+ transform: translateX(-50%);
118
+ color: #fff;
119
+ background: rgba(0,0,0,0.6);
120
+ padding: 2px 6px;
121
+ border-radius: 4px;
122
+ font-size: 14px;
123
+ `, this.container.appendChild(this.img), this.container.appendChild(this.prevBtn), this.container.appendChild(this.nextBtn), this.container.appendChild(this.closeBtn), this.container.appendChild(this.zoomInBtn), this.container.appendChild(this.zoomOutBtn), this.container.appendChild(this.resetBtn), this.container.appendChild(this.zoomLabel), this.container.appendChild(this.indexLabel), document.body.appendChild(this.container), document.addEventListener("keydown", this.handleKeydown.bind(this)), this.updateIndex();
124
+ }
125
+ createBtn(t, e, a) {
126
+ const n = document.createElement("button");
127
+ return n.textContent = t, Object.assign(n.style, {
128
+ position: "absolute",
129
+ width: "36px",
130
+ height: "36px",
131
+ border: "none",
132
+ borderRadius: "50%",
133
+ background: "rgba(0,0,0,0.6)",
134
+ color: "#fff",
135
+ cursor: "pointer",
136
+ fontSize: "18px",
137
+ ...e
138
+ }), n.addEventListener("click", a), n.addEventListener("mouseover", () => n.style.background = "rgba(0,0,0,0.8)"), n.addEventListener("mouseout", () => n.style.background = "rgba(0,0,0,0.6)"), n;
139
+ }
140
+ updateImage() {
141
+ this.img.src = this.images[this.currentIndex], this.img.style.transform = `scale(${this.scale}) translate(${this.position.x}px, ${this.position.y}px)`;
142
+ }
143
+ updateIndex() {
144
+ this.indexLabel.textContent = `${this.currentIndex + 1} / ${this.images.length}`;
145
+ }
146
+ showZoomLabel() {
147
+ this.zoomLabel.textContent = `${Math.round(this.scale * 100)}%`, this.zoomLabel.style.display = "block", this.zoomTimeout && clearTimeout(this.zoomTimeout), this.zoomTimeout = window.setTimeout(() => {
148
+ this.zoomLabel.style.display = "none";
149
+ }, 800);
150
+ }
151
+ startDrag(t) {
152
+ this.isDragging = !0, this.dragStart = { x: t.clientX, y: t.clientY }, this.startPos = { ...this.position };
153
+ }
154
+ onDrag(t) {
155
+ if (!this.isDragging) return;
156
+ const e = (t.clientX - this.dragStart.x) / this.scale, a = (t.clientY - this.dragStart.y) / this.scale;
157
+ this.position.x = this.startPos.x + e, this.position.y = this.startPos.y + a, this.updateImage();
158
+ }
159
+ endDrag() {
160
+ this.isDragging = !1;
161
+ }
162
+ handleWheel(t) {
163
+ t.deltaY < 0 ? this.zoomIn() : this.zoomOut();
164
+ }
165
+ zoomIn() {
166
+ this.scale = Math.min(this.scale + 0.1, 3), this.updateImage(), this.showZoomLabel();
167
+ }
168
+ zoomOut() {
169
+ this.scale = Math.max(this.scale - 0.1, 0.2), this.updateImage(), this.showZoomLabel();
170
+ }
171
+ reset() {
172
+ this.scale = 1, this.position = { x: 0, y: 0 }, this.updateImage(), this.showZoomLabel();
173
+ }
174
+ prev() {
175
+ this.currentIndex > 0 && (this.currentIndex--, this.reset(), this.updateImage(), this.updateIndex());
176
+ }
177
+ next() {
178
+ this.currentIndex < this.images.length - 1 && (this.currentIndex++, this.reset(), this.updateImage(), this.updateIndex());
179
+ }
180
+ close() {
181
+ this.container.style.display = "none", document.removeEventListener("keydown", this.handleKeydown.bind(this));
182
+ }
183
+ handleKeydown(t) {
184
+ switch (t.key) {
185
+ case "Escape":
186
+ this.close();
187
+ break;
188
+ case "ArrowLeft":
189
+ this.prev();
190
+ break;
191
+ case "ArrowRight":
192
+ this.next();
193
+ break;
194
+ case "+":
195
+ case "=":
196
+ this.zoomIn();
197
+ break;
198
+ case "-":
199
+ this.zoomOut();
200
+ break;
201
+ case "0":
202
+ this.reset();
203
+ break;
204
+ }
205
+ }
206
+ open(t = 0) {
207
+ this.currentIndex = t, this.reset(), this.updateImage(), this.updateIndex(), this.container.style.display = "flex";
208
+ }
209
+ }
210
+ const C = [z, w], $ = (i) => {
211
+ C.forEach((t) => {
212
+ i.component(t.name, t);
213
+ });
214
+ }, P = { install: $ };
55
215
  export {
56
- C as IButton,
57
- k as default
216
+ z as IButton,
217
+ w as ISelect,
218
+ T as ImagePreview,
219
+ P as default
58
220
  };
@@ -1 +1,30 @@
1
- (function(e,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(e=typeof globalThis<"u"?globalThis:e||self,t(e.YanzhiUI={},e.Vue))})(this,(function(e,t){"use strict";var h=Object.defineProperty;var p=(e,t,n)=>t in e?h(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var s=(e,t,n)=>p(e,typeof t!="symbol"?t+"":t,n);const n=["disabled"],r=((i,c)=>{const a=i.__vccOpts||i;for(const[l,d]of c)a[l]=d;return a})(t.defineComponent({__name:"Button",props:{type:{},size:{},color:{},textColor:{},disabled:{type:Boolean},loading:{type:Boolean}},setup(i){class c{constructor(o){s(this,"type");s(this,"size");s(this,"color");s(this,"textColor");s(this,"disabled");s(this,"loading");this.type=o.type||"default",this.size=o.size||"medium",this.color=o.color,this.textColor=o.textColor,this.disabled=o.disabled??!1,this.loading=o.loading??!1}get classes(){const o=["i-button",this.type,this.size];return this.disabled&&o.push("disabled"),this.loading&&o.push("loading"),o.join(" ")}get styles(){return{backgroundColor:this.color||"",color:this.textColor||""}}}const a=i,l=t.reactive(new c(a));return(d,o)=>(t.openBlock(),t.createElementBlock("button",{class:t.normalizeClass(l.classes),style:t.normalizeStyle(l.styles),disabled:l.disabled,onClick:o[0]||(o[0]=f=>d.$emit("click",f))},[t.renderSlot(d.$slots,"default",{},void 0,!0)],14,n))}}),[["__scopeId","data-v-63e0e36c"]]),u={install:i=>{i.component("IButton",r)}};e.IButton=r,e.default=u,Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
1
+ (function(i,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(i=typeof globalThis<"u"?globalThis:i||self,t(i.YanzhiUI={},i.Vue))})(this,(function(i,t){"use strict";var B=Object.defineProperty;var I=(i,t,d)=>t in i?B(i,t,{enumerable:!0,configurable:!0,writable:!0,value:d}):i[t]=d;var s=(i,t,d)=>I(i,typeof t!="symbol"?t+"":t,d);const d=["disabled"],u={class:"i-button__label"},m=t.defineComponent({name:"IButton",__name:"Button",props:{label:{},type:{default:"default"},size:{default:"medium"},loading:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1}},emits:["click"],setup(a,{emit:e}){const n=a,r=e,o=t.computed(()=>n.disabled||n.loading);function h(l){o.value||r("click",l)}const c=t.computed(()=>["i-button",`i-button--${n.type}`,`i-button--${n.size}`,o.value&&"is-disabled",n.loading&&"is-loading"]);return(l,_)=>(t.openBlock(),t.createElementBlock("button",t.mergeProps({type:"button",disabled:o.value,class:c.value,onClick:h},l.$attrs),[t.createElementVNode("span",u,[t.renderSlot(l.$slots,"default")])],16,d))}}),g=["value","disabled"],b=["value"],p=((a,e)=>{const n=a.__vccOpts||a;for(const[r,o]of e)n[r]=o;return n})(t.defineComponent({__name:"Select",props:{modelValue:{},options:{},disabled:{type:Boolean}},emits:["update:modelValue"],setup(a,{emit:e}){const n=a,r=e;function o(h){const c=h.target;r("update:modelValue",c.value)}return(h,c)=>(t.openBlock(),t.createElementBlock("select",{value:a.modelValue,onChange:o,disabled:n.disabled},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(a.options,l=>(t.openBlock(),t.createElementBlock("option",{key:l.value,value:l.value},t.toDisplayString(l.label),9,b))),128))],40,g))}}),[["__scopeId","data-v-1c19bb1f"]]);class x{constructor(e,n=0){s(this,"container");s(this,"img");s(this,"prevBtn");s(this,"nextBtn");s(this,"closeBtn");s(this,"zoomInBtn");s(this,"zoomOutBtn");s(this,"resetBtn");s(this,"zoomLabel");s(this,"indexLabel");s(this,"images");s(this,"currentIndex",0);s(this,"scale",1);s(this,"position",{x:0,y:0});s(this,"isDragging",!1);s(this,"dragStart",{x:0,y:0});s(this,"startPos",{x:0,y:0});s(this,"zoomTimeout",null);this.images=e,this.currentIndex=n,this.container=document.createElement("div"),this.container.className="ip-overlay",this.container.style.cssText=`
2
+ position: fixed;
3
+ inset: 0;
4
+ background: rgba(0,0,0,0.8);
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: center;
8
+ z-index: 9999;
9
+ `,this.container.addEventListener("click",r=>{r.target===this.container&&this.close()}),this.img=document.createElement("img"),this.img.className="ip-image",this.img.draggable=!1,this.img.style.maxWidth="100%",this.img.style.maxHeight="100%",this.img.style.userSelect="none",this.img.style.pointerEvents="none",this.updateImage(),this.img.addEventListener("mousedown",this.startDrag.bind(this)),document.addEventListener("mousemove",this.onDrag.bind(this)),document.addEventListener("mouseup",this.endDrag.bind(this)),this.img.addEventListener("wheel",this.handleWheel.bind(this)),this.prevBtn=this.createBtn("‹",{left:"16px",top:"50%",transform:"translateY(-50%)"},()=>this.prev()),this.nextBtn=this.createBtn("›",{right:"16px",top:"50%",transform:"translateY(-50%)"},()=>this.next()),this.closeBtn=this.createBtn("×",{right:"16px",top:"16px"},()=>this.close()),this.zoomInBtn=this.createBtn("+",{bottom:"20px",left:"50%",marginLeft:"40px"},()=>this.zoomIn()),this.zoomOutBtn=this.createBtn("-",{bottom:"20px",left:"50%",marginRight:"40px"},()=>this.zoomOut()),this.resetBtn=this.createBtn("0",{bottom:"20px",left:"50%"},()=>this.reset()),this.zoomLabel=document.createElement("div"),this.zoomLabel.style.cssText=`
10
+ position: absolute;
11
+ top: 16px;
12
+ left: 50%;
13
+ transform: translateX(-50%);
14
+ color: #fff;
15
+ background: rgba(0,0,0,0.6);
16
+ padding: 4px 8px;
17
+ border-radius: 4px;
18
+ font-size: 14px;
19
+ display: none;
20
+ `,this.indexLabel=document.createElement("div"),this.indexLabel.style.cssText=`
21
+ position: absolute;
22
+ bottom: 8px;
23
+ left: 50%;
24
+ transform: translateX(-50%);
25
+ color: #fff;
26
+ background: rgba(0,0,0,0.6);
27
+ padding: 2px 6px;
28
+ border-radius: 4px;
29
+ font-size: 14px;
30
+ `,this.container.appendChild(this.img),this.container.appendChild(this.prevBtn),this.container.appendChild(this.nextBtn),this.container.appendChild(this.closeBtn),this.container.appendChild(this.zoomInBtn),this.container.appendChild(this.zoomOutBtn),this.container.appendChild(this.resetBtn),this.container.appendChild(this.zoomLabel),this.container.appendChild(this.indexLabel),document.body.appendChild(this.container),document.addEventListener("keydown",this.handleKeydown.bind(this)),this.updateIndex()}createBtn(e,n,r){const o=document.createElement("button");return o.textContent=e,Object.assign(o.style,{position:"absolute",width:"36px",height:"36px",border:"none",borderRadius:"50%",background:"rgba(0,0,0,0.6)",color:"#fff",cursor:"pointer",fontSize:"18px",...n}),o.addEventListener("click",r),o.addEventListener("mouseover",()=>o.style.background="rgba(0,0,0,0.8)"),o.addEventListener("mouseout",()=>o.style.background="rgba(0,0,0,0.6)"),o}updateImage(){this.img.src=this.images[this.currentIndex],this.img.style.transform=`scale(${this.scale}) translate(${this.position.x}px, ${this.position.y}px)`}updateIndex(){this.indexLabel.textContent=`${this.currentIndex+1} / ${this.images.length}`}showZoomLabel(){this.zoomLabel.textContent=`${Math.round(this.scale*100)}%`,this.zoomLabel.style.display="block",this.zoomTimeout&&clearTimeout(this.zoomTimeout),this.zoomTimeout=window.setTimeout(()=>{this.zoomLabel.style.display="none"},800)}startDrag(e){this.isDragging=!0,this.dragStart={x:e.clientX,y:e.clientY},this.startPos={...this.position}}onDrag(e){if(!this.isDragging)return;const n=(e.clientX-this.dragStart.x)/this.scale,r=(e.clientY-this.dragStart.y)/this.scale;this.position.x=this.startPos.x+n,this.position.y=this.startPos.y+r,this.updateImage()}endDrag(){this.isDragging=!1}handleWheel(e){e.deltaY<0?this.zoomIn():this.zoomOut()}zoomIn(){this.scale=Math.min(this.scale+.1,3),this.updateImage(),this.showZoomLabel()}zoomOut(){this.scale=Math.max(this.scale-.1,.2),this.updateImage(),this.showZoomLabel()}reset(){this.scale=1,this.position={x:0,y:0},this.updateImage(),this.showZoomLabel()}prev(){this.currentIndex>0&&(this.currentIndex--,this.reset(),this.updateImage(),this.updateIndex())}next(){this.currentIndex<this.images.length-1&&(this.currentIndex++,this.reset(),this.updateImage(),this.updateIndex())}close(){this.container.style.display="none",document.removeEventListener("keydown",this.handleKeydown.bind(this))}handleKeydown(e){switch(e.key){case"Escape":this.close();break;case"ArrowLeft":this.prev();break;case"ArrowRight":this.next();break;case"+":case"=":this.zoomIn();break;case"-":this.zoomOut();break;case"0":this.reset();break}}open(e=0){this.currentIndex=e,this.reset(),this.updateImage(),this.updateIndex(),this.container.style.display="flex"}}const f=[m,p],y={install:a=>{f.forEach(e=>{a.component(e.name,e)})}};i.IButton=m,i.ISelect=p,i.ImagePreview=x,i.default=y,Object.defineProperties(i,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "yanzhi-ui",
3
3
  "private": false,
4
- "version": "0.1.3",
4
+ "version": "0.1.5",
5
5
  "types": "dist/yanzhi-ui.d.ts",
6
6
  "main": "dist/yanzhi-ui.umd.js",
7
7
  "module": "dist/yanzhi-ui.mjs",
@@ -1,75 +1,133 @@
1
- <template>
2
- <button
3
- :class="button.classes"
4
- :style="button.styles"
5
- :disabled="button.disabled"
6
- @click="$emit('click', $event)"
7
- >
8
- <slot />
9
- </button>
10
- </template>
11
-
12
1
  <script setup lang="ts">
13
- import { reactive, computed, toRefs } from 'vue'
2
+ import { computed } from 'vue'
14
3
 
15
- interface ButtonProps {
16
- type?: 'default' | 'primary' | 'success' | 'warning' | 'error'
17
- size?: 'small' | 'medium' | 'large'
18
- color?: string
19
- textColor?: string
20
- disabled?: boolean
4
+ defineOptions({
5
+ name: 'IButton',
6
+ })
7
+
8
+ export type ButtonType =
9
+ | 'default'
10
+ | 'primary'
11
+ | 'danger'
12
+
13
+ export type Size = 'small' | 'medium' | 'large'
14
+
15
+ const props = withDefaults(defineProps<{
16
+ label: string
17
+ type?: ButtonType
18
+ size?: Size
21
19
  loading?: boolean
20
+ disabled?: boolean
21
+ }>(), {
22
+ type: 'default',
23
+ size: 'medium',
24
+ loading: false,
25
+ disabled: false,
26
+ })
27
+
28
+ const emit = defineEmits<{
29
+ (e: 'click', event: MouseEvent): void
30
+ }>()
31
+
32
+ const isDisabled = computed(() =>
33
+ props.disabled || props.loading
34
+ )
35
+
36
+ function handleClick(e: MouseEvent) {
37
+ if (isDisabled.value) return
38
+ emit('click', e)
22
39
  }
23
40
 
24
- class Button {
25
- type: ButtonProps['type']
26
- size: ButtonProps['size']
27
- color?: string
28
- textColor?: string
29
- disabled: boolean
30
- loading: boolean
41
+ const classes = computed(() => [
42
+ 'i-button',
43
+ `i-button--${props.type}`,
44
+ `i-button--${props.size}`,
45
+ isDisabled.value && 'is-disabled',
46
+ props.loading && 'is-loading',
47
+ ])
48
+ </script>
31
49
 
32
- constructor(props: ButtonProps) {
33
- this.type = props.type || 'default'
34
- this.size = props.size || 'medium'
35
- this.color = props.color
36
- this.textColor = props.textColor
37
- this.disabled = props.disabled ?? false
38
- this.loading = props.loading ?? false
39
- }
50
+ <template>
51
+ <button
52
+ type="button"
53
+ :disabled="isDisabled"
54
+ :class="classes"
55
+ @click="handleClick"
56
+ v-bind="$attrs"
57
+ >
58
+ <!-- 文本 -->
59
+ <span class="i-button__label">
60
+ <slot />
61
+ </span>
62
+ </button>
63
+ </template>
40
64
 
41
- get classes() {
42
- const cls = ['i-button', this.type, this.size]
43
- if (this.disabled) cls.push('disabled')
44
- if (this.loading) cls.push('loading')
45
- return cls.join(' ')
46
- }
65
+ <style>
66
+ /* ===============================
67
+ Base
68
+ =============================== */
69
+ .i-button {
70
+ display: inline-flex;
71
+ align-items: center;
72
+ gap: 6px;
73
+ cursor: pointer;
74
+ user-select: none;
75
+ border: none;
76
+ border-radius: 0.25rem;
77
+ }
47
78
 
48
- get styles() {
49
- return {
50
- backgroundColor: this.color || '',
51
- color: this.textColor || ''
52
- }
53
- }
79
+ /* ===============================
80
+ 类型
81
+ =============================== */
82
+ .i-button--default {
83
+ background: #f5f5f5;
84
+ }
85
+ .i-button--default:hover {
86
+ background: #d1d1d1;
54
87
  }
55
88
 
56
- const props = withDefaults(defineProps<ButtonProps>(), {})
89
+ .i-button--primary {
90
+ background: #409eff;
91
+ color: #fff;
92
+ }
93
+ .i-button--primary:hover {
94
+ background: #398adb;
95
+ color: #fff;
96
+ }
57
97
 
58
- const button = reactive(new Button(props))
59
- </script>
98
+ .i-button--danger {
99
+ background: #f56c6c;
100
+ color: #fff;
101
+ }
102
+ .i-button--danger:hover {
103
+ background: #e05a5a;
104
+ color: #fff;
105
+ }
60
106
 
61
- <style scoped>
62
- .i-button {
63
- border-radius: 4px;
64
- padding: 0 12px;
107
+ /* ===============================
108
+ 大小
109
+ =============================== */
110
+ .i-button--small {
111
+ height: 1.4rem;
112
+ padding: 0 0.5rem;
113
+ font-size: 12px;
114
+ }
115
+ .i-button--medium {
116
+ height: 24px;
117
+ padding: 0 0.75rem;
118
+ font-size: 14px;
119
+ }
120
+ .i-button--large {
65
121
  height: 32px;
66
- border: none;
67
- cursor: pointer;
68
- transition: all 0.2s;
122
+ padding: 0 1rem;
123
+ font-size: 15px;
124
+ }
125
+
126
+ /* ===============================
127
+ State
128
+ =============================== */
129
+ .i-button.is-disabled {
130
+ cursor: not-allowed;
131
+ opacity: 0.6;
69
132
  }
70
- .i-button.small { height: 24px; }
71
- .i-button.medium { height: 32px; }
72
- .i-button.large { height: 40px; }
73
- .i-button.disabled { cursor: not-allowed; opacity: 0.6; }
74
- .i-button.loading { opacity: 0.8; }
75
133
  </style>
@@ -0,0 +1,10 @@
1
+ import type { Component } from 'vue'
2
+
3
+ declare module 'vue' {
4
+ export interface GlobalComponents {
5
+ IButton: typeof Component,
6
+ IInput: typeof Component,
7
+ }
8
+ }
9
+
10
+ export {}
@@ -0,0 +1,200 @@
1
+ // ImagePreview.ts
2
+ export class ImagePreview {
3
+ private container: HTMLDivElement
4
+ private img: HTMLImageElement
5
+ private prevBtn: HTMLButtonElement
6
+ private nextBtn: HTMLButtonElement
7
+ private closeBtn: HTMLButtonElement
8
+ private zoomInBtn: HTMLButtonElement
9
+ private zoomOutBtn: HTMLButtonElement
10
+ private resetBtn: HTMLButtonElement
11
+ private zoomLabel: HTMLDivElement
12
+ private indexLabel: HTMLDivElement
13
+
14
+ private images: string[]
15
+ private currentIndex: number = 0
16
+ private scale: number = 1
17
+ private position = { x: 0, y: 0 }
18
+ private isDragging = false
19
+ private dragStart = { x: 0, y: 0 }
20
+ private startPos = { x: 0, y: 0 }
21
+ private zoomTimeout: number | null = null
22
+
23
+ constructor(images: string[], initialIndex = 0) {
24
+ this.images = images
25
+ this.currentIndex = initialIndex
26
+
27
+ this.container = document.createElement('div')
28
+ this.container.className = 'ip-overlay'
29
+ this.container.style.cssText = `
30
+ position: fixed;
31
+ inset: 0;
32
+ background: rgba(0,0,0,0.8);
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ z-index: 9999;
37
+ `
38
+ this.container.addEventListener('click', e => {
39
+ if (e.target === this.container) this.close()
40
+ })
41
+
42
+ this.img = document.createElement('img')
43
+ this.img.className = 'ip-image'
44
+ this.img.draggable = false
45
+ this.img.style.maxWidth = '100%'
46
+ this.img.style.maxHeight = '100%'
47
+ this.img.style.userSelect = 'none'
48
+ this.img.style.pointerEvents = 'none'
49
+ this.updateImage()
50
+
51
+ // 拖拽
52
+ this.img.addEventListener('mousedown', this.startDrag.bind(this))
53
+ document.addEventListener('mousemove', this.onDrag.bind(this))
54
+ document.addEventListener('mouseup', this.endDrag.bind(this))
55
+ // 缩放
56
+ this.img.addEventListener('wheel', this.handleWheel.bind(this))
57
+
58
+ // 按钮
59
+ this.prevBtn = this.createBtn('‹', { left: '16px', top: '50%', transform: 'translateY(-50%)' }, () => this.prev())
60
+ this.nextBtn = this.createBtn('›', { right: '16px', top: '50%', transform: 'translateY(-50%)' }, () => this.next())
61
+ this.closeBtn = this.createBtn('×', { right: '16px', top: '16px' }, () => this.close())
62
+ this.zoomInBtn = this.createBtn('+', { bottom: '20px', left: '50%', marginLeft: '40px' }, () => this.zoomIn())
63
+ this.zoomOutBtn = this.createBtn('-', { bottom: '20px', left: '50%', marginRight: '40px' }, () => this.zoomOut())
64
+ this.resetBtn = this.createBtn('0', { bottom: '20px', left: '50%' }, () => this.reset())
65
+
66
+ // 缩放百分比
67
+ this.zoomLabel = document.createElement('div')
68
+ this.zoomLabel.style.cssText = `
69
+ position: absolute;
70
+ top: 16px;
71
+ left: 50%;
72
+ transform: translateX(-50%);
73
+ color: #fff;
74
+ background: rgba(0,0,0,0.6);
75
+ padding: 4px 8px;
76
+ border-radius: 4px;
77
+ font-size: 14px;
78
+ display: none;
79
+ `
80
+
81
+ // 图片索引
82
+ this.indexLabel = document.createElement('div')
83
+ this.indexLabel.style.cssText = `
84
+ position: absolute;
85
+ bottom: 8px;
86
+ left: 50%;
87
+ transform: translateX(-50%);
88
+ color: #fff;
89
+ background: rgba(0,0,0,0.6);
90
+ padding: 2px 6px;
91
+ border-radius: 4px;
92
+ font-size: 14px;
93
+ `
94
+
95
+ this.container.appendChild(this.img)
96
+ this.container.appendChild(this.prevBtn)
97
+ this.container.appendChild(this.nextBtn)
98
+ this.container.appendChild(this.closeBtn)
99
+ this.container.appendChild(this.zoomInBtn)
100
+ this.container.appendChild(this.zoomOutBtn)
101
+ this.container.appendChild(this.resetBtn)
102
+ this.container.appendChild(this.zoomLabel)
103
+ this.container.appendChild(this.indexLabel)
104
+
105
+ document.body.appendChild(this.container)
106
+
107
+ // 键盘事件
108
+ document.addEventListener('keydown', this.handleKeydown.bind(this))
109
+
110
+ this.updateIndex()
111
+ }
112
+
113
+ private createBtn(text: string, style: Partial<CSSStyleDeclaration>, onClick: () => void) {
114
+ const btn = document.createElement('button')
115
+ btn.textContent = text
116
+ Object.assign(btn.style, {
117
+ position: 'absolute',
118
+ width: '36px',
119
+ height: '36px',
120
+ border: 'none',
121
+ borderRadius: '50%',
122
+ background: 'rgba(0,0,0,0.6)',
123
+ color: '#fff',
124
+ cursor: 'pointer',
125
+ fontSize: '18px',
126
+ ...style
127
+ })
128
+ btn.addEventListener('click', onClick)
129
+ btn.addEventListener('mouseover', () => btn.style.background = 'rgba(0,0,0,0.8)')
130
+ btn.addEventListener('mouseout', () => btn.style.background = 'rgba(0,0,0,0.6)')
131
+ return btn
132
+ }
133
+
134
+ private updateImage() {
135
+ this.img.src = this.images[this.currentIndex]
136
+ this.img.style.transform = `scale(${this.scale}) translate(${this.position.x}px, ${this.position.y}px)`
137
+ }
138
+
139
+ private updateIndex() {
140
+ this.indexLabel.textContent = `${this.currentIndex + 1} / ${this.images.length}`
141
+ }
142
+
143
+ private showZoomLabel() {
144
+ this.zoomLabel.textContent = `${Math.round(this.scale * 100)}%`
145
+ this.zoomLabel.style.display = 'block'
146
+ if (this.zoomTimeout) clearTimeout(this.zoomTimeout)
147
+ this.zoomTimeout = window.setTimeout(() => {
148
+ this.zoomLabel.style.display = 'none'
149
+ }, 800)
150
+ }
151
+
152
+ private startDrag(e: MouseEvent) {
153
+ this.isDragging = true
154
+ this.dragStart = { x: e.clientX, y: e.clientY }
155
+ this.startPos = { ...this.position }
156
+ }
157
+
158
+ private onDrag(e: MouseEvent) {
159
+ if (!this.isDragging) return
160
+ const dx = (e.clientX - this.dragStart.x) / this.scale
161
+ const dy = (e.clientY - this.dragStart.y) / this.scale
162
+ this.position.x = this.startPos.x + dx
163
+ this.position.y = this.startPos.y + dy
164
+ this.updateImage()
165
+ }
166
+
167
+ private endDrag() { this.isDragging = false }
168
+
169
+ private handleWheel(e: WheelEvent) {
170
+ if (e.deltaY < 0) this.zoomIn()
171
+ else this.zoomOut()
172
+ }
173
+
174
+ private zoomIn() { this.scale = Math.min(this.scale + 0.1, 3); this.updateImage(); this.showZoomLabel() }
175
+ private zoomOut() { this.scale = Math.max(this.scale - 0.1, 0.2); this.updateImage(); this.showZoomLabel() }
176
+ private reset() { this.scale = 1; this.position = { x: 0, y: 0 }; this.updateImage(); this.showZoomLabel() }
177
+
178
+ private prev() { if (this.currentIndex > 0) { this.currentIndex--; this.reset(); this.updateImage(); this.updateIndex() } }
179
+ private next() { if (this.currentIndex < this.images.length - 1) { this.currentIndex++; this.reset(); this.updateImage(); this.updateIndex() } }
180
+ public close() { this.container.style.display = 'none'; document.removeEventListener('keydown', this.handleKeydown.bind(this)) }
181
+
182
+ private handleKeydown(e: KeyboardEvent) {
183
+ switch(e.key) {
184
+ case 'Escape': this.close(); break
185
+ case 'ArrowLeft': this.prev(); break
186
+ case 'ArrowRight': this.next(); break
187
+ case '+': case '=': this.zoomIn(); break
188
+ case '-': this.zoomOut(); break
189
+ case '0': this.reset(); break
190
+ }
191
+ }
192
+
193
+ public open(index = 0) {
194
+ this.currentIndex = index
195
+ this.reset()
196
+ this.updateImage()
197
+ this.updateIndex()
198
+ this.container.style.display = 'flex'
199
+ }
200
+ }
@@ -1,10 +1,20 @@
1
1
  // packages/index.ts
2
2
  import type { App } from 'vue'
3
3
  import IButton from './button/Button.vue'
4
+ import ISelect from './select/Select.vue'
5
+ import { ImagePreview } from './image-preview/ImagePreview'
6
+
7
+ const components = [IButton, ISelect]
4
8
 
5
9
  const install = (app: App) => {
6
- app.component('IButton', IButton)
10
+ components.forEach(component => {
11
+ app.component(component.name!, component)
12
+ })
7
13
  }
8
14
 
9
- export { IButton }
10
- export default { install }
15
+ export {
16
+ IButton,
17
+ ISelect,
18
+ ImagePreview
19
+ }
20
+ export default { install }
@@ -0,0 +1,45 @@
1
+ <!-- ISelect.vue -->
2
+ <script setup lang="ts">
3
+
4
+ interface OptionItem {
5
+ label: string
6
+ value: string | number
7
+ }
8
+
9
+ const props = defineProps<{
10
+ modelValue?: string | number
11
+ options: OptionItem[]
12
+ disabled?: boolean
13
+ }>()
14
+
15
+ const emit = defineEmits<{
16
+ (e: 'update:modelValue', value: string | number): void
17
+ }>()
18
+
19
+ function handleChange(e: Event) {
20
+ const target = e.target as HTMLSelectElement
21
+ emit('update:modelValue', target.value)
22
+ }
23
+ </script>
24
+
25
+ <template>
26
+ <select :value="modelValue" @change="handleChange" :disabled="props.disabled">
27
+ <option v-for="opt in options" :key="opt.value" :value="opt.value">
28
+ {{ opt.label }}
29
+ </option>
30
+ </select>
31
+ </template>
32
+
33
+ <style scoped>
34
+ select {
35
+ /* padding: 4px 8px; */
36
+ /* border: 1px solid #ccc; */
37
+ /* border-radius: 4px; */
38
+ /* background: white; */
39
+ /* font-size: 14px; */
40
+ }
41
+ select:disabled {
42
+ /* background: #f5f5f5; */
43
+ /* cursor: not-allowed; */
44
+ }
45
+ </style>