@mindlogic-ai/logician-ui 4.0.0-alpha.38 → 4.0.0-alpha.40

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,6 +1,3 @@
1
1
  import { PinInputProps } from './PinInput.types';
2
- export declare const PinInput: {
3
- ({ value, onChange, inputStyle, autoFocus, isNumberOnly, ...rest }: PinInputProps): import("react/jsx-runtime").JSX.Element;
4
- displayName: string;
5
- };
2
+ export declare const PinInput: import("react").ForwardRefExoticComponent<PinInputProps & import("react").RefAttributes<HTMLInputElement>>;
6
3
  //# sourceMappingURL=PinInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PinInput.d.ts","sourceRoot":"","sources":["../../../src/components/PinInput/PinInput.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,eAAO,MAAM,QAAQ;wEAOlB,aAAa;;CAkCf,CAAC"}
1
+ {"version":3,"file":"PinInput.d.ts","sourceRoot":"","sources":["../../../src/components/PinInput/PinInput.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,eAAO,MAAM,QAAQ,4GAgDpB,CAAC"}
@@ -3,30 +3,13 @@
3
3
 
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var React = require('react');
6
- var ReactPinInput = require('react-pin-input');
7
6
  var react = require('@chakra-ui/react');
7
+ var formControls = require('../../theme/formControls.js');
8
8
 
9
- // TODO: forwardRef
10
- const PinInput = ({ value, onChange, inputStyle, autoFocus = true, isNumberOnly = true, ...rest }) => {
11
- const pinInputRef = React.useRef(null);
12
- const primaryColor = react.useToken('colors', 'primary.main')[0];
13
- const grayColor = react.useToken('colors', 'border.default')[0];
14
- React.useEffect(() => {
15
- // Automatically focus the PinInput component on mount
16
- if (autoFocus)
17
- pinInputRef.current?.focus();
18
- }, []);
19
- return (jsxRuntime.jsx(ReactPinInput, { ref: pinInputRef, initialValue: value, onChange: onChange, type: isNumberOnly ? 'numeric' : 'custom', inputMode: isNumberOnly ? 'number' : 'text', inputStyle: {
20
- borderColor: grayColor,
21
- borderRadius: '8px',
22
- width: '48px',
23
- height: '48px',
24
- ...inputStyle,
25
- }, inputFocusStyle: {
26
- borderColor: primaryColor,
27
- boxShadow: `0 0 0 1px ${primaryColor}`,
28
- }, onComplete: onChange, autoSelect: true, regexCriteria: isNumberOnly ? /^[0-9]*$/ : undefined, ...rest }));
29
- };
9
+ const PinInput = React.forwardRef(function PinInput({ length, value, onChange, onComplete, placeholder = '', inputProps, ...rest }, ref) {
10
+ const valueArray = Array.from({ length }, (_, i) => value?.[i] ?? '');
11
+ return (jsxRuntime.jsxs(react.PinInput.Root, { count: length, value: valueArray, onValueChange: (d) => onChange?.(d.valueAsString), onValueComplete: (d) => onComplete?.(d.valueAsString), placeholder: placeholder, ...rest, children: [jsxRuntime.jsx(react.PinInput.HiddenInput, { ref: ref, ...inputProps }), jsxRuntime.jsx(react.PinInput.Control, { children: Array.from({ length }).map((_, i) => (jsxRuntime.jsx(react.PinInput.Input, { index: i, w: 12, h: 12, fontSize: "lg", borderRadius: "md", bg: "bg.surface", color: "fg.default", borderColor: "border.default", _hover: { borderColor: 'primary.lighter' }, _focus: { borderColor: 'primary.main' }, _invalid: { borderColor: 'danger.main' }, _disabled: { borderColor: 'border.subtle', bg: 'bg.subtle' }, css: formControls.noZoomOnFocus }, i))) })] }));
12
+ });
30
13
  PinInput.displayName = 'PinInput';
31
14
 
32
15
  exports.PinInput = PinInput;
@@ -1 +1 @@
1
- {"version":3,"file":"PinInput.js","sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":[null],"names":["useRef","useToken","useEffect","_jsx"],"mappings":";;;;;;;;AAMA;AACO,MAAM,QAAQ,GAAG,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,UAAU,EACV,SAAS,GAAG,IAAI,EAChB,YAAY,GAAG,IAAI,EACnB,GAAG,IAAI,EACO,KAAI;AAClB,IAAA,MAAM,WAAW,GAAGA,YAAM,CAAgB,IAAI,CAAC;IAC/C,MAAM,YAAY,GAAGC,cAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAGA,cAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEzDC,eAAS,CAAC,MAAK;;AAEb,QAAA,IAAI,SAAS;AAAE,YAAA,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE;IAC7C,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,QACEC,cAAA,CAAC,aAAa,IACZ,GAAG,EAAE,WAAW,EAChB,YAAY,EAAE,KAAK,EACnB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,YAAY,GAAG,SAAS,GAAG,QAAQ,EACzC,SAAS,EAAE,YAAY,GAAG,QAAQ,GAAG,MAAM,EAC3C,UAAU,EAAE;AACV,YAAA,WAAW,EAAE,SAAS;AACtB,YAAA,YAAY,EAAE,KAAK;AACnB,YAAA,KAAK,EAAE,MAAM;AACb,YAAA,MAAM,EAAE,MAAM;AACd,YAAA,GAAG,UAAU;AACd,SAAA,EACD,eAAe,EAAE;AACf,YAAA,WAAW,EAAE,YAAY;YACzB,SAAS,EAAE,CAAA,UAAA,EAAa,YAAY,CAAA,CAAE;SACvC,EACD,UAAU,EAAE,QAAQ,EACpB,UAAU,EAAA,IAAA,EACV,aAAa,EAAE,YAAY,GAAG,UAAU,GAAG,SAAS,EAAA,GAChD,IAAI,EAAA,CACR;AAEN;AAEA,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
1
+ {"version":3,"file":"PinInput.js","sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":[null],"names":["forwardRef","_jsxs","ChakraPinInput","_jsx","noZoomOnFocus"],"mappings":";;;;;;;;AASO,MAAM,QAAQ,GAAGA,gBAAU,CAChC,SAAS,QAAQ,CACf,EACE,MAAM,EACN,KAAK,EACL,QAAQ,EACR,UAAU,EACV,WAAW,GAAG,EAAE,EAChB,UAAU,EACV,GAAG,IAAI,EACR,EACD,GAAG,EAAA;IAEH,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAErE,IAAA,QACEC,eAAA,CAACC,cAAc,CAAC,IAAI,IAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,UAAU,EACjB,aAAa,EAAE,CAAC,CAAC,KAAK,QAAQ,GAAG,CAAC,CAAC,aAAa,CAAC,EACjD,eAAe,EAAE,CAAC,CAAC,KAAK,UAAU,GAAG,CAAC,CAAC,aAAa,CAAC,EACrD,WAAW,EAAE,WAAW,EAAA,GACpB,IAAI,aAERC,cAAA,CAACD,cAAc,CAAC,WAAW,IAAC,GAAG,EAAE,GAAG,EAAA,GAAM,UAAU,GAAI,EACxDC,cAAA,CAACD,cAAc,CAAC,OAAO,EAAA,EAAA,QAAA,EACpB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAC/BC,cAAA,CAACD,cAAc,CAAC,KAAK,EAAA,EAEnB,KAAK,EAAE,CAAC,EACR,CAAC,EAAE,EAAE,EACL,CAAC,EAAE,EAAE,EACL,QAAQ,EAAC,IAAI,EACb,YAAY,EAAC,IAAI,EACjB,EAAE,EAAC,YAAY,EACf,KAAK,EAAC,YAAY,EAClB,WAAW,EAAC,gBAAgB,EAC5B,MAAM,EAAE,EAAE,WAAW,EAAE,iBAAiB,EAAE,EAC1C,MAAM,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,EACvC,QAAQ,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EACxC,SAAS,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,EAAE,WAAW,EAAE,EAC5D,GAAG,EAAEE,0BAAa,EAAA,EAbb,CAAC,CAcN,CACH,CAAC,EAAA,CACqB,CAAA,EAAA,CACL;AAE1B,CAAC;AAGH,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
@@ -1,30 +1,13 @@
1
1
  "use client";
2
- import { jsx } from 'react/jsx-runtime';
3
- import { useRef, useEffect } from 'react';
4
- import ReactPinInput from 'react-pin-input';
5
- import { useToken } from '@chakra-ui/react';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { forwardRef } from 'react';
4
+ import { PinInput as PinInput$1 } from '@chakra-ui/react';
5
+ import { noZoomOnFocus } from '../../theme/formControls.mjs';
6
6
 
7
- // TODO: forwardRef
8
- const PinInput = ({ value, onChange, inputStyle, autoFocus = true, isNumberOnly = true, ...rest }) => {
9
- const pinInputRef = useRef(null);
10
- const primaryColor = useToken('colors', 'primary.main')[0];
11
- const grayColor = useToken('colors', 'border.default')[0];
12
- useEffect(() => {
13
- // Automatically focus the PinInput component on mount
14
- if (autoFocus)
15
- pinInputRef.current?.focus();
16
- }, []);
17
- return (jsx(ReactPinInput, { ref: pinInputRef, initialValue: value, onChange: onChange, type: isNumberOnly ? 'numeric' : 'custom', inputMode: isNumberOnly ? 'number' : 'text', inputStyle: {
18
- borderColor: grayColor,
19
- borderRadius: '8px',
20
- width: '48px',
21
- height: '48px',
22
- ...inputStyle,
23
- }, inputFocusStyle: {
24
- borderColor: primaryColor,
25
- boxShadow: `0 0 0 1px ${primaryColor}`,
26
- }, onComplete: onChange, autoSelect: true, regexCriteria: isNumberOnly ? /^[0-9]*$/ : undefined, ...rest }));
27
- };
7
+ const PinInput = forwardRef(function PinInput({ length, value, onChange, onComplete, placeholder = '', inputProps, ...rest }, ref) {
8
+ const valueArray = Array.from({ length }, (_, i) => value?.[i] ?? '');
9
+ return (jsxs(PinInput$1.Root, { count: length, value: valueArray, onValueChange: (d) => onChange?.(d.valueAsString), onValueComplete: (d) => onComplete?.(d.valueAsString), placeholder: placeholder, ...rest, children: [jsx(PinInput$1.HiddenInput, { ref: ref, ...inputProps }), jsx(PinInput$1.Control, { children: Array.from({ length }).map((_, i) => (jsx(PinInput$1.Input, { index: i, w: 12, h: 12, fontSize: "lg", borderRadius: "md", bg: "bg.surface", color: "fg.default", borderColor: "border.default", _hover: { borderColor: 'primary.lighter' }, _focus: { borderColor: 'primary.main' }, _invalid: { borderColor: 'danger.main' }, _disabled: { borderColor: 'border.subtle', bg: 'bg.subtle' }, css: noZoomOnFocus }, i))) })] }));
10
+ });
28
11
  PinInput.displayName = 'PinInput';
29
12
 
30
13
  export { PinInput };
@@ -1 +1 @@
1
- {"version":3,"file":"PinInput.mjs","sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;;;AAMA;AACO,MAAM,QAAQ,GAAG,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,UAAU,EACV,SAAS,GAAG,IAAI,EAChB,YAAY,GAAG,IAAI,EACnB,GAAG,IAAI,EACO,KAAI;AAClB,IAAA,MAAM,WAAW,GAAG,MAAM,CAAgB,IAAI,CAAC;IAC/C,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEzD,SAAS,CAAC,MAAK;;AAEb,QAAA,IAAI,SAAS;AAAE,YAAA,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE;IAC7C,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,QACEA,GAAA,CAAC,aAAa,IACZ,GAAG,EAAE,WAAW,EAChB,YAAY,EAAE,KAAK,EACnB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,YAAY,GAAG,SAAS,GAAG,QAAQ,EACzC,SAAS,EAAE,YAAY,GAAG,QAAQ,GAAG,MAAM,EAC3C,UAAU,EAAE;AACV,YAAA,WAAW,EAAE,SAAS;AACtB,YAAA,YAAY,EAAE,KAAK;AACnB,YAAA,KAAK,EAAE,MAAM;AACb,YAAA,MAAM,EAAE,MAAM;AACd,YAAA,GAAG,UAAU;AACd,SAAA,EACD,eAAe,EAAE;AACf,YAAA,WAAW,EAAE,YAAY;YACzB,SAAS,EAAE,CAAA,UAAA,EAAa,YAAY,CAAA,CAAE;SACvC,EACD,UAAU,EAAE,QAAQ,EACpB,UAAU,EAAA,IAAA,EACV,aAAa,EAAE,YAAY,GAAG,UAAU,GAAG,SAAS,EAAA,GAChD,IAAI,EAAA,CACR;AAEN;AAEA,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
1
+ {"version":3,"file":"PinInput.mjs","sources":["../../../src/components/PinInput/PinInput.tsx"],"sourcesContent":[null],"names":["_jsxs","ChakraPinInput","_jsx"],"mappings":";;;;;;AASO,MAAM,QAAQ,GAAG,UAAU,CAChC,SAAS,QAAQ,CACf,EACE,MAAM,EACN,KAAK,EACL,QAAQ,EACR,UAAU,EACV,WAAW,GAAG,EAAE,EAChB,UAAU,EACV,GAAG,IAAI,EACR,EACD,GAAG,EAAA;IAEH,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAErE,IAAA,QACEA,IAAA,CAACC,UAAc,CAAC,IAAI,IAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,UAAU,EACjB,aAAa,EAAE,CAAC,CAAC,KAAK,QAAQ,GAAG,CAAC,CAAC,aAAa,CAAC,EACjD,eAAe,EAAE,CAAC,CAAC,KAAK,UAAU,GAAG,CAAC,CAAC,aAAa,CAAC,EACrD,WAAW,EAAE,WAAW,EAAA,GACpB,IAAI,aAERC,GAAA,CAACD,UAAc,CAAC,WAAW,IAAC,GAAG,EAAE,GAAG,EAAA,GAAM,UAAU,GAAI,EACxDC,GAAA,CAACD,UAAc,CAAC,OAAO,EAAA,EAAA,QAAA,EACpB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAC/BC,GAAA,CAACD,UAAc,CAAC,KAAK,EAAA,EAEnB,KAAK,EAAE,CAAC,EACR,CAAC,EAAE,EAAE,EACL,CAAC,EAAE,EAAE,EACL,QAAQ,EAAC,IAAI,EACb,YAAY,EAAC,IAAI,EACjB,EAAE,EAAC,YAAY,EACf,KAAK,EAAC,YAAY,EAClB,WAAW,EAAC,gBAAgB,EAC5B,MAAM,EAAE,EAAE,WAAW,EAAE,iBAAiB,EAAE,EAC1C,MAAM,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,EACvC,QAAQ,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EACxC,SAAS,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,EAAE,WAAW,EAAE,EAC5D,GAAG,EAAE,aAAa,EAAA,EAbb,CAAC,CAcN,CACH,CAAC,EAAA,CACqB,CAAA,EAAA,CACL;AAE1B,CAAC;AAGH,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
@@ -1,27 +1,10 @@
1
- interface ReactPinInputProps {
1
+ import type { InputHTMLAttributes } from 'react';
2
+ import type { PinInput as ChakraPinInput } from '@chakra-ui/react';
3
+ export interface PinInputProps extends Omit<ChakraPinInput.RootProps, 'count' | 'value' | 'defaultValue' | 'onValueChange' | 'onValueComplete' | 'onChange' | 'children'> {
2
4
  length: number;
3
- initialValue?: number | string;
4
- type?: 'numeric' | 'custom';
5
- inputMode?: string;
6
- secret?: boolean;
7
- secretDelay?: number;
8
- disabled?: boolean;
9
- focus?: boolean;
10
- onChange?: (value: string, index: number) => void;
11
- onComplete?: (value: string, index: number) => void;
12
- style?: React.CSSProperties;
13
- inputStyle?: React.CSSProperties;
14
- inputFocusStyle?: React.CSSProperties;
15
- validate?: (value: string) => string;
16
- autoSelect?: boolean;
17
- regexCriteria?: any;
18
- ariaLabel?: string;
19
- placeholder?: string;
20
- }
21
- export type PinInputProps = ReactPinInputProps & {
22
5
  value?: string;
23
- autoFocus?: boolean;
24
- isNumberOnly?: boolean;
25
- };
26
- export {};
6
+ onChange?: (value: string) => void;
7
+ onComplete?: (value: string) => void;
8
+ inputProps?: InputHTMLAttributes<HTMLInputElement>;
9
+ }
27
10
  //# sourceMappingURL=PinInput.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PinInput.types.d.ts","sourceRoot":"","sources":["../../../src/components/PinInput/PinInput.types.ts"],"names":[],"mappings":"AACA,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACjC,eAAe,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACtC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,aAAa,GAAG,kBAAkB,GAAG;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC"}
1
+ {"version":3,"file":"PinInput.types.d.ts","sourceRoot":"","sources":["../../../src/components/PinInput/PinInput.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEnE,MAAM,WAAW,aAAc,SAAQ,IAAI,CACzC,cAAc,CAAC,SAAS,EACtB,OAAO,GACP,OAAO,GACP,cAAc,GACd,eAAe,GACf,iBAAiB,GACjB,UAAU,GACV,UAAU,CACb;IACC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,UAAU,CAAC,EAAE,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;CACpD"}
@@ -27,16 +27,14 @@ import type { SystemStyleObject } from '@chakra-ui/react';
27
27
  * browser zoom has a ~640px CSS viewport, so a width rule enlarges their form
28
28
  * controls and pushes wide tables off-screen, making the low-vision case worse.
29
29
  *
30
- * `Input` and `Textarea` already spread this, so their call sites need nothing,
31
- * and `PasswordInput` composes `Input` so it inherits.
30
+ * `Input`, `Textarea` and `PinInput` already spread this, so their call sites
31
+ * need nothing, and `PasswordInput` composes `Input` so it inherits.
32
32
  *
33
- * Two components deliberately do NOT, because the zoom does not reach them.
34
- * `Select` is a listbox — a `<button>` trigger over a portalled list, plus a
33
+ * `Select` deliberately does NOT, because the zoom does not reach it. It is a
34
+ * listbox — a `<button>` trigger over a portalled list, plus a
35
35
  * visually hidden native `<select>` that exists only for form submission and
36
36
  * never takes visible focus; Safari zooms toward text entry, not toward a
37
- * button. `PinInput` wraps `react-pin-input`, which takes an inline `style`
38
- * object, and an inline style cannot carry a media query at all — a consumer
39
- * that builds OTP boxes on `ChakraPinInput` instead has to spread this itself.
37
+ * button.
40
38
  *
41
39
  * Spread it yourself on any editable surface the design system does not own —
42
40
  * a Lexical/ProseMirror `contenteditable`, a bare Chakra `Input`, or a
@@ -1 +1 @@
1
- {"version":3,"file":"formControls.d.ts","sourceRoot":"","sources":["../../src/theme/formControls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,eAAO,MAAM,aAAa,EAAE,iBAE3B,CAAC"}
1
+ {"version":3,"file":"formControls.d.ts","sourceRoot":"","sources":["../../src/theme/formControls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,eAAO,MAAM,aAAa,EAAE,iBAE3B,CAAC"}
@@ -29,16 +29,14 @@
29
29
  * browser zoom has a ~640px CSS viewport, so a width rule enlarges their form
30
30
  * controls and pushes wide tables off-screen, making the low-vision case worse.
31
31
  *
32
- * `Input` and `Textarea` already spread this, so their call sites need nothing,
33
- * and `PasswordInput` composes `Input` so it inherits.
32
+ * `Input`, `Textarea` and `PinInput` already spread this, so their call sites
33
+ * need nothing, and `PasswordInput` composes `Input` so it inherits.
34
34
  *
35
- * Two components deliberately do NOT, because the zoom does not reach them.
36
- * `Select` is a listbox — a `<button>` trigger over a portalled list, plus a
35
+ * `Select` deliberately does NOT, because the zoom does not reach it. It is a
36
+ * listbox — a `<button>` trigger over a portalled list, plus a
37
37
  * visually hidden native `<select>` that exists only for form submission and
38
38
  * never takes visible focus; Safari zooms toward text entry, not toward a
39
- * button. `PinInput` wraps `react-pin-input`, which takes an inline `style`
40
- * object, and an inline style cannot carry a media query at all — a consumer
41
- * that builds OTP boxes on `ChakraPinInput` instead has to spread this itself.
39
+ * button.
42
40
  *
43
41
  * Spread it yourself on any editable surface the design system does not own —
44
42
  * a Lexical/ProseMirror `contenteditable`, a bare Chakra `Input`, or a
@@ -1 +1 @@
1
- {"version":3,"file":"formControls.js","sources":["../../src/theme/formControls.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDG;AACI,MAAM,aAAa,GAAsB;AAC9C,IAAA,0BAA0B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;;;;;"}
1
+ {"version":3,"file":"formControls.js","sources":["../../src/theme/formControls.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDG;AACI,MAAM,aAAa,GAAsB;AAC9C,IAAA,0BAA0B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;;;;;"}
@@ -27,16 +27,14 @@
27
27
  * browser zoom has a ~640px CSS viewport, so a width rule enlarges their form
28
28
  * controls and pushes wide tables off-screen, making the low-vision case worse.
29
29
  *
30
- * `Input` and `Textarea` already spread this, so their call sites need nothing,
31
- * and `PasswordInput` composes `Input` so it inherits.
30
+ * `Input`, `Textarea` and `PinInput` already spread this, so their call sites
31
+ * need nothing, and `PasswordInput` composes `Input` so it inherits.
32
32
  *
33
- * Two components deliberately do NOT, because the zoom does not reach them.
34
- * `Select` is a listbox — a `<button>` trigger over a portalled list, plus a
33
+ * `Select` deliberately does NOT, because the zoom does not reach it. It is a
34
+ * listbox — a `<button>` trigger over a portalled list, plus a
35
35
  * visually hidden native `<select>` that exists only for form submission and
36
36
  * never takes visible focus; Safari zooms toward text entry, not toward a
37
- * button. `PinInput` wraps `react-pin-input`, which takes an inline `style`
38
- * object, and an inline style cannot carry a media query at all — a consumer
39
- * that builds OTP boxes on `ChakraPinInput` instead has to spread this itself.
37
+ * button.
40
38
  *
41
39
  * Spread it yourself on any editable surface the design system does not own —
42
40
  * a Lexical/ProseMirror `contenteditable`, a bare Chakra `Input`, or a
@@ -1 +1 @@
1
- {"version":3,"file":"formControls.mjs","sources":["../../src/theme/formControls.ts"],"sourcesContent":[null],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDG;AACI,MAAM,aAAa,GAAsB;AAC9C,IAAA,0BAA0B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;;;;;"}
1
+ {"version":3,"file":"formControls.mjs","sources":["../../src/theme/formControls.ts"],"sourcesContent":[null],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDG;AACI,MAAM,aAAa,GAAsB;AAC9C,IAAA,0BAA0B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;;;;;"}
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var lodash = require('lodash');
4
+ var merge = require('lodash/merge');
5
5
 
6
6
  const mergeCss = (...styles) => styles.reduce((acc, style) => {
7
7
  if (style && typeof style === 'object') {
8
- lodash.merge(acc, style);
8
+ merge(acc, style);
9
9
  }
10
10
  return acc;
11
11
  }, {});
@@ -1 +1 @@
1
- {"version":3,"file":"mergeCss.js","sources":["../../src/utils/mergeCss.ts"],"sourcesContent":[null],"names":["merge"],"mappings":";;;;;AAGO,MAAM,QAAQ,GAAG,CACtB,GAAG,MAAwD,KAE3D,MAAM,CAAC,MAAM,CAAoB,CAAC,GAAG,EAAE,KAAK,KAAI;AAC9C,IAAA,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AACtC,QAAAA,YAAK,CAAC,GAAG,EAAE,KAAK,CAAC;IACnB;AACA,IAAA,OAAO,GAAG;AACZ,CAAC,EAAE,EAAuB;;;;"}
1
+ {"version":3,"file":"mergeCss.js","sources":["../../src/utils/mergeCss.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;AAGO,MAAM,QAAQ,GAAG,CACtB,GAAG,MAAwD,KAE3D,MAAM,CAAC,MAAM,CAAoB,CAAC,GAAG,EAAE,KAAK,KAAI;AAC9C,IAAA,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AACtC,QAAA,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC;IACnB;AACA,IAAA,OAAO,GAAG;AACZ,CAAC,EAAE,EAAuB;;;;"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { merge } from 'lodash';
2
+ import merge from 'lodash/merge';
3
3
 
4
4
  const mergeCss = (...styles) => styles.reduce((acc, style) => {
5
5
  if (style && typeof style === 'object') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindlogic-ai/logician-ui",
3
- "version": "4.0.0-alpha.38",
3
+ "version": "4.0.0-alpha.40",
4
4
  "description": "A comprehensive React design system built on Chakra UI",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -77,7 +77,6 @@
77
77
  "next-themes": "^0.4.6",
78
78
  "polished": "^4.3.0",
79
79
  "react-markdown": "^10.1.0",
80
- "react-pin-input": "^1.3.0",
81
80
  "recharts": "^3.1.2",
82
81
  "rehype-katex": "^7.0.1",
83
82
  "rehype-raw": "^7.0.0",
@@ -11,6 +11,14 @@ const meta = {
11
11
  },
12
12
  argTypes: {
13
13
  length: { control: 'number' },
14
+ type: {
15
+ control: 'select',
16
+ options: ['numeric', 'alphanumeric', 'alphabetic'],
17
+ },
18
+ autoFocus: { control: 'boolean' },
19
+ otp: { control: 'boolean' },
20
+ disabled: { control: 'boolean' },
21
+ invalid: { control: 'boolean' },
14
22
  },
15
23
  } satisfies Meta<typeof PinInput>;
16
24
 
@@ -18,13 +26,32 @@ export default meta;
18
26
 
19
27
  type Story = StoryObj<typeof PinInput>;
20
28
 
21
- export const Basic: Story = {
22
- args: {
23
- length: 5,
24
- },
25
- render: (args) => {
26
- const [value, setValue] = useState('');
29
+ const Controlled = (args: React.ComponentProps<typeof PinInput>) => {
30
+ const [value, setValue] = useState('');
31
+ return <PinInput {...args} value={value} onChange={setValue} />;
32
+ };
27
33
 
28
- return <PinInput {...args} value={value} onChange={setValue} />;
29
- },
30
- }
34
+ export const Numeric: Story = {
35
+ args: { length: 6, type: 'numeric' },
36
+ render: (args) => <Controlled {...args} />,
37
+ };
38
+
39
+ export const Alphanumeric: Story = {
40
+ args: { length: 6, type: 'alphanumeric' },
41
+ render: (args) => <Controlled {...args} />,
42
+ };
43
+
44
+ export const Otp: Story = {
45
+ args: { length: 6, type: 'numeric', otp: true, autoFocus: true },
46
+ render: (args) => <Controlled {...args} />,
47
+ };
48
+
49
+ export const Disabled: Story = {
50
+ args: { length: 5, disabled: true },
51
+ render: (args) => <Controlled {...args} />,
52
+ };
53
+
54
+ export const Invalid: Story = {
55
+ args: { length: 5, invalid: true },
56
+ render: (args) => <Controlled {...args} />,
57
+ };
@@ -1,51 +1,60 @@
1
- import React, { useEffect, useRef } from 'react';
2
- import ReactPinInput from 'react-pin-input';
3
- import { useToken } from '@chakra-ui/react';
1
+ 'use client';
4
2
 
5
- import { PinInputProps } from './PinInput.types';
3
+ import { forwardRef } from 'react';
4
+ import { PinInput as ChakraPinInput } from '@chakra-ui/react';
5
+
6
+ import { noZoomOnFocus } from '@/theme/formControls';
6
7
 
7
- // TODO: forwardRef
8
- export const PinInput = ({
9
- value,
10
- onChange,
11
- inputStyle,
12
- autoFocus = true,
13
- isNumberOnly = true,
14
- ...rest
15
- }: PinInputProps) => {
16
- const pinInputRef = useRef<ReactPinInput>(null);
17
- const primaryColor = useToken('colors', 'primary.main')[0];
18
- const grayColor = useToken('colors', 'border.default')[0];
8
+ import { PinInputProps } from './PinInput.types';
19
9
 
20
- useEffect(() => {
21
- // Automatically focus the PinInput component on mount
22
- if (autoFocus) pinInputRef.current?.focus();
23
- }, []);
10
+ export const PinInput = forwardRef<HTMLInputElement, PinInputProps>(
11
+ function PinInput(
12
+ {
13
+ length,
14
+ value,
15
+ onChange,
16
+ onComplete,
17
+ placeholder = '',
18
+ inputProps,
19
+ ...rest
20
+ },
21
+ ref
22
+ ) {
23
+ const valueArray = Array.from({ length }, (_, i) => value?.[i] ?? '');
24
24
 
25
- return (
26
- <ReactPinInput
27
- ref={pinInputRef} // Attach the ref to the PinInput component
28
- initialValue={value}
29
- onChange={onChange}
30
- type={isNumberOnly ? 'numeric' : 'custom'}
31
- inputMode={isNumberOnly ? 'number' : 'text'}
32
- inputStyle={{
33
- borderColor: grayColor,
34
- borderRadius: '8px',
35
- width: '48px',
36
- height: '48px',
37
- ...inputStyle,
38
- }}
39
- inputFocusStyle={{
40
- borderColor: primaryColor,
41
- boxShadow: `0 0 0 1px ${primaryColor}`,
42
- }}
43
- onComplete={onChange}
44
- autoSelect
45
- regexCriteria={isNumberOnly ? /^[0-9]*$/ : undefined}
46
- {...rest}
47
- />
48
- );
49
- };
25
+ return (
26
+ <ChakraPinInput.Root
27
+ count={length}
28
+ value={valueArray}
29
+ onValueChange={(d) => onChange?.(d.valueAsString)}
30
+ onValueComplete={(d) => onComplete?.(d.valueAsString)}
31
+ placeholder={placeholder}
32
+ {...rest}
33
+ >
34
+ <ChakraPinInput.HiddenInput ref={ref} {...inputProps} />
35
+ <ChakraPinInput.Control>
36
+ {Array.from({ length }).map((_, i) => (
37
+ <ChakraPinInput.Input
38
+ key={i}
39
+ index={i}
40
+ w={12}
41
+ h={12}
42
+ fontSize="lg"
43
+ borderRadius="md"
44
+ bg="bg.surface"
45
+ color="fg.default"
46
+ borderColor="border.default"
47
+ _hover={{ borderColor: 'primary.lighter' }}
48
+ _focus={{ borderColor: 'primary.main' }}
49
+ _invalid={{ borderColor: 'danger.main' }}
50
+ _disabled={{ borderColor: 'border.subtle', bg: 'bg.subtle' }}
51
+ css={noZoomOnFocus}
52
+ />
53
+ ))}
54
+ </ChakraPinInput.Control>
55
+ </ChakraPinInput.Root>
56
+ );
57
+ }
58
+ );
50
59
 
51
60
  PinInput.displayName = 'PinInput';
@@ -1,27 +1,19 @@
1
- // TODO: This interface is copied from the react-pin-input package. Find a more scalable way to import this interface if it gets updated
2
- interface ReactPinInputProps {
3
- length: number;
4
- initialValue?: number | string;
5
- type?: 'numeric' | 'custom';
6
- inputMode?: string;
7
- secret?: boolean;
8
- secretDelay?: number;
9
- disabled?: boolean;
10
- focus?: boolean;
11
- onChange?: (value: string, index: number) => void;
12
- onComplete?: (value: string, index: number) => void;
13
- style?: React.CSSProperties;
14
- inputStyle?: React.CSSProperties;
15
- inputFocusStyle?: React.CSSProperties;
16
- validate?: (value: string) => string;
17
- autoSelect?: boolean;
18
- regexCriteria?: any;
19
- ariaLabel?: string;
20
- placeholder?: string;
21
- }
1
+ import type { InputHTMLAttributes } from 'react';
2
+ import type { PinInput as ChakraPinInput } from '@chakra-ui/react';
22
3
 
23
- export type PinInputProps = ReactPinInputProps & {
4
+ export interface PinInputProps extends Omit<
5
+ ChakraPinInput.RootProps,
6
+ | 'count'
7
+ | 'value'
8
+ | 'defaultValue'
9
+ | 'onValueChange'
10
+ | 'onValueComplete'
11
+ | 'onChange'
12
+ | 'children'
13
+ > {
14
+ length: number;
24
15
  value?: string;
25
- autoFocus?: boolean;
26
- isNumberOnly?: boolean;
27
- };
16
+ onChange?: (value: string) => void;
17
+ onComplete?: (value: string) => void;
18
+ inputProps?: InputHTMLAttributes<HTMLInputElement>;
19
+ }
@@ -28,16 +28,14 @@ import type { SystemStyleObject } from '@chakra-ui/react';
28
28
  * browser zoom has a ~640px CSS viewport, so a width rule enlarges their form
29
29
  * controls and pushes wide tables off-screen, making the low-vision case worse.
30
30
  *
31
- * `Input` and `Textarea` already spread this, so their call sites need nothing,
32
- * and `PasswordInput` composes `Input` so it inherits.
31
+ * `Input`, `Textarea` and `PinInput` already spread this, so their call sites
32
+ * need nothing, and `PasswordInput` composes `Input` so it inherits.
33
33
  *
34
- * Two components deliberately do NOT, because the zoom does not reach them.
35
- * `Select` is a listbox — a `<button>` trigger over a portalled list, plus a
34
+ * `Select` deliberately does NOT, because the zoom does not reach it. It is a
35
+ * listbox — a `<button>` trigger over a portalled list, plus a
36
36
  * visually hidden native `<select>` that exists only for form submission and
37
37
  * never takes visible focus; Safari zooms toward text entry, not toward a
38
- * button. `PinInput` wraps `react-pin-input`, which takes an inline `style`
39
- * object, and an inline style cannot carry a media query at all — a consumer
40
- * that builds OTP boxes on `ChakraPinInput` instead has to spread this itself.
38
+ * button.
41
39
  *
42
40
  * Spread it yourself on any editable surface the design system does not own —
43
41
  * a Lexical/ProseMirror `contenteditable`, a bare Chakra `Input`, or a
@@ -1,5 +1,5 @@
1
1
  import type { SystemStyleObject } from '@chakra-ui/react';
2
- import { merge } from 'lodash';
2
+ import merge from 'lodash/merge';
3
3
 
4
4
  export const mergeCss = (
5
5
  ...styles: (SystemStyleObject | undefined | null | false)[]