@a-drowned-fish/rox-v 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @a-drowned-fish/rox-v
2
+
3
+ ## Usage
4
+
5
+ ### Install
6
+
7
+ ```bash
8
+ npm add @a-drowned-fish/rox-v
9
+ ```
10
+
11
+ ### Import all components
12
+
13
+ ```ts
14
+ import { createApp } from "vue";
15
+ import RoxV from "@a-drowned-fish/rox-v";
16
+ import "@a-drowned-fish/rox-v/dist/style.css";
17
+
18
+ const app = createApp(App);
19
+ app.use(RoxV);
20
+ ```
21
+
22
+ ### Tree-shakable import
23
+
24
+ ```ts
25
+ import { InputOtp } from "@a-drowned-fish/rox-v";
26
+ import "@a-drowned-fish/rox-v/es/input-otp/index.css";
27
+ ```
28
+
29
+ ### Auto Import
30
+
31
+ ```ts
32
+ // vite.config.ts
33
+ import { defineConfig } from "vite";
34
+ import vue from "@vitejs/plugin-vue";
35
+ import Components from "unplugin-vue-components/vite";
36
+ import { RoxVResolver } from "@a-drowned-fish/rox-v/resolver";
37
+
38
+ // https://vitejs.dev/config/
39
+ export default defineConfig({
40
+ plugins: [
41
+ vue(),
42
+ Components({
43
+ resolvers: [RoxVResolver()],
44
+ }),
45
+ ],
46
+ });
47
+ ```
48
+
49
+ ## License
50
+
51
+ MIT
@@ -0,0 +1 @@
1
+ var RoxV=function(c,e){"use strict";const f=["maxlength"],p=((o,r)=>{const l=o.__vccOpts||o;for(const[s,i]of r)l[s]=i;return l})(e.defineComponent({__name:"input-otp",props:{modelValue:{default:""},length:{default:6},itemClass:{default:""},activeItemClass:{default:""},gap:{default:"10px"}},emits:["update:modelValue","complete"],setup(o,{emit:r}){const l=o,s=r,i=e.ref(null),a=e.ref(l.modelValue);e.watch(()=>l.modelValue,n=>{n!==a.value&&(a.value=n)});function _(n){let t=n.target.value;t=t.replace(/\D/g,""),t=t.slice(0,l.length),a.value=t,s("update:modelValue",t),t.length===l.length&&s("complete",t)}function h(){var n;(n=i.value)==null||n.focus()}function m(n){return n===a.value.length}return(n,t)=>(e.openBlock(),e.createElementBlock("div",{class:"otp-wrapper",onClick:h},[e.withDirectives(e.createElementVNode("input",{inputmode:"numeric",autocomplete:"one-time-code",ref_key:"inputRef",ref:i,"onUpdate:modelValue":t[0]||(t[0]=d=>a.value=d),maxlength:o.length,onInput:_,class:"otp-input"},null,40,f),[[e.vModelText,a.value]]),e.createElementVNode("div",{class:"otp-box",style:e.normalizeStyle({gap:l.gap})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.length,(d,u)=>(e.openBlock(),e.createElementBlock("div",{key:u,class:e.normalizeClass(["otp-item",[{active:m(u),[l.activeItemClass]:m(u)},l.itemClass]])},e.toDisplayString(a.value[u]||""),3))),128))],4)]))}}),[["__scopeId","data-v-14ecb7bd"]]),g={version:"1.0.0",install:o=>{o.component("RInputOtp",p)}};return c.InputOtp=p,c.default=g,Object.defineProperties(c,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}}),c}({},Vue);
package/dist/index.js ADDED
@@ -0,0 +1,75 @@
1
+ import { defineComponent as h, ref as d, watch as _, openBlock as i, createElementBlock as p, withDirectives as I, createElementVNode as f, vModelText as V, normalizeStyle as C, Fragment as k, renderList as x, normalizeClass as y, toDisplayString as b } from "vue";
2
+ const w = ["maxlength"], D = /* @__PURE__ */ h({
3
+ __name: "input-otp",
4
+ props: {
5
+ modelValue: { default: "" },
6
+ length: { default: 6 },
7
+ itemClass: { default: "" },
8
+ activeItemClass: { default: "" },
9
+ gap: { default: "10px" }
10
+ },
11
+ emits: ["update:modelValue", "complete"],
12
+ setup(n, { emit: c }) {
13
+ const t = n, o = c, u = d(null), a = d(t.modelValue);
14
+ _(
15
+ () => t.modelValue,
16
+ (l) => {
17
+ l !== a.value && (a.value = l);
18
+ }
19
+ );
20
+ function v(l) {
21
+ let e = l.target.value;
22
+ e = e.replace(/\D/g, ""), e = e.slice(0, t.length), a.value = e, o("update:modelValue", e), e.length === t.length && o("complete", e);
23
+ }
24
+ function g() {
25
+ var l;
26
+ (l = u.value) == null || l.focus();
27
+ }
28
+ function r(l) {
29
+ return l === a.value.length;
30
+ }
31
+ return (l, e) => (i(), p("div", {
32
+ class: "otp-wrapper",
33
+ onClick: g
34
+ }, [
35
+ I(f("input", {
36
+ inputmode: "numeric",
37
+ autocomplete: "one-time-code",
38
+ ref_key: "inputRef",
39
+ ref: u,
40
+ "onUpdate:modelValue": e[0] || (e[0] = (m) => a.value = m),
41
+ maxlength: n.length,
42
+ onInput: v,
43
+ class: "otp-input"
44
+ }, null, 40, w), [
45
+ [V, a.value]
46
+ ]),
47
+ f("div", {
48
+ class: "otp-box",
49
+ style: C({ gap: t.gap })
50
+ }, [
51
+ (i(!0), p(k, null, x(n.length, (m, s) => (i(), p("div", {
52
+ key: s,
53
+ class: y(["otp-item", [
54
+ { active: r(s), [t.activeItemClass]: r(s) },
55
+ t.itemClass
56
+ ]])
57
+ }, b(a.value[s] || ""), 3))), 128))
58
+ ], 4)
59
+ ]));
60
+ }
61
+ }), O = (n, c) => {
62
+ const t = n.__vccOpts || n;
63
+ for (const [o, u] of c)
64
+ t[o] = u;
65
+ return t;
66
+ }, R = /* @__PURE__ */ O(D, [["__scopeId", "data-v-14ecb7bd"]]), z = "1.0.0", B = (n) => {
67
+ n.component("RInputOtp", R);
68
+ }, S = {
69
+ version: z,
70
+ install: B
71
+ };
72
+ export {
73
+ R as InputOtp,
74
+ S as default
75
+ };
@@ -0,0 +1 @@
1
+ (function(o,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(o=typeof globalThis<"u"?globalThis:o||self,e(o.RoxV={},o.Vue))})(this,function(o,e){"use strict";const f=["maxlength"],r=((a,p)=>{const n=a.__vccOpts||a;for(const[s,c]of p)n[s]=c;return n})(e.defineComponent({__name:"input-otp",props:{modelValue:{default:""},length:{default:6},itemClass:{default:""},activeItemClass:{default:""},gap:{default:"10px"}},emits:["update:modelValue","complete"],setup(a,{emit:p}){const n=a,s=p,c=e.ref(null),i=e.ref(n.modelValue);e.watch(()=>n.modelValue,l=>{l!==i.value&&(i.value=l)});function _(l){let t=l.target.value;t=t.replace(/\D/g,""),t=t.slice(0,n.length),i.value=t,s("update:modelValue",t),t.length===n.length&&s("complete",t)}function h(){var l;(l=c.value)==null||l.focus()}function d(l){return l===i.value.length}return(l,t)=>(e.openBlock(),e.createElementBlock("div",{class:"otp-wrapper",onClick:h},[e.withDirectives(e.createElementVNode("input",{inputmode:"numeric",autocomplete:"one-time-code",ref_key:"inputRef",ref:c,"onUpdate:modelValue":t[0]||(t[0]=m=>i.value=m),maxlength:a.length,onInput:_,class:"otp-input"},null,40,f),[[e.vModelText,i.value]]),e.createElementVNode("div",{class:"otp-box",style:e.normalizeStyle({gap:n.gap})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(a.length,(m,u)=>(e.openBlock(),e.createElementBlock("div",{key:u,class:e.normalizeClass(["otp-item",[{active:d(u),[n.activeItemClass]:d(u)},n.itemClass]])},e.toDisplayString(i.value[u]||""),3))),128))],4)]))}}),[["__scopeId","data-v-14ecb7bd"]]),g={version:"1.0.0",install:a=>{a.component("RInputOtp",r)}};o.InputOtp=r,o.default=g,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .otp-wrapper[data-v-14ecb7bd]{position:relative;width:max-content;cursor:pointer}.otp-input[data-v-14ecb7bd]{position:absolute;opacity:0;pointer-events:none}.otp-box[data-v-14ecb7bd]{display:flex}.otp-item[data-v-14ecb7bd]{width:40px;height:50px;border:1px solid #ccc;border-radius:8px;text-align:center;line-height:50px;font-size:20px;transition:all .2s}.otp-item.active[data-v-14ecb7bd]{border-color:#409eff;box-shadow:0 0 0 2px #409eff33}
@@ -0,0 +1 @@
1
+ export { InputOtp } from './components/input-otp';
@@ -0,0 +1,69 @@
1
+ import { defineComponent as h, ref as d, watch as _, openBlock as i, createElementBlock as p, withDirectives as V, createElementVNode as f, vModelText as C, normalizeStyle as I, Fragment as k, renderList as y, normalizeClass as x, toDisplayString as b } from "vue";
2
+ const w = ["maxlength"], D = /* @__PURE__ */ h({
3
+ __name: "input-otp",
4
+ props: {
5
+ modelValue: { default: "" },
6
+ length: { default: 6 },
7
+ itemClass: { default: "" },
8
+ activeItemClass: { default: "" },
9
+ gap: { default: "10px" }
10
+ },
11
+ emits: ["update:modelValue", "complete"],
12
+ setup(a, { emit: c }) {
13
+ const t = a, o = c, u = d(null), n = d(t.modelValue);
14
+ _(
15
+ () => t.modelValue,
16
+ (l) => {
17
+ l !== n.value && (n.value = l);
18
+ }
19
+ );
20
+ function v(l) {
21
+ let e = l.target.value;
22
+ e = e.replace(/\D/g, ""), e = e.slice(0, t.length), n.value = e, o("update:modelValue", e), e.length === t.length && o("complete", e);
23
+ }
24
+ function g() {
25
+ var l;
26
+ (l = u.value) == null || l.focus();
27
+ }
28
+ function r(l) {
29
+ return l === n.value.length;
30
+ }
31
+ return (l, e) => (i(), p("div", {
32
+ class: "otp-wrapper",
33
+ onClick: g
34
+ }, [
35
+ V(f("input", {
36
+ inputmode: "numeric",
37
+ autocomplete: "one-time-code",
38
+ ref_key: "inputRef",
39
+ ref: u,
40
+ "onUpdate:modelValue": e[0] || (e[0] = (m) => n.value = m),
41
+ maxlength: a.length,
42
+ onInput: v,
43
+ class: "otp-input"
44
+ }, null, 40, w), [
45
+ [C, n.value]
46
+ ]),
47
+ f("div", {
48
+ class: "otp-box",
49
+ style: I({ gap: t.gap })
50
+ }, [
51
+ (i(!0), p(k, null, y(a.length, (m, s) => (i(), p("div", {
52
+ key: s,
53
+ class: x(["otp-item", [
54
+ { active: r(s), [t.activeItemClass]: r(s) },
55
+ t.itemClass
56
+ ]])
57
+ }, b(n.value[s] || ""), 3))), 128))
58
+ ], 4)
59
+ ]));
60
+ }
61
+ }), z = (a, c) => {
62
+ const t = a.__vccOpts || a;
63
+ for (const [o, u] of c)
64
+ t[o] = u;
65
+ return t;
66
+ }, E = /* @__PURE__ */ z(D, [["__scopeId", "data-v-14ecb7bd"]]);
67
+ export {
68
+ E as InputOtp
69
+ };
package/es/index.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { App } from 'vue';
2
+ import { default as InputOtp } from './components/input-otp/input-otp.vue';
3
+ export * from './components';
4
+ export { InputOtp };
5
+ declare const _default: {
6
+ version: string;
7
+ install: (app: App) => void;
8
+ };
9
+ export default _default;
package/es/index.js ADDED
@@ -0,0 +1,75 @@
1
+ import { defineComponent as h, ref as d, watch as _, openBlock as i, createElementBlock as p, withDirectives as I, createElementVNode as f, vModelText as V, normalizeStyle as C, Fragment as k, renderList as x, normalizeClass as y, toDisplayString as b } from "vue";
2
+ const w = ["maxlength"], D = /* @__PURE__ */ h({
3
+ __name: "input-otp",
4
+ props: {
5
+ modelValue: { default: "" },
6
+ length: { default: 6 },
7
+ itemClass: { default: "" },
8
+ activeItemClass: { default: "" },
9
+ gap: { default: "10px" }
10
+ },
11
+ emits: ["update:modelValue", "complete"],
12
+ setup(n, { emit: c }) {
13
+ const t = n, o = c, u = d(null), a = d(t.modelValue);
14
+ _(
15
+ () => t.modelValue,
16
+ (l) => {
17
+ l !== a.value && (a.value = l);
18
+ }
19
+ );
20
+ function v(l) {
21
+ let e = l.target.value;
22
+ e = e.replace(/\D/g, ""), e = e.slice(0, t.length), a.value = e, o("update:modelValue", e), e.length === t.length && o("complete", e);
23
+ }
24
+ function g() {
25
+ var l;
26
+ (l = u.value) == null || l.focus();
27
+ }
28
+ function r(l) {
29
+ return l === a.value.length;
30
+ }
31
+ return (l, e) => (i(), p("div", {
32
+ class: "otp-wrapper",
33
+ onClick: g
34
+ }, [
35
+ I(f("input", {
36
+ inputmode: "numeric",
37
+ autocomplete: "one-time-code",
38
+ ref_key: "inputRef",
39
+ ref: u,
40
+ "onUpdate:modelValue": e[0] || (e[0] = (m) => a.value = m),
41
+ maxlength: n.length,
42
+ onInput: v,
43
+ class: "otp-input"
44
+ }, null, 40, w), [
45
+ [V, a.value]
46
+ ]),
47
+ f("div", {
48
+ class: "otp-box",
49
+ style: C({ gap: t.gap })
50
+ }, [
51
+ (i(!0), p(k, null, x(n.length, (m, s) => (i(), p("div", {
52
+ key: s,
53
+ class: y(["otp-item", [
54
+ { active: r(s), [t.activeItemClass]: r(s) },
55
+ t.itemClass
56
+ ]])
57
+ }, b(a.value[s] || ""), 3))), 128))
58
+ ], 4)
59
+ ]));
60
+ }
61
+ }), O = (n, c) => {
62
+ const t = n.__vccOpts || n;
63
+ for (const [o, u] of c)
64
+ t[o] = u;
65
+ return t;
66
+ }, R = /* @__PURE__ */ O(D, [["__scopeId", "data-v-14ecb7bd"]]), z = "1.0.0", B = (n) => {
67
+ n.component("RInputOtp", R);
68
+ }, S = {
69
+ version: z,
70
+ install: B
71
+ };
72
+ export {
73
+ R as InputOtp,
74
+ S as default
75
+ };
@@ -0,0 +1,28 @@
1
+
2
+ .otp-wrapper[data-v-14ecb7bd] {
3
+ position: relative;
4
+ width: max-content;
5
+ cursor: pointer;
6
+ }
7
+ .otp-input[data-v-14ecb7bd] {
8
+ position: absolute;
9
+ opacity: 0;
10
+ pointer-events: none;
11
+ }
12
+ .otp-box[data-v-14ecb7bd] {
13
+ display: flex;
14
+ }
15
+ .otp-item[data-v-14ecb7bd] {
16
+ width: 40px;
17
+ height: 50px;
18
+ border: 1px solid #ccc;
19
+ border-radius: 8px;
20
+ text-align: center;
21
+ line-height: 50px;
22
+ font-size: 20px;
23
+ transition: all 0.2s;
24
+ }
25
+ .otp-item.active[data-v-14ecb7bd] {
26
+ border-color: #409eff;
27
+ box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
28
+ }
@@ -0,0 +1,3 @@
1
+ import { default as InputOtp } from './input-otp.vue';
2
+ export { InputOtp };
3
+ export default InputOtp;
@@ -0,0 +1,89 @@
1
+ import { defineComponent, ref, watch, openBlock, createElementBlock, withDirectives, createElementVNode, vModelText, normalizeStyle, Fragment, renderList, normalizeClass, toDisplayString } from "vue";
2
+ const _hoisted_1 = ["maxlength"];
3
+ const _sfc_main = /* @__PURE__ */ defineComponent({
4
+ __name: "input-otp",
5
+ props: {
6
+ modelValue: { default: "" },
7
+ length: { default: 6 },
8
+ itemClass: { default: "" },
9
+ activeItemClass: { default: "" },
10
+ gap: { default: "10px" }
11
+ },
12
+ emits: ["update:modelValue", "complete"],
13
+ setup(__props, { emit: __emit }) {
14
+ const props = __props;
15
+ const emit = __emit;
16
+ const inputRef = ref(null);
17
+ const innerValue = ref(props.modelValue);
18
+ watch(
19
+ () => props.modelValue,
20
+ (val) => {
21
+ if (val !== innerValue.value) {
22
+ innerValue.value = val;
23
+ }
24
+ }
25
+ );
26
+ function handleInput(e) {
27
+ let value = e.target.value;
28
+ value = value.replace(/\D/g, "");
29
+ value = value.slice(0, props.length);
30
+ innerValue.value = value;
31
+ emit("update:modelValue", value);
32
+ if (value.length === props.length) {
33
+ emit("complete", value);
34
+ }
35
+ }
36
+ function focusInput() {
37
+ var _a;
38
+ (_a = inputRef.value) == null ? void 0 : _a.focus();
39
+ }
40
+ function isActive(index) {
41
+ return index === innerValue.value.length;
42
+ }
43
+ return (_ctx, _cache) => {
44
+ return openBlock(), createElementBlock("div", {
45
+ class: "otp-wrapper",
46
+ onClick: focusInput
47
+ }, [
48
+ withDirectives(createElementVNode("input", {
49
+ inputmode: "numeric",
50
+ autocomplete: "one-time-code",
51
+ ref_key: "inputRef",
52
+ ref: inputRef,
53
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => innerValue.value = $event),
54
+ maxlength: __props.length,
55
+ onInput: handleInput,
56
+ class: "otp-input"
57
+ }, null, 40, _hoisted_1), [
58
+ [vModelText, innerValue.value]
59
+ ]),
60
+ createElementVNode("div", {
61
+ class: "otp-box",
62
+ style: normalizeStyle({ gap: props.gap })
63
+ }, [
64
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.length, (_, index) => {
65
+ return openBlock(), createElementBlock("div", {
66
+ key: index,
67
+ class: normalizeClass(["otp-item", [
68
+ { active: isActive(index), [props.activeItemClass]: isActive(index) },
69
+ props.itemClass
70
+ ]])
71
+ }, toDisplayString(innerValue.value[index] || ""), 3);
72
+ }), 128))
73
+ ], 4)
74
+ ]);
75
+ };
76
+ }
77
+ });
78
+ const _export_sfc = (sfc, props) => {
79
+ const target = sfc.__vccOpts || sfc;
80
+ for (const [key, val] of props) {
81
+ target[key] = val;
82
+ }
83
+ return target;
84
+ };
85
+ const InputOtp = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-14ecb7bd"]]);
86
+ export {
87
+ InputOtp,
88
+ InputOtp as default
89
+ };
@@ -0,0 +1,23 @@
1
+ interface Props {
2
+ modelValue?: string;
3
+ length?: number;
4
+ itemClass?: string;
5
+ activeItemClass?: string;
6
+ gap?: string;
7
+ }
8
+ declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
9
+ "update:modelValue": (value: string) => any;
10
+ complete: (value: string) => any;
11
+ }, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
12
+ "onUpdate:modelValue"?: ((value: string) => any) | undefined;
13
+ onComplete?: ((value: string) => any) | undefined;
14
+ }>, {
15
+ modelValue: string;
16
+ length: number;
17
+ itemClass: string;
18
+ activeItemClass: string;
19
+ gap: string;
20
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
21
+ inputRef: HTMLInputElement;
22
+ }, HTMLDivElement>;
23
+ export default _default;
@@ -0,0 +1 @@
1
+ export { InputOtp } from './components/input-otp';
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),f=["maxlength"],v=e.defineComponent({__name:"input-otp",props:{modelValue:{default:""},length:{default:6},itemClass:{default:""},activeItemClass:{default:""},gap:{default:"10px"}},emits:["update:modelValue","complete"],setup(a,{emit:i}){const l=a,u=i,c=e.ref(null),o=e.ref(l.modelValue);e.watch(()=>l.modelValue,n=>{n!==o.value&&(o.value=n)});function m(n){let t=n.target.value;t=t.replace(/\D/g,""),t=t.slice(0,l.length),o.value=t,u("update:modelValue",t),t.length===l.length&&u("complete",t)}function d(){var n;(n=c.value)==null||n.focus()}function r(n){return n===o.value.length}return(n,t)=>(e.openBlock(),e.createElementBlock("div",{class:"otp-wrapper",onClick:d},[e.withDirectives(e.createElementVNode("input",{inputmode:"numeric",autocomplete:"one-time-code",ref_key:"inputRef",ref:c,"onUpdate:modelValue":t[0]||(t[0]=p=>o.value=p),maxlength:a.length,onInput:m,class:"otp-input"},null,40,f),[[e.vModelText,o.value]]),e.createElementVNode("div",{class:"otp-box",style:e.normalizeStyle({gap:l.gap})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(a.length,(p,s)=>(e.openBlock(),e.createElementBlock("div",{key:s,class:e.normalizeClass(["otp-item",[{active:r(s),[l.activeItemClass]:r(s)},l.itemClass]])},e.toDisplayString(o.value[s]||""),3))),128))],4)]))}}),g=(a,i)=>{const l=a.__vccOpts||a;for(const[u,c]of i)l[u]=c;return l},h=g(v,[["__scopeId","data-v-14ecb7bd"]]);exports.InputOtp=h;
package/lib/index.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { App } from 'vue';
2
+ import { default as InputOtp } from './components/input-otp/input-otp.vue';
3
+ export * from './components';
4
+ export { InputOtp };
5
+ declare const _default: {
6
+ version: string;
7
+ install: (app: App) => void;
8
+ };
9
+ export default _default;
package/lib/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),f=["maxlength"],g=e.defineComponent({__name:"input-otp",props:{modelValue:{default:""},length:{default:6},itemClass:{default:""},activeItemClass:{default:""},gap:{default:"10px"}},emits:["update:modelValue","complete"],setup(o,{emit:i}){const l=o,u=i,c=e.ref(null),a=e.ref(l.modelValue);e.watch(()=>l.modelValue,n=>{n!==a.value&&(a.value=n)});function d(n){let t=n.target.value;t=t.replace(/\D/g,""),t=t.slice(0,l.length),a.value=t,u("update:modelValue",t),t.length===l.length&&u("complete",t)}function v(){var n;(n=c.value)==null||n.focus()}function p(n){return n===a.value.length}return(n,t)=>(e.openBlock(),e.createElementBlock("div",{class:"otp-wrapper",onClick:v},[e.withDirectives(e.createElementVNode("input",{inputmode:"numeric",autocomplete:"one-time-code",ref_key:"inputRef",ref:c,"onUpdate:modelValue":t[0]||(t[0]=r=>a.value=r),maxlength:o.length,onInput:d,class:"otp-input"},null,40,f),[[e.vModelText,a.value]]),e.createElementVNode("div",{class:"otp-box",style:e.normalizeStyle({gap:l.gap})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.length,(r,s)=>(e.openBlock(),e.createElementBlock("div",{key:s,class:e.normalizeClass(["otp-item",[{active:p(s),[l.activeItemClass]:p(s)},l.itemClass]])},e.toDisplayString(a.value[s]||""),3))),128))],4)]))}}),h=(o,i)=>{const l=o.__vccOpts||o;for(const[u,c]of i)l[u]=c;return l},m=h(g,[["__scopeId","data-v-14ecb7bd"]]),_="1.0.0",k=o=>{o.component("RInputOtp",m)},I={version:_,install:k};exports.InputOtp=m;exports.default=I;
@@ -0,0 +1,28 @@
1
+
2
+ .otp-wrapper[data-v-14ecb7bd] {
3
+ position: relative;
4
+ width: max-content;
5
+ cursor: pointer;
6
+ }
7
+ .otp-input[data-v-14ecb7bd] {
8
+ position: absolute;
9
+ opacity: 0;
10
+ pointer-events: none;
11
+ }
12
+ .otp-box[data-v-14ecb7bd] {
13
+ display: flex;
14
+ }
15
+ .otp-item[data-v-14ecb7bd] {
16
+ width: 40px;
17
+ height: 50px;
18
+ border: 1px solid #ccc;
19
+ border-radius: 8px;
20
+ text-align: center;
21
+ line-height: 50px;
22
+ font-size: 20px;
23
+ transition: all 0.2s;
24
+ }
25
+ .otp-item.active[data-v-14ecb7bd] {
26
+ border-color: #409eff;
27
+ box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
28
+ }
@@ -0,0 +1,3 @@
1
+ import { default as InputOtp } from './input-otp.vue';
2
+ export { InputOtp };
3
+ export default InputOtp;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const vue = require("vue");
4
+ const _hoisted_1 = ["maxlength"];
5
+ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
6
+ __name: "input-otp",
7
+ props: {
8
+ modelValue: { default: "" },
9
+ length: { default: 6 },
10
+ itemClass: { default: "" },
11
+ activeItemClass: { default: "" },
12
+ gap: { default: "10px" }
13
+ },
14
+ emits: ["update:modelValue", "complete"],
15
+ setup(__props, { emit: __emit }) {
16
+ const props = __props;
17
+ const emit = __emit;
18
+ const inputRef = vue.ref(null);
19
+ const innerValue = vue.ref(props.modelValue);
20
+ vue.watch(
21
+ () => props.modelValue,
22
+ (val) => {
23
+ if (val !== innerValue.value) {
24
+ innerValue.value = val;
25
+ }
26
+ }
27
+ );
28
+ function handleInput(e) {
29
+ let value = e.target.value;
30
+ value = value.replace(/\D/g, "");
31
+ value = value.slice(0, props.length);
32
+ innerValue.value = value;
33
+ emit("update:modelValue", value);
34
+ if (value.length === props.length) {
35
+ emit("complete", value);
36
+ }
37
+ }
38
+ function focusInput() {
39
+ var _a;
40
+ (_a = inputRef.value) == null ? void 0 : _a.focus();
41
+ }
42
+ function isActive(index) {
43
+ return index === innerValue.value.length;
44
+ }
45
+ return (_ctx, _cache) => {
46
+ return vue.openBlock(), vue.createElementBlock("div", {
47
+ class: "otp-wrapper",
48
+ onClick: focusInput
49
+ }, [
50
+ vue.withDirectives(vue.createElementVNode("input", {
51
+ inputmode: "numeric",
52
+ autocomplete: "one-time-code",
53
+ ref_key: "inputRef",
54
+ ref: inputRef,
55
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => innerValue.value = $event),
56
+ maxlength: __props.length,
57
+ onInput: handleInput,
58
+ class: "otp-input"
59
+ }, null, 40, _hoisted_1), [
60
+ [vue.vModelText, innerValue.value]
61
+ ]),
62
+ vue.createElementVNode("div", {
63
+ class: "otp-box",
64
+ style: vue.normalizeStyle({ gap: props.gap })
65
+ }, [
66
+ (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(__props.length, (_, index) => {
67
+ return vue.openBlock(), vue.createElementBlock("div", {
68
+ key: index,
69
+ class: vue.normalizeClass(["otp-item", [
70
+ { active: isActive(index), [props.activeItemClass]: isActive(index) },
71
+ props.itemClass
72
+ ]])
73
+ }, vue.toDisplayString(innerValue.value[index] || ""), 3);
74
+ }), 128))
75
+ ], 4)
76
+ ]);
77
+ };
78
+ }
79
+ });
80
+ const _export_sfc = (sfc, props) => {
81
+ const target = sfc.__vccOpts || sfc;
82
+ for (const [key, val] of props) {
83
+ target[key] = val;
84
+ }
85
+ return target;
86
+ };
87
+ const InputOtp = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-14ecb7bd"]]);
88
+ exports.InputOtp = InputOtp;
89
+ exports.default = InputOtp;
@@ -0,0 +1,23 @@
1
+ interface Props {
2
+ modelValue?: string;
3
+ length?: number;
4
+ itemClass?: string;
5
+ activeItemClass?: string;
6
+ gap?: string;
7
+ }
8
+ declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
9
+ "update:modelValue": (value: string) => any;
10
+ complete: (value: string) => any;
11
+ }, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
12
+ "onUpdate:modelValue"?: ((value: string) => any) | undefined;
13
+ onComplete?: ((value: string) => any) | undefined;
14
+ }>, {
15
+ modelValue: string;
16
+ length: number;
17
+ itemClass: string;
18
+ activeItemClass: string;
19
+ gap: string;
20
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
21
+ inputRef: HTMLInputElement;
22
+ }, HTMLDivElement>;
23
+ export default _default;
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@a-drowned-fish/rox-v",
3
+ "version": "1.0.0",
4
+ "description": "A Vue 3 UI Component Library",
5
+ "main": "lib/index.js",
6
+ "module": "es/index.js",
7
+ "types": "es/index.d.ts",
8
+ "browser": "dist/index.iife.js",
9
+ "unpkg": "dist/index.iife.js",
10
+ "jsdelivr": "dist/index.iife.js",
11
+ "files": [
12
+ "dist",
13
+ "es",
14
+ "lib",
15
+ "resolver"
16
+ ],
17
+ "exports": {
18
+ ".": {
19
+ "import": "./es/index.js",
20
+ "require": "./lib/index.js",
21
+ "types": "./es/index.d.ts"
22
+ },
23
+ "./components": {
24
+ "import": "./es/components.js",
25
+ "require": "./lib/components.js",
26
+ "types": "./es/components.d.ts"
27
+ },
28
+ "./resolver": {
29
+ "import": "./resolver/resolver.js",
30
+ "require": "./resolver/resolver.cjs",
31
+ "types": "./resolver/resolver.d.ts"
32
+ },
33
+ "./dist/*": "./dist/*",
34
+ "./es/*": "./es/*",
35
+ "./lib/*": "./lib/*"
36
+ },
37
+ "sideEffects": [
38
+ "*.css",
39
+ "*.vue.css"
40
+ ],
41
+ "scripts": {
42
+ "build": "tsx scripts/build.ts",
43
+ "dev": "vite",
44
+ "type-check": "vue-tsc --noEmit"
45
+ },
46
+ "keywords": [
47
+ "vue",
48
+ "ui",
49
+ "component-library",
50
+ "auto-import",
51
+ "unplugin-vue-components"
52
+ ],
53
+ "author": "",
54
+ "license": "MIT",
55
+ "peerDependencies": {
56
+ "vue": "^3.0.0"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "unplugin-vue-components": {
60
+ "optional": true
61
+ }
62
+ },
63
+ "dependencies": {
64
+ "vue": "^3.0.0"
65
+ },
66
+ "devDependencies": {
67
+ "@types/node": "^25.6.0",
68
+ "@vitejs/plugin-vue": "^5.2.4",
69
+ "rimraf": "^6.1.3",
70
+ "tsx": "^4.21.0",
71
+ "typescript": "^6.0.3",
72
+ "unplugin-vue-components": "^28.8.0",
73
+ "vite": "^5.4.21",
74
+ "vite-plugin-dts": "^4.5.4",
75
+ "vue-tsc": "^3.2.6"
76
+ }
77
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const componentMap = {
4
+ RInputOtp: "input-otp"
5
+ };
6
+ function RoxVResolver(options = {}) {
7
+ const { cjs = false } = options;
8
+ const moduleType = cjs ? "lib" : "es";
9
+ return {
10
+ type: "component",
11
+ resolve: (name) => {
12
+ const componentName = componentMap[name];
13
+ if (!componentName) {
14
+ return void 0;
15
+ }
16
+ return {
17
+ name,
18
+ path: `rox-v/${moduleType}/${componentName}`,
19
+ sideEffects: `rox-v/${moduleType}/${componentName}/index.css`
20
+ };
21
+ }
22
+ };
23
+ }
24
+ exports.RoxVResolver = RoxVResolver;
25
+ exports.default = RoxVResolver;
@@ -0,0 +1,13 @@
1
+ import { ComponentResolver } from 'unplugin-vue-components/types';
2
+ export interface RoxVResolverOptions {
3
+ /**
4
+ * Use CommonJS build (lib) instead of ES modules (es)
5
+ * @default false
6
+ */
7
+ cjs?: boolean;
8
+ }
9
+ /**
10
+ * Create a resolver for rox-v components
11
+ */
12
+ export declare function RoxVResolver(options?: RoxVResolverOptions): ComponentResolver;
13
+ export default RoxVResolver;
@@ -0,0 +1,25 @@
1
+ const componentMap = {
2
+ RInputOtp: "input-otp"
3
+ };
4
+ function RoxVResolver(options = {}) {
5
+ const { cjs = false } = options;
6
+ const moduleType = cjs ? "lib" : "es";
7
+ return {
8
+ type: "component",
9
+ resolve: (name) => {
10
+ const componentName = componentMap[name];
11
+ if (!componentName) {
12
+ return void 0;
13
+ }
14
+ return {
15
+ name,
16
+ path: `rox-v/${moduleType}/${componentName}`,
17
+ sideEffects: `rox-v/${moduleType}/${componentName}/index.css`
18
+ };
19
+ }
20
+ };
21
+ }
22
+ export {
23
+ RoxVResolver,
24
+ RoxVResolver as default
25
+ };