@lynx-js/lynx-ui-input-otp 0.0.0-oidc-bootstrap.0 → 3.137.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/CHANGELOG.md +26 -0
- package/README.md +35 -4
- package/dist/InputOTP.d.ts +3 -0
- package/dist/InputOTP.d.ts.map +1 -0
- package/dist/InputOTP.jsx +150 -0
- package/dist/InputOTP.jsx.map +1 -0
- package/dist/InputOTPContext.d.ts +4 -0
- package/dist/InputOTPContext.d.ts.map +1 -0
- package/dist/InputOTPContext.jsx +10 -0
- package/dist/InputOTPContext.jsx.map +1 -0
- package/dist/InputOTPSlot.d.ts +3 -0
- package/dist/InputOTPSlot.d.ts.map +1 -0
- package/dist/InputOTPSlot.jsx +37 -0
- package/dist/InputOTPSlot.jsx.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.jsx +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.docs.d.ts +340 -0
- package/dist/types/index.docs.d.ts.map +1 -0
- package/dist/types/index.docs.jsx +1 -0
- package/dist/types/index.jsx +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.jsx +19 -0
- package/dist/utils.jsx.map +1 -0
- package/package.json +44 -5
- package/src/InputOTP.tsx +311 -0
- package/src/InputOTPContext.ts +19 -0
- package/src/InputOTPSlot.tsx +79 -0
- package/src/index.tsx +18 -0
- package/src/types/index.docs.ts +397 -0
- package/src/types/index.ts +5 -0
- package/src/utils.ts +29 -0
- package/tsconfig.docs.json +7 -0
- package/tsconfig.json +9 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @lynx-js/lynx-ui-input-otp
|
|
2
|
+
|
|
3
|
+
## 3.137.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Emit declaration imports with explicit ESM-compatible paths. ([#280](https://github.com/lynx-family/lynx-ui/pull/280))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`064ea4e`](https://github.com/lynx-family/lynx-ui/commit/064ea4e49cd3d0ac5754519cbee43d8ab3040024)]:
|
|
10
|
+
- @lynx-js/lynx-ui-common@3.137.0
|
|
11
|
+
- @lynx-js/lynx-ui-input@3.137.0
|
|
12
|
+
|
|
13
|
+
## 3.136.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- Add the headless InputOTP and InputOTPSlot primitives with four- and six-character ([#241](https://github.com/lynx-family/lynx-ui/pull/241))
|
|
18
|
+
input, controlled and uncontrolled state, input filtering, completion callbacks,
|
|
19
|
+
state styling hooks, examples, and skill references. InputOTP requires Lynx SDK
|
|
20
|
+
4.0 or newer.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [[`0257f8b`](https://github.com/lynx-family/lynx-ui/commit/0257f8bc9fbe6b8a51df00663c7860827ce468b2), [`4214d92`](https://github.com/lynx-family/lynx-ui/commit/4214d923421d0a61ecd0b7cbf9a7a44acaff8d2a)]:
|
|
25
|
+
- @lynx-js/lynx-ui-common@3.136.0
|
|
26
|
+
- @lynx-js/lynx-ui-input@3.136.0
|
package/README.md
CHANGED
|
@@ -1,9 +1,40 @@
|
|
|
1
1
|
# @lynx-js/lynx-ui-input-otp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A headless, configurable-length OTP and PIN input for ReactLynx. InputOTP owns
|
|
4
|
+
keyboard, focus, deletion, paste, filtering, and value state through one hidden
|
|
5
|
+
native input. Consumers compose the visible field with InputOTPSlot.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
## Requirements
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
- **Lynx SDK**: >= 4.0
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm add @lynx-js/lynx-ui
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The standalone package is also available as
|
|
18
|
+
`@lynx-js/lynx-ui-input-otp`.
|
|
19
|
+
|
|
20
|
+
## Component structure
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
<InputOTP length={4}>
|
|
24
|
+
<InputOTPSlot index={0} />
|
|
25
|
+
<InputOTPSlot index={1} />
|
|
26
|
+
<InputOTPSlot index={2} />
|
|
27
|
+
<InputOTPSlot index={3} />
|
|
28
|
+
</InputOTP>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- `InputOTP` owns the normalized controlled or uncontrolled value and the
|
|
32
|
+
hidden native input.
|
|
33
|
+
- `InputOTPSlot` reads one character and its focused, filled, complete,
|
|
34
|
+
disabled, and invalid states from context.
|
|
35
|
+
|
|
36
|
+
InputOTP and InputOTPSlot ship without visible styles. Use `className`,
|
|
37
|
+
`style`, injected `ui-*` variants, and render props to compose the
|
|
38
|
+
presentation.
|
|
39
|
+
|
|
40
|
+
[View examples](https://github.com/lynx-family/lynx-ui/tree/main/apps/examples/InputOTP)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputOTP.d.ts","sourceRoot":"","sources":["../src/InputOTP.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAIV,QAAQ,IAAI,YAAY,EACzB,MAAM,SAAS,CAAA;AAqBhB,eAAO,MAAM,QAAQ,EAAqC,YAAY,CAAA"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { forwardRef, memo, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "@lynx-js/react";
|
|
2
|
+
import { InvokeRejectError, useMemoizedFn } from "@lynx-js/lynx-ui-common";
|
|
3
|
+
import { KeyboardAwareTriggerContext } from "@lynx-js/lynx-ui-input";
|
|
4
|
+
import { clsx } from "clsx";
|
|
5
|
+
import { InputOTPContext } from "./InputOTPContext.jsx";
|
|
6
|
+
import { nativeInputFilters, normalizeInputOTPLength, normalizeOTPValue } from "./utils.jsx";
|
|
7
|
+
const hiddenInputStyle = {
|
|
8
|
+
position: 'absolute',
|
|
9
|
+
top: '0px',
|
|
10
|
+
left: '0px',
|
|
11
|
+
width: '1px',
|
|
12
|
+
height: '1px',
|
|
13
|
+
padding: '0px',
|
|
14
|
+
borderWidth: '0px',
|
|
15
|
+
opacity: 0,
|
|
16
|
+
color: 'transparent',
|
|
17
|
+
caretColor: 'transparent',
|
|
18
|
+
backgroundColor: 'transparent'
|
|
19
|
+
};
|
|
20
|
+
const InputOTP = memo(forwardRef(InputOTPImpl));
|
|
21
|
+
function reportInputError(error) {
|
|
22
|
+
console.warn(`[lynx-ui-input-otp][InputOTP] native input command failed: ${String(error)}`);
|
|
23
|
+
}
|
|
24
|
+
function InputOTPImpl(props, ref) {
|
|
25
|
+
const { length = 6, inputType = 'numeric', value, defaultValue = '', autoFocus = false, disabled = false, invalid = false, className, style, children, onChange, onComplete, onFocus, onBlur } = props;
|
|
26
|
+
const fieldLength = normalizeInputOTPLength(length);
|
|
27
|
+
const isControlled = void 0 !== value;
|
|
28
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(normalizeOTPValue(defaultValue, fieldLength, inputType));
|
|
29
|
+
const [focused, setFocused] = useState(false);
|
|
30
|
+
const inputRef = useRef(null);
|
|
31
|
+
const { onInputBlurred, onInputFocused } = useContext(KeyboardAwareTriggerContext);
|
|
32
|
+
const displayedValue = normalizeOTPValue(isControlled ? value : uncontrolledValue, fieldLength, inputType);
|
|
33
|
+
const invokeInput = useMemoizedFn((method, nextValue)=>new Promise((resolve, reject)=>{
|
|
34
|
+
if (!inputRef.current) return void reject(new Error('InputOTP input is not mounted.'));
|
|
35
|
+
inputRef.current.invoke({
|
|
36
|
+
method,
|
|
37
|
+
...'setValue' === method ? {
|
|
38
|
+
params: {
|
|
39
|
+
value: nextValue ?? ''
|
|
40
|
+
}
|
|
41
|
+
} : {},
|
|
42
|
+
success: ()=>{
|
|
43
|
+
resolve();
|
|
44
|
+
},
|
|
45
|
+
fail: (result)=>{
|
|
46
|
+
reject(new InvokeRejectError(result.code, result.data));
|
|
47
|
+
}
|
|
48
|
+
}).exec();
|
|
49
|
+
}));
|
|
50
|
+
const focus = useMemoizedFn(()=>disabled ? Promise.resolve() : invokeInput('focus'));
|
|
51
|
+
const blur = useMemoizedFn(()=>invokeInput('blur'));
|
|
52
|
+
const syncNativeValue = useMemoizedFn((nextValue)=>invokeInput('setValue', nextValue));
|
|
53
|
+
const emitValue = useMemoizedFn((nextValue, previousValue)=>{
|
|
54
|
+
if (nextValue === previousValue) return;
|
|
55
|
+
onChange?.(nextValue);
|
|
56
|
+
if (nextValue.length === fieldLength && previousValue.length !== fieldLength) onComplete?.(nextValue);
|
|
57
|
+
});
|
|
58
|
+
const setValue = useMemoizedFn((nextRawValue)=>{
|
|
59
|
+
const nextValue = normalizeOTPValue(nextRawValue, fieldLength, inputType);
|
|
60
|
+
if (!isControlled) setUncontrolledValue(nextValue);
|
|
61
|
+
emitValue(nextValue, displayedValue);
|
|
62
|
+
return syncNativeValue(nextValue);
|
|
63
|
+
});
|
|
64
|
+
useImperativeHandle(ref, ()=>({
|
|
65
|
+
focus,
|
|
66
|
+
blur,
|
|
67
|
+
setValue,
|
|
68
|
+
clear: ()=>setValue(''),
|
|
69
|
+
getValue: ()=>displayedValue
|
|
70
|
+
}), [
|
|
71
|
+
blur,
|
|
72
|
+
displayedValue,
|
|
73
|
+
focus,
|
|
74
|
+
setValue
|
|
75
|
+
]);
|
|
76
|
+
useEffect(()=>{
|
|
77
|
+
if (isControlled) return;
|
|
78
|
+
const nextValue = normalizeOTPValue(uncontrolledValue, fieldLength, inputType);
|
|
79
|
+
if (nextValue !== uncontrolledValue) setUncontrolledValue(nextValue);
|
|
80
|
+
}, [
|
|
81
|
+
fieldLength,
|
|
82
|
+
inputType,
|
|
83
|
+
isControlled,
|
|
84
|
+
uncontrolledValue
|
|
85
|
+
]);
|
|
86
|
+
useEffect(()=>{
|
|
87
|
+
syncNativeValue(displayedValue).catch(reportInputError);
|
|
88
|
+
}, [
|
|
89
|
+
displayedValue,
|
|
90
|
+
syncNativeValue
|
|
91
|
+
]);
|
|
92
|
+
useEffect(()=>{
|
|
93
|
+
if (autoFocus && !disabled) focus().catch(reportInputError);
|
|
94
|
+
}, [
|
|
95
|
+
autoFocus,
|
|
96
|
+
disabled,
|
|
97
|
+
focus
|
|
98
|
+
]);
|
|
99
|
+
const handleInput = useMemoizedFn((event)=>{
|
|
100
|
+
const rawValue = event.detail.value;
|
|
101
|
+
const nextValue = normalizeOTPValue(rawValue, fieldLength, inputType);
|
|
102
|
+
if (!isControlled) setUncontrolledValue(nextValue);
|
|
103
|
+
emitValue(nextValue, displayedValue);
|
|
104
|
+
if (rawValue !== nextValue) syncNativeValue(nextValue).catch(reportInputError);
|
|
105
|
+
});
|
|
106
|
+
const handleFocus = useMemoizedFn((_event)=>{
|
|
107
|
+
setFocused(true);
|
|
108
|
+
onInputFocused?.();
|
|
109
|
+
onFocus?.();
|
|
110
|
+
});
|
|
111
|
+
const handleBlur = useMemoizedFn((_event)=>{
|
|
112
|
+
setFocused(false);
|
|
113
|
+
onInputBlurred?.();
|
|
114
|
+
onBlur?.();
|
|
115
|
+
});
|
|
116
|
+
const handleTap = useMemoizedFn(()=>{
|
|
117
|
+
if (!disabled) focus().catch(reportInputError);
|
|
118
|
+
});
|
|
119
|
+
const contextValue = useMemo(()=>({
|
|
120
|
+
value: displayedValue,
|
|
121
|
+
length: fieldLength,
|
|
122
|
+
inputType,
|
|
123
|
+
focused,
|
|
124
|
+
complete: displayedValue.length === fieldLength,
|
|
125
|
+
disabled,
|
|
126
|
+
invalid
|
|
127
|
+
}), [
|
|
128
|
+
disabled,
|
|
129
|
+
displayedValue,
|
|
130
|
+
fieldLength,
|
|
131
|
+
focused,
|
|
132
|
+
inputType,
|
|
133
|
+
invalid
|
|
134
|
+
]);
|
|
135
|
+
const renderedChildren = 'function' == typeof children ? children(contextValue) : children;
|
|
136
|
+
return <InputOTPContext.Provider value={contextValue}>
|
|
137
|
+
<view bindtap={handleTap} className={clsx(className, {
|
|
138
|
+
'ui-focused': focused,
|
|
139
|
+
'ui-complete': contextValue.complete,
|
|
140
|
+
'ui-disabled': disabled,
|
|
141
|
+
'ui-invalid': invalid
|
|
142
|
+
})} flatten={false} style={style}>
|
|
143
|
+
{renderedChildren}
|
|
144
|
+
<input ref={inputRef} android-fullscreen-mode={false} bindblur={handleBlur} bindfocus={handleFocus} bindinput={handleInput} confirm-type='done' disabled={disabled} ignore-focus={true} input-filter={nativeInputFilters[inputType]} ios-auto-correct={false} ios-spell-check={false} maxlength={fieldLength} show-soft-input-on-focus={true} style={hiddenInputStyle} type={'numeric' === inputType ? 'number' : 'text'}/>
|
|
145
|
+
</view>
|
|
146
|
+
</InputOTPContext.Provider>;
|
|
147
|
+
}
|
|
148
|
+
export { InputOTP };
|
|
149
|
+
|
|
150
|
+
//# sourceMappingURL=InputOTP.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputOTP.jsx","sources":["../src/InputOTP.tsx"],"sourcesContent":["// Copyright 2026 The Lynx Authors. All rights reserved.\n// Licensed under the Apache License Version 2.0 that can be found in the\n// LICENSE file in the root directory of this source tree.\n\nimport {\n forwardRef,\n memo,\n useContext,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from '@lynx-js/react'\nimport type { ForwardedRef } from '@lynx-js/react'\n\nimport { InvokeRejectError, useMemoizedFn } from '@lynx-js/lynx-ui-common'\nimport { KeyboardAwareTriggerContext } from '@lynx-js/lynx-ui-input'\nimport type {\n BaseEvent,\n CSSProperties,\n InputBlurEvent,\n InputFocusEvent,\n InputInputEvent,\n NodesRef,\n} from '@lynx-js/types'\nimport { clsx } from 'clsx'\n\nimport { InputOTPContext } from './InputOTPContext'\nimport type {\n InputOTPProps,\n InputOTPRef,\n InputOTPRenderProps,\n InputOTP as InputOTPType,\n} from './types'\nimport {\n nativeInputFilters,\n normalizeInputOTPLength,\n normalizeOTPValue,\n} from './utils'\n\nconst hiddenInputStyle: CSSProperties = {\n position: 'absolute',\n top: '0px',\n left: '0px',\n width: '1px',\n height: '1px',\n padding: '0px',\n borderWidth: '0px',\n opacity: 0,\n color: 'transparent',\n caretColor: 'transparent',\n backgroundColor: 'transparent',\n}\n\nexport const InputOTP = memo(forwardRef(InputOTPImpl)) as InputOTPType\n\nfunction reportInputError(error: unknown) {\n console.warn(\n `[lynx-ui-input-otp][InputOTP] native input command failed: ${\n String(error)\n }`,\n )\n}\n\nfunction InputOTPImpl(\n props: InputOTPProps,\n ref: ForwardedRef<InputOTPRef>,\n) {\n const {\n length = 6,\n inputType = 'numeric',\n value,\n defaultValue = '',\n autoFocus = false,\n disabled = false,\n invalid = false,\n className,\n style,\n children,\n onChange,\n onComplete,\n onFocus,\n onBlur,\n } = props\n\n const fieldLength = normalizeInputOTPLength(length)\n const isControlled = value !== undefined\n const [uncontrolledValue, setUncontrolledValue] = useState(\n normalizeOTPValue(defaultValue, fieldLength, inputType),\n )\n const [focused, setFocused] = useState(false)\n const inputRef = useRef<NodesRef>(null)\n const { onInputBlurred, onInputFocused } = useContext(\n KeyboardAwareTriggerContext,\n )\n\n const displayedValue = normalizeOTPValue(\n isControlled ? value : uncontrolledValue,\n fieldLength,\n inputType,\n )\n\n const invokeInput = useMemoizedFn(\n (\n method: 'focus' | 'blur' | 'setValue',\n nextValue?: string,\n ): Promise<void> =>\n new Promise((resolve, reject) => {\n if (!inputRef.current) {\n reject(new Error('InputOTP input is not mounted.'))\n return\n }\n\n inputRef.current\n .invoke({\n method,\n ...(method === 'setValue'\n ? {\n params: {\n value: nextValue ?? '',\n },\n }\n : {}),\n success: () => {\n resolve()\n },\n fail: (result: { code: number, data: string }) => {\n reject(new InvokeRejectError(result.code, result.data))\n },\n })\n .exec()\n }),\n )\n\n const focus = useMemoizedFn(() =>\n disabled ? Promise.resolve() : invokeInput('focus')\n )\n\n const blur = useMemoizedFn(() => invokeInput('blur'))\n\n const syncNativeValue = useMemoizedFn(\n (nextValue: string) => invokeInput('setValue', nextValue),\n )\n\n const emitValue = useMemoizedFn(\n (nextValue: string, previousValue: string) => {\n if (nextValue === previousValue) {\n return\n }\n\n onChange?.(nextValue)\n\n if (\n nextValue.length === fieldLength\n && previousValue.length !== fieldLength\n ) {\n onComplete?.(nextValue)\n }\n },\n )\n\n const setValue = useMemoizedFn((nextRawValue: string) => {\n const nextValue = normalizeOTPValue(\n nextRawValue,\n fieldLength,\n inputType,\n )\n\n if (!isControlled) {\n setUncontrolledValue(nextValue)\n }\n\n emitValue(nextValue, displayedValue)\n\n return syncNativeValue(nextValue)\n })\n\n useImperativeHandle(\n ref,\n () => ({\n focus,\n blur,\n setValue,\n clear: () => setValue(''),\n getValue: () => displayedValue,\n }),\n [blur, displayedValue, focus, setValue],\n )\n\n useEffect(() => {\n if (isControlled) {\n return\n }\n\n const nextValue = normalizeOTPValue(\n uncontrolledValue,\n fieldLength,\n inputType,\n )\n\n if (nextValue !== uncontrolledValue) {\n setUncontrolledValue(nextValue)\n }\n }, [fieldLength, inputType, isControlled, uncontrolledValue])\n\n useEffect(() => {\n void syncNativeValue(displayedValue).catch(reportInputError)\n }, [displayedValue, syncNativeValue])\n\n useEffect(() => {\n if (autoFocus && !disabled) {\n void focus().catch(reportInputError)\n }\n }, [autoFocus, disabled, focus])\n\n const handleInput = useMemoizedFn(\n (event: BaseEvent<'bindinput', InputInputEvent>) => {\n const rawValue = event.detail.value\n const nextValue = normalizeOTPValue(rawValue, fieldLength, inputType)\n\n if (!isControlled) {\n setUncontrolledValue(nextValue)\n }\n\n emitValue(nextValue, displayedValue)\n\n if (rawValue !== nextValue) {\n void syncNativeValue(nextValue).catch(reportInputError)\n }\n },\n )\n\n const handleFocus = useMemoizedFn(\n (_event: BaseEvent<'bindfocus', InputFocusEvent>) => {\n setFocused(true)\n onInputFocused?.()\n onFocus?.()\n },\n )\n\n const handleBlur = useMemoizedFn(\n (_event: BaseEvent<'bindblur', InputBlurEvent>) => {\n setFocused(false)\n onInputBlurred?.()\n onBlur?.()\n },\n )\n\n const handleTap = useMemoizedFn(() => {\n if (!disabled) {\n void focus().catch(reportInputError)\n }\n })\n\n const contextValue = useMemo<InputOTPRenderProps>(() => ({\n value: displayedValue,\n length: fieldLength,\n inputType,\n focused,\n complete: displayedValue.length === fieldLength,\n disabled,\n invalid,\n }), [\n disabled,\n displayedValue,\n fieldLength,\n focused,\n inputType,\n invalid,\n ])\n\n const renderedChildren = typeof children === 'function'\n ? children(contextValue)\n : children\n\n return (\n <InputOTPContext.Provider value={contextValue}>\n <view\n bindtap={handleTap}\n className={clsx(className, {\n 'ui-focused': focused,\n 'ui-complete': contextValue.complete,\n 'ui-disabled': disabled,\n 'ui-invalid': invalid,\n })}\n flatten={false}\n style={style}\n >\n {renderedChildren}\n <input\n ref={inputRef}\n android-fullscreen-mode={false}\n bindblur={handleBlur}\n bindfocus={handleFocus}\n bindinput={handleInput}\n confirm-type='done'\n disabled={disabled}\n ignore-focus={true}\n input-filter={nativeInputFilters[inputType]}\n ios-auto-correct={false}\n ios-spell-check={false}\n maxlength={fieldLength}\n show-soft-input-on-focus={true}\n style={hiddenInputStyle}\n type={inputType === 'numeric' ? 'number' : 'text'}\n />\n </view>\n </InputOTPContext.Provider>\n )\n}\n"],"names":["hiddenInputStyle","InputOTP","memo","forwardRef","InputOTPImpl","reportInputError","error","console","String","props","ref","length","inputType","value","defaultValue","autoFocus","disabled","invalid","className","style","children","onChange","onComplete","onFocus","onBlur","fieldLength","normalizeInputOTPLength","isControlled","undefined","uncontrolledValue","setUncontrolledValue","useState","normalizeOTPValue","focused","setFocused","inputRef","useRef","onInputBlurred","onInputFocused","useContext","KeyboardAwareTriggerContext","displayedValue","invokeInput","useMemoizedFn","method","nextValue","Promise","resolve","reject","Error","result","InvokeRejectError","focus","blur","syncNativeValue","emitValue","previousValue","setValue","nextRawValue","useImperativeHandle","useEffect","handleInput","event","rawValue","handleFocus","_event","handleBlur","handleTap","contextValue","useMemo","renderedChildren","InputOTPContext","view","clsx","input","nativeInputFilters"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputOTPContext.d.ts","sourceRoot":"","sources":["../src/InputOTPContext.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElD,eAAO,MAAM,eAAe,qDAAkD,CAAA;AAE9E,wBAAgB,kBAAkB,IAAI,mBAAmB,CAQxD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createContext, useContext } from "@lynx-js/react";
|
|
2
|
+
const InputOTPContext = createContext(null);
|
|
3
|
+
function useInputOTPContext() {
|
|
4
|
+
const context = useContext(InputOTPContext);
|
|
5
|
+
if (!context) throw new Error('InputOTPSlot must be used within InputOTP.');
|
|
6
|
+
return context;
|
|
7
|
+
}
|
|
8
|
+
export { InputOTPContext, useInputOTPContext };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=InputOTPContext.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputOTPContext.jsx","sources":["../src/InputOTPContext.ts"],"sourcesContent":["// Copyright 2026 The Lynx Authors. All rights reserved.\n// Licensed under the Apache License Version 2.0 that can be found in the\n// LICENSE file in the root directory of this source tree.\n\nimport { createContext, useContext } from '@lynx-js/react'\n\nimport type { InputOTPRenderProps } from './types'\n\nexport const InputOTPContext = createContext<InputOTPRenderProps | null>(null)\n\nexport function useInputOTPContext(): InputOTPRenderProps {\n const context = useContext(InputOTPContext)\n\n if (!context) {\n throw new Error('InputOTPSlot must be used within InputOTP.')\n }\n\n return context\n}\n"],"names":["InputOTPContext","createContext","useInputOTPContext","context","useContext","Error"],"mappings":";AAQO,MAAMA,kBAAkBC,cAA0C;AAElE,SAASC;IACd,MAAMC,UAAUC,WAAWJ;IAE3B,IAAI,CAACG,SACH,MAAM,IAAIE,MAAM;IAGlB,OAAOF;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputOTPSlot.d.ts","sourceRoot":"","sources":["../src/InputOTPSlot.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAGV,YAAY,IAAI,gBAAgB,EACjC,MAAM,SAAS,CAAA;AAEhB,eAAO,MAAM,YAAY,EAA6B,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { memo } from "@lynx-js/react";
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { useInputOTPContext } from "./InputOTPContext.jsx";
|
|
4
|
+
const InputOTPSlot = memo(InputOTPSlotImpl);
|
|
5
|
+
function InputOTPSlotImpl(props) {
|
|
6
|
+
const { index, className, style, children } = props;
|
|
7
|
+
const context = useInputOTPContext();
|
|
8
|
+
const { value, length, focused, complete, disabled, invalid } = context;
|
|
9
|
+
const char = value[index];
|
|
10
|
+
const isFilled = void 0 !== char;
|
|
11
|
+
const hasFakeCaret = focused && !disabled && value.length < length && index === value.length;
|
|
12
|
+
const slotState = {
|
|
13
|
+
index,
|
|
14
|
+
char,
|
|
15
|
+
focused: hasFakeCaret,
|
|
16
|
+
filled: isFilled,
|
|
17
|
+
complete,
|
|
18
|
+
disabled,
|
|
19
|
+
invalid
|
|
20
|
+
};
|
|
21
|
+
const renderedChildren = 'function' == typeof children ? children(slotState) : children;
|
|
22
|
+
return <view className={clsx(className, {
|
|
23
|
+
'ui-focused': hasFakeCaret,
|
|
24
|
+
'ui-filled': isFilled,
|
|
25
|
+
'ui-complete': complete,
|
|
26
|
+
'ui-disabled': disabled,
|
|
27
|
+
'ui-invalid': invalid
|
|
28
|
+
})} style={style}>
|
|
29
|
+
{void 0 === children ? <>
|
|
30
|
+
{void 0 === char ? null : <text>{char}</text>}
|
|
31
|
+
{hasFakeCaret ? <view/> : null}
|
|
32
|
+
</> : renderedChildren}
|
|
33
|
+
</view>;
|
|
34
|
+
}
|
|
35
|
+
export { InputOTPSlot };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=InputOTPSlot.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputOTPSlot.jsx","sources":["../src/InputOTPSlot.tsx"],"sourcesContent":["// Copyright 2026 The Lynx Authors. All rights reserved.\n// Licensed under the Apache License Version 2.0 that can be found in the\n// LICENSE file in the root directory of this source tree.\n\nimport { memo } from '@lynx-js/react'\n\nimport { clsx } from 'clsx'\n\nimport { useInputOTPContext } from './InputOTPContext'\nimport type {\n InputOTPSlotProps,\n InputOTPSlotRenderProps,\n InputOTPSlot as InputOTPSlotType,\n} from './types'\n\nexport const InputOTPSlot = memo(InputOTPSlotImpl) as InputOTPSlotType\n\nfunction InputOTPSlotImpl(props: InputOTPSlotProps) {\n const {\n index,\n className,\n style,\n children,\n } = props\n const context = useInputOTPContext()\n\n const {\n value,\n length,\n focused,\n complete,\n disabled,\n invalid,\n } = context\n const char = value[index]\n const isFilled = char !== undefined\n const hasFakeCaret = focused\n && !disabled\n && value.length < length\n && index === value.length\n const slotState: InputOTPSlotRenderProps = {\n index,\n char,\n focused: hasFakeCaret,\n filled: isFilled,\n complete,\n disabled,\n invalid,\n }\n const renderedChildren = typeof children === 'function'\n ? children(slotState)\n : children\n\n return (\n <view\n className={clsx(className, {\n 'ui-focused': hasFakeCaret,\n 'ui-filled': isFilled,\n 'ui-complete': complete,\n 'ui-disabled': disabled,\n 'ui-invalid': invalid,\n })}\n style={style}\n >\n {children === undefined\n ? (\n <>\n {char === undefined\n ? null\n : <text>{char}</text>}\n {hasFakeCaret\n ? <view />\n : null}\n </>\n )\n : renderedChildren}\n </view>\n )\n}\n"],"names":["InputOTPSlot","memo","InputOTPSlotImpl","props","index","className","style","children","context","useInputOTPContext","value","length","focused","complete","disabled","invalid","char","isFilled","undefined","hasFakeCaret","slotState","renderedChildren","view","clsx","text"],"mappings":";;;AAeO,MAAMA,eAAeC,KAAKC;AAEjC,SAASA,iBAAiBC,KAAwB;IAChD,MAAM,EACJC,KAAK,EACLC,SAAS,EACTC,KAAK,EACLC,QAAQ,EACT,GAAGJ;IACJ,MAAMK,UAAUC;IAEhB,MAAM,EACJC,KAAK,EACLC,MAAM,EACNC,OAAO,EACPC,QAAQ,EACRC,QAAQ,EACRC,OAAO,EACR,GAAGP;IACJ,MAAMQ,OAAON,KAAK,CAACN,MAAM;IACzB,MAAMa,WAAWD,AAASE,WAATF;IACjB,MAAMG,eAAeP,WAChB,CAACE,YACDJ,MAAM,MAAM,GAAGC,UACfP,UAAUM,MAAM,MAAM;IAC3B,MAAMU,YAAqC;QACzChB;QACAY;QACA,SAASG;QACT,QAAQF;QACRJ;QACAC;QACAC;IACF;IACA,MAAMM,mBAAmB,AAAoB,cAApB,OAAOd,WAC5BA,SAASa,aACTb;IAEJ,QACGe,KACC,WAAWC,KAAKlB,WAAW;QACzB,cAAcc;QACd,aAAaF;QACb,eAAeJ;QACf,eAAeC;QACf,cAAcC;IAChB,IACA,OAAOT,OACR;MACC,CAACC,AAAaW,WAAbX,aAEK;YACA,CAACS,AAASE,WAATF,OACG,QACCQ,MAAMR,OAAOQ,MAAM;YACxB,CAACL,gBACIG,SACD,KAAK;UACX,MAEAD,iBAAiB;IACvB,EAAEC;AAEN"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { InputOTP } from './InputOTP.js';
|
|
2
|
+
export { InputOTPSlot } from './InputOTPSlot.js';
|
|
3
|
+
export type { InputOTPInputType, InputOTPLength, InputOTPProps, InputOTPRef, InputOTPRenderProps, InputOTPSlotProps, InputOTPSlotRenderProps, InputOTPSlotUIVariants, InputOTPUIVariants, } from './types/index.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE7C,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,SAAS,CAAA"}
|
package/dist/index.jsx
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAIA,mBAAmB,cAAc,CAAA"}
|