@adamosuiteservices/ui 2.19.0 → 2.19.2
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/dist/accordion-rounded.cjs +1 -1
- package/dist/accordion-rounded.js +1 -1
- package/dist/accordion.cjs +1 -1
- package/dist/accordion.js +1 -1
- package/dist/amount-input.cjs +1 -1
- package/dist/amount-input.js +1 -1
- package/dist/breadcrumb.cjs +1 -1
- package/dist/breadcrumb.js +1 -1
- package/dist/{button-CXFZVTXF.cjs → button-CPm4-98H.cjs} +1 -1
- package/dist/{button-dT8nqgU3.js → button-D4ddrxyp.js} +1 -1
- package/dist/button.cjs +1 -1
- package/dist/button.js +1 -1
- package/dist/{calendar-B8S5a0TG.cjs → calendar-DbfRhJEt.cjs} +18 -18
- package/dist/{calendar-6NvJv-sP.js → calendar-ghKmqI3K.js} +76 -76
- package/dist/calendar.cjs +1 -1
- package/dist/calendar.js +1 -1
- package/dist/{checkbox-BBlvCoB1.cjs → checkbox-CIzBdqN7.cjs} +1 -1
- package/dist/{checkbox-BuzBXARX.js → checkbox-DPlUjwLi.js} +1 -1
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/{combobox-B002BLsg.js → combobox-DG9u4g84.js} +3 -3
- package/dist/{combobox-B2BkUl7v.cjs → combobox-DylTjGrw.cjs} +1 -1
- package/dist/combobox.cjs +1 -1
- package/dist/combobox.js +1 -1
- package/dist/context-menu.cjs +1 -1
- package/dist/context-menu.js +1 -1
- package/dist/date-picker-selector.cjs +1 -1
- package/dist/date-picker-selector.js +3 -3
- package/dist/dialog.cjs +1 -1
- package/dist/dialog.js +1 -1
- package/dist/dropdown-menu.cjs +1 -1
- package/dist/dropdown-menu.js +1 -1
- package/dist/file-upload-v2.cjs +1 -1
- package/dist/file-upload-v2.js +2 -2
- package/dist/file-upload.cjs +1 -1
- package/dist/file-upload.js +2 -2
- package/dist/full-screen-loader.cjs +1 -1
- package/dist/full-screen-loader.js +1 -1
- package/dist/{icon-B7joBr0A.cjs → icon-C5Q2b1Am.cjs} +1 -1
- package/dist/{icon-BFQz1tQC.js → icon-t4jt1Z2h.js} +1 -1
- package/dist/icon.cjs +1 -1
- package/dist/icon.js +1 -1
- package/dist/{input-8sEO5zwD.js → input-BhpIEjpU.js} +2 -2
- package/dist/{input-AONeSXcs.cjs → input-Dyi5eQGJ.cjs} +4 -4
- package/dist/{input-group-13VFVAxD.cjs → input-group-CW5HkR9e.cjs} +5 -6
- package/dist/{input-group-D4S18xiq.js → input-group-CoG1ulfX.js} +7 -8
- package/dist/input-group.cjs +1 -1
- package/dist/input-group.js +1 -1
- package/dist/input-otp.cjs +10 -12
- package/dist/input-otp.js +92 -94
- package/dist/input.cjs +1 -1
- package/dist/input.js +1 -1
- package/dist/pagination.cjs +1 -1
- package/dist/pagination.js +2 -2
- package/dist/radio-group.cjs +1 -1
- package/dist/radio-group.js +1 -1
- package/dist/select.cjs +1 -1
- package/dist/select.js +1 -1
- package/dist/selectable-card.cjs +2 -2
- package/dist/selectable-card.js +24 -24
- package/dist/{sheet-va7o2x0w.cjs → sheet-Cp6JGhWC.cjs} +1 -1
- package/dist/{sheet-DNwg4a6M.js → sheet-hWerE8S1.js} +1 -1
- package/dist/sheet.cjs +1 -1
- package/dist/sheet.js +1 -1
- package/dist/sidebar.cjs +1 -1
- package/dist/sidebar.js +3 -3
- package/dist/{spinner-C7q7NthY.cjs → spinner-DUZ2vcus.cjs} +1 -1
- package/dist/{spinner-DQ5JLL3U.js → spinner-_-J3zJ_g.js} +1 -1
- package/dist/spinner.cjs +1 -1
- package/dist/spinner.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/timeline.cjs +2 -2
- package/dist/timeline.js +48 -48
- package/docs/components/ui/input-group.md +1 -1
- package/docs/components/ui/input-otp.md +254 -0
- package/docs/components/ui/input.md +0 -2
- package/package.json +1 -1
package/dist/timeline.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./jsx-runtime-BB_1_6y_.cjs"),a=require("./index-DoxiiusW.cjs"),R=require("./index-DCsgSkBj.cjs"),E=require("react");function T(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const n in t)if(n!=="default"){const r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:()=>t[n]})}}return e.default=t,Object.freeze(e)}const s=T(E),d=s.createContext({orientation:"vertical",scrollable:!1}),l=s.createContext({status:"pending"}),v=s.createContext(!1);function C({className:t,orientation:e="vertical",responsive:n=!0,children:r,...m}){const o=R.useMediaQuery("(max-width: 639px)"),c=e==="horizontal"&&n&&o?"vertical":e,u=e==="horizontal"&&!n,p=s.Children.toArray(r),f=i.jsxRuntimeExports.jsx("ol",{"data-slot":"timeline","data-orientation":c,className:a.cn("adm:flex",c==="vertical"?"adm:flex-col":"adm:flex-row adm:items-start",t),...m,children:p.map((x,j)=>{if(!s.isValidElement(x))return x;const b=p[j-1],h=s.isValidElement(b)?b.props.status??"pending":"pending";return i.jsxRuntimeExports.jsx(v.Provider,{value:h==="complete",children:x},j)})});return i.jsxRuntimeExports.jsx(d.Provider,{value:{orientation:c,scrollable:u},children:u?i.jsxRuntimeExports.jsx("div",{className:"adm:w-full adm:overflow-x-auto",children:f}):f})}function y({className:t,status:e="pending",...n}){const{orientation:r,scrollable:m}=s.useContext(d);return i.jsxRuntimeExports.jsx(l.Provider,{value:{status:e},children:i.jsxRuntimeExports.jsx("li",{"data-slot":"timeline-item","data-status":e,className:a.cn("adm:group adm:relative",r==="vertical"?"adm:flex adm:gap-4":a.cn("adm:flex adm:flex-1 adm:flex-col adm:items-center",m&&"adm:min-w-28"),t),...n})})}function g(){const{status:t}=s.useContext(l),e=t==="complete",n=t==="active";return i.jsxRuntimeExports.jsxs("div",{"data-slot":"timeline-dot",className:a.cn("adm:relative adm:flex adm:size-5 adm:shrink-0 adm:items-center","adm:justify-center","adm:rounded-full adm:border","adm:transition-[color,box-shadow,background-color,border-color]",e&&"adm:border-primary adm:bg-primary",n&&"adm:border-primary adm:bg-background",!n&&!e&&"adm:border-border adm:bg-background"),children:[n&&i.jsxRuntimeExports.jsx("span",{className:"adm:size-2 adm:rounded-full adm:bg-primary"}),e&&i.jsxRuntimeExports.jsx("svg",{viewBox:"0 0 12 12",className:"adm:size-3",fill:"none","aria-hidden":!0,children:i.jsxRuntimeExports.jsx("path",{d:"M2 6l3 3 5-5",stroke:"white",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]})}function N({className:t,...e}){const{orientation:n}=s.useContext(d),{status:r}=s.useContext(l),m=s.useContext(v),o=r==="complete";return n==="vertical"?i.jsxRuntimeExports.jsxs("div",{"data-slot":"timeline-indicator",className:a.cn("adm:flex adm:shrink-0 adm:flex-col adm:items-center",t),...e,children:[i.jsxRuntimeExports.jsx(g,{}),i.jsxRuntimeExports.jsx("div",{className:a.cn("adm:my-1 adm:min-h-4 adm:w-px adm:flex-1","adm:group-last:hidden",o?"adm:bg-primary":"adm:bg-border")})]}):i.jsxRuntimeExports.jsxs("div",{"data-slot":"timeline-indicator",className:a.cn("adm:flex adm:w-full adm:items-center",t),...e,children:[i.jsxRuntimeExports.jsx("div",{className:a.cn("adm:h-px adm:flex-1","adm:group-first:invisible",m?"adm:bg-primary":"adm:bg-border")}),i.jsxRuntimeExports.jsx("div",{className:"adm:mx-1",children:i.jsxRuntimeExports.jsx(g,{})}),i.jsxRuntimeExports.jsx("div",{className:a.cn("adm:h-px adm:flex-1","adm:group-last:hidden",o?"adm:bg-primary":"adm:bg-border")})]})}function w({className:t,...e}){const{orientation:n}=s.useContext(d),{status:r}=s.useContext(l);return i.jsxRuntimeExports.jsx("div",{"data-slot":"timeline-content",className:a.cn("adm:flex adm:flex-col adm:gap-3",n==="vertical"?`
|
|
2
2
|
adm:min-w-0 adm:flex-1 adm:pb-4
|
|
3
3
|
adm:group-last:pb-0
|
|
4
|
-
`:"adm:items-center adm:pt-3",r==="pending"?"adm:text-disabled-foreground":"adm:text-foreground",t),...e})}function k({className:t,...e}){return
|
|
4
|
+
`:"adm:items-center adm:pt-3",r==="pending"?"adm:text-disabled-foreground":"adm:text-foreground",t),...e})}function k({className:t,...e}){return i.jsxRuntimeExports.jsx("p",{"data-slot":"timeline-title",className:a.cn("adm:text-sm adm:leading-5 adm:font-semibold",t),...e})}function O({className:t,...e}){return i.jsxRuntimeExports.jsx("p",{"data-slot":"timeline-description",className:a.cn("adm:text-sm adm:leading-5 adm:font-normal",t),...e})}function z({className:t,...e}){return i.jsxRuntimeExports.jsx("time",{"data-slot":"timeline-time",className:a.cn("adm:text-xs adm:leading-4",t),...e})}exports.Timeline=C;exports.TimelineContent=w;exports.TimelineDescription=O;exports.TimelineIndicator=N;exports.TimelineItem=y;exports.TimelineTime=z;exports.TimelineTitle=k;
|
package/dist/timeline.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { j as
|
|
2
|
+
import { j as e } from "./jsx-runtime-BzflLqGi.js";
|
|
3
3
|
import { c as i } from "./index-CRiPKpXj.js";
|
|
4
4
|
import { u as C } from "./index-BBT2EGq8.js";
|
|
5
5
|
import * as n from "react";
|
|
6
|
-
const
|
|
7
|
-
function
|
|
8
|
-
const
|
|
6
|
+
const o = n.createContext({ orientation: "vertical", scrollable: !1 }), l = n.createContext({ status: "pending" }), h = n.createContext(!1);
|
|
7
|
+
function w({ className: a, orientation: t = "vertical", responsive: d = !0, children: m, ...r }) {
|
|
8
|
+
const s = C("(max-width: 639px)"), c = t === "horizontal" && d && s ? "vertical" : t, u = t === "horizontal" && !d, p = n.Children.toArray(m), f = /* @__PURE__ */ e.jsx(
|
|
9
9
|
"ol",
|
|
10
10
|
{
|
|
11
11
|
"data-slot": "timeline",
|
|
@@ -16,22 +16,22 @@ function y({ className: a, orientation: e = "vertical", responsive: d = !0, chil
|
|
|
16
16
|
a
|
|
17
17
|
),
|
|
18
18
|
...r,
|
|
19
|
-
children:
|
|
19
|
+
children: p.map((x, b) => {
|
|
20
20
|
if (!n.isValidElement(x)) return x;
|
|
21
|
-
const v =
|
|
22
|
-
return /* @__PURE__ */
|
|
21
|
+
const v = p[b - 1], j = n.isValidElement(v) ? v.props.status ?? "pending" : "pending";
|
|
22
|
+
return /* @__PURE__ */ e.jsx(h.Provider, { value: j === "complete", children: x }, b);
|
|
23
23
|
})
|
|
24
24
|
}
|
|
25
25
|
);
|
|
26
|
-
return /* @__PURE__ */
|
|
26
|
+
return /* @__PURE__ */ e.jsx(o.Provider, { value: { orientation: c, scrollable: u }, children: u ? /* @__PURE__ */ e.jsx("div", { className: "adm:w-full adm:overflow-x-auto", children: f }) : f });
|
|
27
27
|
}
|
|
28
|
-
function k({ className: a, status:
|
|
29
|
-
const { orientation: m, scrollable: r } = n.useContext(
|
|
30
|
-
return /* @__PURE__ */
|
|
28
|
+
function k({ className: a, status: t = "pending", ...d }) {
|
|
29
|
+
const { orientation: m, scrollable: r } = n.useContext(o);
|
|
30
|
+
return /* @__PURE__ */ e.jsx(l.Provider, { value: { status: t }, children: /* @__PURE__ */ e.jsx(
|
|
31
31
|
"li",
|
|
32
32
|
{
|
|
33
33
|
"data-slot": "timeline-item",
|
|
34
|
-
"data-status":
|
|
34
|
+
"data-status": t,
|
|
35
35
|
className: i(
|
|
36
36
|
"adm:group adm:relative",
|
|
37
37
|
m === "vertical" ? "adm:flex adm:gap-4" : i(
|
|
@@ -45,8 +45,8 @@ function k({ className: a, status: e = "pending", ...d }) {
|
|
|
45
45
|
) });
|
|
46
46
|
}
|
|
47
47
|
function g() {
|
|
48
|
-
const { status: a } = n.useContext(l),
|
|
49
|
-
return /* @__PURE__ */
|
|
48
|
+
const { status: a } = n.useContext(l), t = a === "complete", d = a === "active";
|
|
49
|
+
return /* @__PURE__ */ e.jsxs(
|
|
50
50
|
"div",
|
|
51
51
|
{
|
|
52
52
|
"data-slot": "timeline-dot",
|
|
@@ -55,13 +55,13 @@ function g() {
|
|
|
55
55
|
"adm:justify-center",
|
|
56
56
|
"adm:rounded-full adm:border",
|
|
57
57
|
"adm:transition-[color,box-shadow,background-color,border-color]",
|
|
58
|
-
|
|
58
|
+
t && "adm:border-primary adm:bg-primary",
|
|
59
59
|
d && "adm:border-primary adm:bg-background",
|
|
60
|
-
!d && !
|
|
60
|
+
!d && !t && "adm:border-border adm:bg-background"
|
|
61
61
|
),
|
|
62
62
|
children: [
|
|
63
|
-
d && /* @__PURE__ */
|
|
64
|
-
|
|
63
|
+
d && /* @__PURE__ */ e.jsx("span", { className: "adm:size-2 adm:rounded-full adm:bg-primary" }),
|
|
64
|
+
t && /* @__PURE__ */ e.jsx("svg", { viewBox: "0 0 12 12", className: "adm:size-3", fill: "none", "aria-hidden": !0, children: /* @__PURE__ */ e.jsx(
|
|
65
65
|
"path",
|
|
66
66
|
{
|
|
67
67
|
d: "M2 6l3 3 5-5",
|
|
@@ -75,53 +75,53 @@ function g() {
|
|
|
75
75
|
}
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
|
-
function z({ className: a, ...
|
|
79
|
-
const { orientation: d } = n.useContext(
|
|
80
|
-
return d === "vertical" ? /* @__PURE__ */
|
|
78
|
+
function z({ className: a, ...t }) {
|
|
79
|
+
const { orientation: d } = n.useContext(o), { status: m } = n.useContext(l), r = n.useContext(h), s = m === "complete";
|
|
80
|
+
return d === "vertical" ? /* @__PURE__ */ e.jsxs(
|
|
81
81
|
"div",
|
|
82
82
|
{
|
|
83
83
|
"data-slot": "timeline-indicator",
|
|
84
84
|
className: i("adm:flex adm:shrink-0 adm:flex-col adm:items-center", a),
|
|
85
|
-
...
|
|
85
|
+
...t,
|
|
86
86
|
children: [
|
|
87
|
-
/* @__PURE__ */
|
|
88
|
-
/* @__PURE__ */
|
|
87
|
+
/* @__PURE__ */ e.jsx(g, {}),
|
|
88
|
+
/* @__PURE__ */ e.jsx(
|
|
89
89
|
"div",
|
|
90
90
|
{
|
|
91
91
|
className: i(
|
|
92
|
-
"adm:
|
|
92
|
+
"adm:my-1 adm:min-h-4 adm:w-px adm:flex-1",
|
|
93
93
|
"adm:group-last:hidden",
|
|
94
|
-
|
|
94
|
+
s ? "adm:bg-primary" : "adm:bg-border"
|
|
95
95
|
)
|
|
96
96
|
}
|
|
97
97
|
)
|
|
98
98
|
]
|
|
99
99
|
}
|
|
100
|
-
) : /* @__PURE__ */
|
|
100
|
+
) : /* @__PURE__ */ e.jsxs(
|
|
101
101
|
"div",
|
|
102
102
|
{
|
|
103
103
|
"data-slot": "timeline-indicator",
|
|
104
104
|
className: i("adm:flex adm:w-full adm:items-center", a),
|
|
105
|
-
...
|
|
105
|
+
...t,
|
|
106
106
|
children: [
|
|
107
|
-
/* @__PURE__ */
|
|
107
|
+
/* @__PURE__ */ e.jsx(
|
|
108
108
|
"div",
|
|
109
109
|
{
|
|
110
110
|
className: i(
|
|
111
|
-
"adm:h-
|
|
111
|
+
"adm:h-px adm:flex-1",
|
|
112
112
|
"adm:group-first:invisible",
|
|
113
113
|
r ? "adm:bg-primary" : "adm:bg-border"
|
|
114
114
|
)
|
|
115
115
|
}
|
|
116
116
|
),
|
|
117
|
-
/* @__PURE__ */
|
|
118
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ e.jsx("div", { className: "adm:mx-1", children: /* @__PURE__ */ e.jsx(g, {}) }),
|
|
118
|
+
/* @__PURE__ */ e.jsx(
|
|
119
119
|
"div",
|
|
120
120
|
{
|
|
121
121
|
className: i(
|
|
122
|
-
"adm:h-
|
|
122
|
+
"adm:h-px adm:flex-1",
|
|
123
123
|
"adm:group-last:hidden",
|
|
124
|
-
|
|
124
|
+
s ? "adm:bg-primary" : "adm:bg-border"
|
|
125
125
|
)
|
|
126
126
|
}
|
|
127
127
|
)
|
|
@@ -129,9 +129,9 @@ function z({ className: a, ...e }) {
|
|
|
129
129
|
}
|
|
130
130
|
);
|
|
131
131
|
}
|
|
132
|
-
function A({ className: a, ...
|
|
133
|
-
const { orientation: d } = n.useContext(
|
|
134
|
-
return /* @__PURE__ */
|
|
132
|
+
function A({ className: a, ...t }) {
|
|
133
|
+
const { orientation: d } = n.useContext(o), { status: m } = n.useContext(l);
|
|
134
|
+
return /* @__PURE__ */ e.jsx(
|
|
135
135
|
"div",
|
|
136
136
|
{
|
|
137
137
|
"data-slot": "timeline-content",
|
|
@@ -144,42 +144,42 @@ function A({ className: a, ...e }) {
|
|
|
144
144
|
m === "pending" ? "adm:text-disabled-foreground" : "adm:text-foreground",
|
|
145
145
|
a
|
|
146
146
|
),
|
|
147
|
-
...
|
|
147
|
+
...t
|
|
148
148
|
}
|
|
149
149
|
);
|
|
150
150
|
}
|
|
151
|
-
function E({ className: a, ...
|
|
152
|
-
return /* @__PURE__ */
|
|
151
|
+
function E({ className: a, ...t }) {
|
|
152
|
+
return /* @__PURE__ */ e.jsx(
|
|
153
153
|
"p",
|
|
154
154
|
{
|
|
155
155
|
"data-slot": "timeline-title",
|
|
156
156
|
className: i("adm:text-sm adm:leading-5 adm:font-semibold", a),
|
|
157
|
-
...
|
|
157
|
+
...t
|
|
158
158
|
}
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
|
-
function I({ className: a, ...
|
|
162
|
-
return /* @__PURE__ */
|
|
161
|
+
function I({ className: a, ...t }) {
|
|
162
|
+
return /* @__PURE__ */ e.jsx(
|
|
163
163
|
"p",
|
|
164
164
|
{
|
|
165
165
|
"data-slot": "timeline-description",
|
|
166
166
|
className: i("adm:text-sm adm:leading-5 adm:font-normal", a),
|
|
167
|
-
...
|
|
167
|
+
...t
|
|
168
168
|
}
|
|
169
169
|
);
|
|
170
170
|
}
|
|
171
|
-
function M({ className: a, ...
|
|
172
|
-
return /* @__PURE__ */
|
|
171
|
+
function M({ className: a, ...t }) {
|
|
172
|
+
return /* @__PURE__ */ e.jsx(
|
|
173
173
|
"time",
|
|
174
174
|
{
|
|
175
175
|
"data-slot": "timeline-time",
|
|
176
176
|
className: i("adm:text-xs adm:leading-4", a),
|
|
177
|
-
...
|
|
177
|
+
...t
|
|
178
178
|
}
|
|
179
179
|
);
|
|
180
180
|
}
|
|
181
181
|
export {
|
|
182
|
-
|
|
182
|
+
w as Timeline,
|
|
183
183
|
A as TimelineContent,
|
|
184
184
|
I as TimelineDescription,
|
|
185
185
|
z as TimelineIndicator,
|
|
@@ -478,7 +478,7 @@ Addons focus the input when clicking on the addon (not on buttons).
|
|
|
478
478
|
|
|
479
479
|
## Implementation notes
|
|
480
480
|
|
|
481
|
-
- **Container**: InputGroup is the wrapper with border,
|
|
481
|
+
- **Container**: InputGroup is the wrapper with border, focus ring
|
|
482
482
|
- **Input/Textarea**: No border, no shadow, no focus ring (applied to group)
|
|
483
483
|
- **Auto-height**: Group has `has-[>textarea]:h-auto` for textareas
|
|
484
484
|
- **Alignment**: CVA with 4 positions (inline-start, inline-end, block-start, block-end)
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# Input OTP component
|
|
2
|
+
|
|
3
|
+
Accessible one-time password (OTP) input. Built on top of the `input-otp` library with support for separators, custom patterns, validation, and disabled state.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
The `InputOTP` component provides a set of individual input slots for entering one-time passwords or verification codes. Each slot accepts a single character and advances focus automatically.
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import {
|
|
13
|
+
InputOTP,
|
|
14
|
+
InputOTPGroup,
|
|
15
|
+
InputOTPSeparator,
|
|
16
|
+
InputOTPSlot,
|
|
17
|
+
} from "@adamosuiteservices/ui/input-otp";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Components**: 4 (`InputOTP`, `InputOTPGroup`, `InputOTPSlot`, `InputOTPSeparator`)
|
|
21
|
+
|
|
22
|
+
## Basic usage
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
<InputOTP maxLength={6}>
|
|
26
|
+
<InputOTPGroup>
|
|
27
|
+
<InputOTPSlot index={0} />
|
|
28
|
+
<InputOTPSlot index={1} />
|
|
29
|
+
<InputOTPSlot index={2} />
|
|
30
|
+
<InputOTPSlot index={3} />
|
|
31
|
+
<InputOTPSlot index={4} />
|
|
32
|
+
<InputOTPSlot index={5} />
|
|
33
|
+
</InputOTPGroup>
|
|
34
|
+
</InputOTP>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## With separator
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
<InputOTP maxLength={6}>
|
|
41
|
+
<InputOTPGroup>
|
|
42
|
+
<InputOTPSlot index={0} />
|
|
43
|
+
<InputOTPSlot index={1} />
|
|
44
|
+
<InputOTPSlot index={2} />
|
|
45
|
+
</InputOTPGroup>
|
|
46
|
+
<InputOTPSeparator />
|
|
47
|
+
<InputOTPGroup>
|
|
48
|
+
<InputOTPSlot index={3} />
|
|
49
|
+
<InputOTPSlot index={4} />
|
|
50
|
+
<InputOTPSlot index={5} />
|
|
51
|
+
</InputOTPGroup>
|
|
52
|
+
</InputOTP>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## With label and description
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
<FieldGroup>
|
|
59
|
+
<Field>
|
|
60
|
+
<FieldLabel htmlFor="otp">One-time password</FieldLabel>
|
|
61
|
+
<InputOTP maxLength={6} id="otp">
|
|
62
|
+
<InputOTPGroup>
|
|
63
|
+
<InputOTPSlot index={0} />
|
|
64
|
+
<InputOTPSlot index={1} />
|
|
65
|
+
<InputOTPSlot index={2} />
|
|
66
|
+
<InputOTPSlot index={3} />
|
|
67
|
+
<InputOTPSlot index={4} />
|
|
68
|
+
<InputOTPSlot index={5} />
|
|
69
|
+
</InputOTPGroup>
|
|
70
|
+
</InputOTP>
|
|
71
|
+
<FieldDescription>
|
|
72
|
+
Enter the 6-digit code sent to your email.
|
|
73
|
+
</FieldDescription>
|
|
74
|
+
</Field>
|
|
75
|
+
</FieldGroup>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Controlled
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
const [value, setValue] = useState("");
|
|
82
|
+
|
|
83
|
+
<InputOTP maxLength={6} value={value} onChange={setValue}>
|
|
84
|
+
<InputOTPGroup>
|
|
85
|
+
<InputOTPSlot index={0} />
|
|
86
|
+
<InputOTPSlot index={1} />
|
|
87
|
+
<InputOTPSlot index={2} />
|
|
88
|
+
</InputOTPGroup>
|
|
89
|
+
<InputOTPSeparator />
|
|
90
|
+
<InputOTPGroup>
|
|
91
|
+
<InputOTPSlot index={3} />
|
|
92
|
+
<InputOTPSlot index={4} />
|
|
93
|
+
<InputOTPSlot index={5} />
|
|
94
|
+
</InputOTPGroup>
|
|
95
|
+
</InputOTP>;
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Digits only
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { REGEXP_ONLY_DIGITS } from "input-otp";
|
|
102
|
+
|
|
103
|
+
<InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS}>
|
|
104
|
+
<InputOTPGroup>
|
|
105
|
+
<InputOTPSlot index={0} />
|
|
106
|
+
<InputOTPSlot index={1} />
|
|
107
|
+
<InputOTPSlot index={2} />
|
|
108
|
+
<InputOTPSlot index={3} />
|
|
109
|
+
<InputOTPSlot index={4} />
|
|
110
|
+
<InputOTPSlot index={5} />
|
|
111
|
+
</InputOTPGroup>
|
|
112
|
+
</InputOTP>;
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Letters only
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import { REGEXP_ONLY_CHARS } from "input-otp";
|
|
119
|
+
|
|
120
|
+
<InputOTP maxLength={6} pattern={REGEXP_ONLY_CHARS}>
|
|
121
|
+
<InputOTPGroup>
|
|
122
|
+
<InputOTPSlot index={0} />
|
|
123
|
+
<InputOTPSlot index={1} />
|
|
124
|
+
<InputOTPSlot index={2} />
|
|
125
|
+
<InputOTPSlot index={3} />
|
|
126
|
+
<InputOTPSlot index={4} />
|
|
127
|
+
<InputOTPSlot index={5} />
|
|
128
|
+
</InputOTPGroup>
|
|
129
|
+
</InputOTP>;
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## States
|
|
133
|
+
|
|
134
|
+
### Disabled
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<InputOTP maxLength={6} disabled>
|
|
138
|
+
<InputOTPGroup>
|
|
139
|
+
<InputOTPSlot index={0} />
|
|
140
|
+
<InputOTPSlot index={1} />
|
|
141
|
+
<InputOTPSlot index={2} />
|
|
142
|
+
</InputOTPGroup>
|
|
143
|
+
<InputOTPSeparator />
|
|
144
|
+
<InputOTPGroup>
|
|
145
|
+
<InputOTPSlot index={3} />
|
|
146
|
+
<InputOTPSlot index={4} />
|
|
147
|
+
<InputOTPSlot index={5} />
|
|
148
|
+
</InputOTPGroup>
|
|
149
|
+
</InputOTP>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Invalid
|
|
153
|
+
|
|
154
|
+
Apply `aria-invalid` to each `InputOTPSlot` to show validation error styles:
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
<FieldGroup>
|
|
158
|
+
<Field>
|
|
159
|
+
<FieldLabel htmlFor="invalid-otp">Verification code</FieldLabel>
|
|
160
|
+
<InputOTP maxLength={6} id="invalid-otp">
|
|
161
|
+
<InputOTPGroup>
|
|
162
|
+
<InputOTPSlot index={0} aria-invalid />
|
|
163
|
+
<InputOTPSlot index={1} aria-invalid />
|
|
164
|
+
<InputOTPSlot index={2} aria-invalid />
|
|
165
|
+
<InputOTPSlot index={3} aria-invalid />
|
|
166
|
+
<InputOTPSlot index={4} aria-invalid />
|
|
167
|
+
<InputOTPSlot index={5} aria-invalid />
|
|
168
|
+
</InputOTPGroup>
|
|
169
|
+
</InputOTP>
|
|
170
|
+
<FieldError>Invalid code. Please try again.</FieldError>
|
|
171
|
+
</Field>
|
|
172
|
+
</FieldGroup>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Props
|
|
176
|
+
|
|
177
|
+
### InputOTP
|
|
178
|
+
|
|
179
|
+
| Prop | Type | Default | Description |
|
|
180
|
+
| -------------------- | ------------------------- | ------- | --------------------------------------- |
|
|
181
|
+
| `maxLength` | `number` | - | Total number of OTP slots (required) |
|
|
182
|
+
| `value` | `string` | - | Controlled value |
|
|
183
|
+
| `onChange` | `(value: string) => void` | - | Callback when value changes |
|
|
184
|
+
| `pattern` | `string \| RegExp` | - | Regex pattern to restrict allowed input |
|
|
185
|
+
| `disabled` | `boolean` | `false` | Disables all slots |
|
|
186
|
+
| `containerClassName` | `string` | - | Additional classes for the container |
|
|
187
|
+
| `className` | `string` | - | Additional classes for the hidden input |
|
|
188
|
+
|
|
189
|
+
### InputOTPGroup
|
|
190
|
+
|
|
191
|
+
| Prop | Type | Default | Description |
|
|
192
|
+
| ----------- | -------- | ------- | ---------------------- |
|
|
193
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
194
|
+
|
|
195
|
+
### InputOTPSlot
|
|
196
|
+
|
|
197
|
+
| Prop | Type | Default | Description |
|
|
198
|
+
| -------------- | --------- | ------- | ------------------------------ |
|
|
199
|
+
| `index` | `number` | - | Slot position index (required) |
|
|
200
|
+
| `aria-invalid` | `boolean` | `false` | Marks slot as invalid |
|
|
201
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
202
|
+
|
|
203
|
+
### InputOTPSeparator
|
|
204
|
+
|
|
205
|
+
Renders a visual separator (dash icon) between groups. Accepts all native `<div>` props.
|
|
206
|
+
|
|
207
|
+
## Slot styles
|
|
208
|
+
|
|
209
|
+
### Default
|
|
210
|
+
|
|
211
|
+
- **Size**: `h-10 w-14` (40×56px)
|
|
212
|
+
- **Border**: `border border-input rounded-md`
|
|
213
|
+
- **Background**: `bg-background`
|
|
214
|
+
- **Font**: `text-sm text-input-foreground`
|
|
215
|
+
- **Placeholder**: `-` dash shown in `text-foreground-secondary` when empty
|
|
216
|
+
- **Spacing between slots**: `gap-4` (16px) via `InputOTPGroup`
|
|
217
|
+
- **Transitions**: `transition-[color,box-shadow]`
|
|
218
|
+
|
|
219
|
+
### Active (focused slot)
|
|
220
|
+
|
|
221
|
+
- `data-[active=true]:border-primary-300`
|
|
222
|
+
- `data-[active=true]:ring-4 data-[active=true]:ring-primary/10`
|
|
223
|
+
|
|
224
|
+
### Invalid
|
|
225
|
+
|
|
226
|
+
- `aria-invalid:border-destructive`
|
|
227
|
+
- `data-[active=true]:aria-invalid:border-destructive`
|
|
228
|
+
- `data-[active=true]:aria-invalid:ring-destructive/10`
|
|
229
|
+
|
|
230
|
+
### Disabled
|
|
231
|
+
|
|
232
|
+
- `has-disabled:opacity-50` applied to the container
|
|
233
|
+
|
|
234
|
+
## Accessibility
|
|
235
|
+
|
|
236
|
+
- ✅ **Keyboard**: Focus advances automatically between slots on input
|
|
237
|
+
- ✅ **ARIA**: Use `aria-invalid` on each slot for error states
|
|
238
|
+
- ✅ **Label**: Associate an `id` on `InputOTP` and use `<FieldLabel htmlFor="...">`
|
|
239
|
+
- ✅ **Role**: `InputOTPSeparator` has `role="separator"`
|
|
240
|
+
- ✅ **Description**: Use `aria-describedby` or `<FieldDescription>` for help messages
|
|
241
|
+
- ⚠️ **Error messages**: Associate with `<FieldError>` and `aria-describedby` for screen readers
|
|
242
|
+
|
|
243
|
+
## Implementation notes
|
|
244
|
+
|
|
245
|
+
- **Built on `input-otp`**: Wraps the `OTPInput` and `OTPInputContext` primitives
|
|
246
|
+
- **Hidden input**: The actual `<input>` element is hidden; visible slots are `<div>` elements driven by context
|
|
247
|
+
- **Fake caret**: An animated blinking caret is rendered inside the active slot via `hasFakeCaret`
|
|
248
|
+
- **Pattern support**: Pass `REGEXP_ONLY_DIGITS` or `REGEXP_ONLY_CHARS` from `input-otp` for restricted input
|
|
249
|
+
- **Composition**: Slots are always zero-indexed. When using a separator, slot indices continue sequentially across groups (0–2 in first group, 3–5 in second)
|
|
250
|
+
|
|
251
|
+
## References
|
|
252
|
+
|
|
253
|
+
- input-otp library: <https://github.com/guilhermerodz/input-otp>
|
|
254
|
+
- shadcn/ui documentation: <https://ui.shadcn.com/docs/components/input-otp>
|
|
@@ -306,7 +306,6 @@ const maxLength = 100;
|
|
|
306
306
|
- **Border**: `border`, `border-input`, `rounded-md`
|
|
307
307
|
- **Padding**: `px-3` (no vertical padding, height defines the height)
|
|
308
308
|
- **Font**: `text-sm`
|
|
309
|
-
- **Shadow**: `shadow-xs`
|
|
310
309
|
- **Background**: `bg-background`
|
|
311
310
|
- **Hover**: `hover:bg-muted`
|
|
312
311
|
- **Transitions**: `transition-[color,box-shadow]`
|
|
@@ -330,7 +329,6 @@ const maxLength = 100;
|
|
|
330
329
|
- **Validation**: Uses native attributes (`required`, `pattern`, `min`, `max`) + `aria-invalid`
|
|
331
330
|
- **File input**: Special styles for "Choose file" button
|
|
332
331
|
- **Focus ring**: `ring-4` with `ring-primary/10` for visibility without being invasive
|
|
333
|
-
- **Shadow**: Subtle `shadow-xs` for depth
|
|
334
332
|
- **Font size**: `text-sm` on all screen sizes
|
|
335
333
|
- **Background**: Solid `bg-background`, `hover:bg-muted`
|
|
336
334
|
|