@ahrowe/ui 0.16.1 → 0.16.3

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,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../bodyEnd/bodyEnd.mjs";import{useFloatingPosition as n}from"../floatingMenu/useFloatingPosition.mjs";import r from"../input/input.mjs";import i from"./inputDropdown.module.mjs";import{useCallback as a,useRef as o,useState as s}from"react";import c from"classnames";import{jsx as l,jsxs as u}from"react/jsx-runtime";function d(e,t){return t?t.value??``:e??``}function f(e,t){let n=t.find(t=>t.value===e);return n?n.label??n.value:e}function p(p){let{label:m=``,value:h=``,formValidator:g=null,items:_=[],allowCustomValue:v=!1,className:y,style:b,classNames:x,styles:S,onSelect:C=()=>null,onChange:w,placeholder:T=``,readOnly:E=!1,...D}=e(`InputDropdown`,p),O=d(h,g),[k,A]=s(()=>f(O,_)),[j,M]=s(O),[N,P]=s(!1),[F,I]=s(null),L=o(null),R=o(null),z=o(null);if(n({isOpen:N,triggerRef:R,anchorRef:z,panelRef:z,flipClassName:i.dropdownFlip}),O!==j){M(O);let e=_.find(e=>e.value===O);e?A(e.label??e.value):v&&A(O)}let B=_.filter(e=>(e.label??e.value).toLowerCase().includes(k.toLowerCase())),V=()=>{E||(L.current&&=(clearTimeout(L.current),null),P(!0))},H=()=>{L.current=setTimeout(()=>{P(!1),L.current=null,v||A(f(O,_))},100)},U=a(e=>{A(e.label??e.value),P(!1),I(null),g&&g.set(e.value),w&&w(e.value),C(e.value)},[g,w,C]),W=a(e=>{E||(e.key===`ArrowUp`?(e.preventDefault(),I(e=>e?e-1:null)):e.key===`ArrowDown`?(e.preventDefault(),I(e=>e===null?0:Math.min(e+1,B.length-1))):e.key===`Enter`&&(F!==null&&B[F]?U(B[F]):v&&(P(!1),I(null))))},[B,F,U,v,E]);return u(`div`,{...D,ref:R,className:c(i.inputDropdown,x?.root,y),style:{...S?.root,...b},onFocus:V,onBlur:H,onKeyDown:W,children:[l(r,{label:m,value:k,readOnly:E,onChange:e=>{if(A(e),I(null),P(!0),v)g&&g.set(e),w&&w(e);else if(e===``)g&&g.set(``),w&&w(``),C(``);else{let t=_.find(t=>(t.label??t.value).toLowerCase()===e.toLowerCase());t&&(g&&g.set(t.value),w&&w(t.value),C(t.value))}},placeholder:T}),N&&!E&&l(t,{children:l(`div`,{ref:z,className:c(i.dropdown,i.dropdownShown,x?.dropdown),style:S?.dropdown,children:l(`div`,{className:i.dropdownScroll,children:B.map((e,t)=>l(`div`,{className:c(i.dropdownItem,F===t&&i.dropdownItemHighlighted,x?.item),style:S?.item,onMouseDown:e=>e.preventDefault(),onClick:()=>U(e),children:e.label??e.value},`${t}_${e.label}_${e.value}`))})})})]})}export{p as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../bodyEnd/bodyEnd.mjs";import{useFloatingPosition as n}from"../floatingMenu/useFloatingPosition.mjs";import r from"../input/input.mjs";import i from"./inputDropdown.module.mjs";import{useCallback as a,useEffect as o,useRef as s,useState as c}from"react";import l from"classnames";import{jsx as u,jsxs as d}from"react/jsx-runtime";function f(e,t){return t?t.value??``:e??``}function p(e,t){let n=t.find(t=>t.value===e);return n?n.label??n.value:e}function m(m){let{label:h=``,value:g=``,formValidator:_=null,error:v,isRequired:y=!1,items:b=[],allowCustomValue:x=!1,className:S,style:C,classNames:w,styles:T,onSelect:E=()=>null,onChange:D,placeholder:O=``,readOnly:k=!1,...A}=e(`InputDropdown`,m),j=f(g,_),[,M]=c(0),N=s(_);o(()=>{if(N.current=_,!_)return;let e=()=>M(e=>e+1);return _.registerOnUpdateListener(e),()=>{_.removeOnUpdateListener(e)}},[_]);let P=y||!!_?.validators.find(e=>e.validatorId===`required`),[F,I]=c(()=>p(j,b)),[L,R]=c(j),[z,B]=c(!1),[V,H]=c(null),U=s(null),W=s(null),G=s(null);if(n({isOpen:z,triggerRef:W,anchorRef:G,panelRef:G,flipClassName:i.dropdownFlip}),j!==L){R(j);let e=b.find(e=>e.value===j);e?I(e.label??e.value):x&&I(j)}let K=b.filter(e=>(e.label??e.value).toLowerCase().includes(F.toLowerCase())),q=()=>{k||(U.current&&=(clearTimeout(U.current),null),B(!0))},J=()=>{N.current&&(N.current.touched=!0),U.current=setTimeout(()=>{B(!1),U.current=null,x||I(p(j,b))},100)},Y=a(e=>{I(e.label??e.value),B(!1),H(null),_&&_.set(e.value),D&&D(e.value),E(e.value)},[_,D,E]),X=a(e=>{k||(e.key===`ArrowUp`?(e.preventDefault(),H(e=>e?e-1:null)):e.key===`ArrowDown`?(e.preventDefault(),H(e=>e===null?0:Math.min(e+1,K.length-1))):e.key===`Enter`&&(V!==null&&K[V]?Y(K[V]):x&&(B(!1),H(null))))},[K,V,Y,x,k]);return d(`div`,{...A,ref:W,className:l(i.inputDropdown,w?.root,S),style:{...T?.root,...C},onFocus:q,onBlur:J,onKeyDown:X,children:[u(r,{label:h,value:F,readOnly:k,formValidator:null,isRequired:P,isValid:_?_.touched?!_.hasError():!0:!v,errorMessage:_?_.touched?_.getCurrentErrorMessage()??``:``:v??``,onChange:e=>{if(I(e),H(null),B(!0),x)_&&_.set(e),D&&D(e);else if(e===``)_&&_.set(``),D&&D(``),E(``);else{let t=b.find(t=>(t.label??t.value).toLowerCase()===e.toLowerCase());t&&(_&&_.set(t.value),D&&D(t.value),E(t.value))}},placeholder:O}),z&&!k&&u(t,{children:u(`div`,{ref:G,className:l(i.dropdown,i.dropdownShown,w?.dropdown),style:T?.dropdown,children:u(`div`,{className:i.dropdownScroll,children:K.map((e,t)=>u(`div`,{className:l(i.dropdownItem,V===t&&i.dropdownItemHighlighted,w?.item),style:T?.item,onMouseDown:e=>e.preventDefault(),onClick:()=>Y(e),children:e.label??e.value},`${t}_${e.label}_${e.value}`))})})})]})}export{m as default};
2
2
  //# sourceMappingURL=inputDropdown.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"inputDropdown.mjs","names":[],"sources":["../../../../package/common/inputDropdown/inputDropdown.tsx"],"sourcesContent":["import React, { useCallback, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\nimport styles from './inputDropdown.module.pcss';\nimport Input from '../input';\nimport { useFloatingPosition } from '../floatingMenu/useFloatingPosition';\nimport { useComponentDefaults } from '../configProvider';\nimport type { InputDropdownItem, InputDropdownProps } from './inputDropdown.types';\n\nfunction getKeyFromProps(value: string | undefined, formValidator: InputDropdownProps['formValidator']): string {\n return formValidator ? (formValidator.value as string) ?? '' : (value ?? '');\n}\n\nfunction labelForKey(key: string, items: InputDropdownItem[]): string {\n const match = items.find((item) => item.value === key);\n return match ? (match.label ?? match.value) : key;\n}\n\nexport default function InputDropdown(props: InputDropdownProps) {\n const {\n label = '',\n value = '',\n formValidator = null,\n items = [],\n allowCustomValue = false,\n className,\n style,\n classNames,\n styles: slotStyles,\n onSelect = () => null,\n onChange,\n placeholder = '',\n readOnly = false,\n ...rest\n } = useComponentDefaults('InputDropdown', props);\n const currentKey = getKeyFromProps(value, formValidator);\n\n const [inputText, setInputText] = useState(() => labelForKey(currentKey, items));\n const [prevKey, setPrevKey] = useState(currentKey);\n const [isMenuShown, setIsMenuShown] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState<number | null>(null);\n const hideTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLDivElement>(null);\n\n useFloatingPosition({\n isOpen: isMenuShown,\n triggerRef,\n anchorRef,\n panelRef: anchorRef,\n flipClassName: styles.dropdownFlip,\n });\n\n // Sync display text when the controlled key changes externally (e.g. parent reset).\n if (currentKey !== prevKey) {\n setPrevKey(currentKey);\n const match = items.find((item) => item.value === currentKey);\n if (match) setInputText(match.label ?? match.value);\n else if (allowCustomValue) setInputText(currentKey);\n }\n\n const currItems = items.filter((item) =>\n (item.label ?? item.value).toLowerCase().includes(inputText.toLowerCase())\n );\n\n const handleFocus = () => {\n if (readOnly) return;\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n setIsMenuShown(true);\n };\n\n const handleBlur = () => {\n hideTimeoutRef.current = setTimeout(() => {\n setIsMenuShown(false);\n hideTimeoutRef.current = null;\n // Without custom values, uncommitted typed text is invalid — snap the\n // display back to the currently selected item's label.\n if (!allowCustomValue) setInputText(labelForKey(currentKey, items));\n }, 100);\n };\n\n const handleSelect = useCallback((item: InputDropdownItem) => {\n setInputText(item.label ?? item.value);\n setIsMenuShown(false);\n setHighlightedIndex(null);\n if (formValidator) formValidator.set(item.value);\n if (onChange) onChange(item.value);\n onSelect(item.value);\n }, [formValidator, onChange, onSelect]);\n\n const onKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (readOnly) return;\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n setHighlightedIndex((idx) => (!idx ? null : idx - 1));\n } else if (event.key === 'ArrowDown') {\n event.preventDefault();\n setHighlightedIndex((idx) =>\n idx === null ? 0 : Math.min(idx + 1, currItems.length - 1)\n );\n } else if (event.key === 'Enter') {\n if (highlightedIndex !== null && currItems[highlightedIndex]) {\n handleSelect(currItems[highlightedIndex]);\n } else if (allowCustomValue) {\n setIsMenuShown(false);\n setHighlightedIndex(null);\n }\n }\n }, [currItems, highlightedIndex, handleSelect, allowCustomValue, readOnly]);\n\n return (\n <div\n {...rest}\n ref={triggerRef}\n className={cx(styles.inputDropdown, classNames?.root, className)}\n style={{ ...slotStyles?.root, ...style }}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={onKeyDown}\n >\n <Input\n label={label}\n value={inputText}\n readOnly={readOnly}\n onChange={(text) => {\n setInputText(text);\n setHighlightedIndex(null);\n setIsMenuShown(true);\n if (allowCustomValue) {\n if (formValidator) formValidator.set(text);\n if (onChange) onChange(text);\n } else if (text === '') {\n if (formValidator) formValidator.set('');\n if (onChange) onChange('');\n onSelect('');\n } else {\n // Emit when the typed text exactly matches an item's label/value.\n const match = items.find(\n (item) => (item.label ?? item.value).toLowerCase() === text.toLowerCase()\n );\n if (match) {\n if (formValidator) formValidator.set(match.value);\n if (onChange) onChange(match.value);\n onSelect(match.value);\n }\n }\n }}\n placeholder={placeholder}\n />\n {isMenuShown && !readOnly && (\n <BodyEnd>\n <div\n ref={anchorRef}\n className={cx(styles.dropdown, styles.dropdownShown, classNames?.dropdown)}\n style={slotStyles?.dropdown}\n >\n <div className={styles.dropdownScroll}>\n {currItems.map((item, key) => (\n <div\n key={`${key}_${item.label}_${item.value}`}\n className={cx(\n styles.dropdownItem,\n highlightedIndex === key && styles.dropdownItemHighlighted,\n classNames?.item\n )}\n style={slotStyles?.item}\n // Prevent the input from blurring before the click resolves.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleSelect(item)}\n >\n {item.label ?? item.value}\n </div>\n ))}\n </div>\n </div>\n </BodyEnd>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inputDropdown.mjs","names":[],"sources":["../../../../package/common/inputDropdown/inputDropdown.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\nimport styles from './inputDropdown.module.pcss';\nimport Input from '../input';\nimport { useFloatingPosition } from '../floatingMenu/useFloatingPosition';\nimport { useComponentDefaults } from '../configProvider';\nimport type { InputDropdownItem, InputDropdownProps } from './inputDropdown.types';\n\nfunction getKeyFromProps(value: string | undefined, formValidator: InputDropdownProps['formValidator']): string {\n return formValidator ? (formValidator.value as string) ?? '' : (value ?? '');\n}\n\nfunction labelForKey(key: string, items: InputDropdownItem[]): string {\n const match = items.find((item) => item.value === key);\n return match ? (match.label ?? match.value) : key;\n}\n\nexport default function InputDropdown(props: InputDropdownProps) {\n const {\n label = '',\n value = '',\n formValidator = null,\n error,\n isRequired = false,\n items = [],\n allowCustomValue = false,\n className,\n style,\n classNames,\n styles: slotStyles,\n onSelect = () => null,\n onChange,\n placeholder = '',\n readOnly = false,\n ...rest\n } = useComponentDefaults('InputDropdown', props);\n const currentKey = getKeyFromProps(value, formValidator);\n const [, forceUpdate] = useState(0);\n const fvRef = useRef(formValidator);\n\n useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n const listener = () => forceUpdate((n) => n + 1);\n formValidator.registerOnUpdateListener(listener);\n return () => { formValidator.removeOnUpdateListener(listener); };\n }, [formValidator]);\n\n const computedIsRequired = isRequired || !!formValidator?.validators.find(\n (v) => (v as { validatorId?: string }).validatorId === 'required'\n );\n\n const [inputText, setInputText] = useState(() => labelForKey(currentKey, items));\n const [prevKey, setPrevKey] = useState(currentKey);\n const [isMenuShown, setIsMenuShown] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState<number | null>(null);\n const hideTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLDivElement>(null);\n\n useFloatingPosition({\n isOpen: isMenuShown,\n triggerRef,\n anchorRef,\n panelRef: anchorRef,\n flipClassName: styles.dropdownFlip,\n });\n\n // Sync display text when the controlled key changes externally (e.g. parent reset).\n if (currentKey !== prevKey) {\n setPrevKey(currentKey);\n const match = items.find((item) => item.value === currentKey);\n if (match) setInputText(match.label ?? match.value);\n else if (allowCustomValue) setInputText(currentKey);\n }\n\n const currItems = items.filter((item) =>\n (item.label ?? item.value).toLowerCase().includes(inputText.toLowerCase())\n );\n\n const handleFocus = () => {\n if (readOnly) return;\n if (hideTimeoutRef.current) {\n clearTimeout(hideTimeoutRef.current);\n hideTimeoutRef.current = null;\n }\n setIsMenuShown(true);\n };\n\n const handleBlur = () => {\n if (fvRef.current) fvRef.current.touched = true;\n hideTimeoutRef.current = setTimeout(() => {\n setIsMenuShown(false);\n hideTimeoutRef.current = null;\n // Without custom values, uncommitted typed text is invalid — snap the\n // display back to the currently selected item's label.\n if (!allowCustomValue) setInputText(labelForKey(currentKey, items));\n }, 100);\n };\n\n const handleSelect = useCallback((item: InputDropdownItem) => {\n setInputText(item.label ?? item.value);\n setIsMenuShown(false);\n setHighlightedIndex(null);\n if (formValidator) formValidator.set(item.value);\n if (onChange) onChange(item.value);\n onSelect(item.value);\n }, [formValidator, onChange, onSelect]);\n\n const onKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (readOnly) return;\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n setHighlightedIndex((idx) => (!idx ? null : idx - 1));\n } else if (event.key === 'ArrowDown') {\n event.preventDefault();\n setHighlightedIndex((idx) =>\n idx === null ? 0 : Math.min(idx + 1, currItems.length - 1)\n );\n } else if (event.key === 'Enter') {\n if (highlightedIndex !== null && currItems[highlightedIndex]) {\n handleSelect(currItems[highlightedIndex]);\n } else if (allowCustomValue) {\n setIsMenuShown(false);\n setHighlightedIndex(null);\n }\n }\n }, [currItems, highlightedIndex, handleSelect, allowCustomValue, readOnly]);\n\n return (\n <div\n {...rest}\n ref={triggerRef}\n className={cx(styles.inputDropdown, classNames?.root, className)}\n style={{ ...slotStyles?.root, ...style }}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={onKeyDown}\n >\n <Input\n label={label}\n value={inputText}\n readOnly={readOnly}\n formValidator={null}\n isRequired={computedIsRequired}\n isValid={formValidator ? (formValidator.touched ? !formValidator.hasError() : true) : !error}\n errorMessage={formValidator ? (formValidator.touched ? (formValidator.getCurrentErrorMessage() ?? '') : '') : (error ?? '')}\n onChange={(text) => {\n setInputText(text);\n setHighlightedIndex(null);\n setIsMenuShown(true);\n if (allowCustomValue) {\n if (formValidator) formValidator.set(text);\n if (onChange) onChange(text);\n } else if (text === '') {\n if (formValidator) formValidator.set('');\n if (onChange) onChange('');\n onSelect('');\n } else {\n // Emit when the typed text exactly matches an item's label/value.\n const match = items.find(\n (item) => (item.label ?? item.value).toLowerCase() === text.toLowerCase()\n );\n if (match) {\n if (formValidator) formValidator.set(match.value);\n if (onChange) onChange(match.value);\n onSelect(match.value);\n }\n }\n }}\n placeholder={placeholder}\n />\n {isMenuShown && !readOnly && (\n <BodyEnd>\n <div\n ref={anchorRef}\n className={cx(styles.dropdown, styles.dropdownShown, classNames?.dropdown)}\n style={slotStyles?.dropdown}\n >\n <div className={styles.dropdownScroll}>\n {currItems.map((item, key) => (\n <div\n key={`${key}_${item.label}_${item.value}`}\n className={cx(\n styles.dropdownItem,\n highlightedIndex === key && styles.dropdownItemHighlighted,\n classNames?.item\n )}\n style={slotStyles?.item}\n // Prevent the input from blurring before the click resolves.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => handleSelect(item)}\n >\n {item.label ?? item.value}\n </div>\n ))}\n </div>\n </div>\n </BodyEnd>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../interactableDiv/index.mjs";import n from"../input/input.mjs";import r from"./numberInput.module.mjs";import"react";import i from"classnames";import{FontAwesomeIcon as a}from"@fortawesome/react-fontawesome";import{faChevronDown as o,faChevronUp as s}from"@fortawesome/free-solid-svg-icons";import{jsx as c,jsxs as l}from"react/jsx-runtime";import{NumericFormat as u}from"react-number-format";function d(d){let{value:f,onChange:p,formValidator:m,label:h,error:g,className:_,style:v,allowNegative:y=!1,decimalSeparator:b,thousandSeparator:x,prefix:S,suffix:C,decimalScale:w,fixedDecimalScale:T=!0,placeholder:E,sign:D,showArrows:O=!1,step:k=1,readOnly:A=!1,onKeyDown:j,...M}=e(`NumberInput`,d),N=m==null?f:m.value,P=D!=null&&N!=null?Math.abs(Number(N)):N,F=P==null?``:String(P);function I(e){let t=e;t!==void 0&&(D===`-`&&(t=-Math.abs(t)),D===`+`&&(t=Math.abs(t))),m?.set(t??null),p?.(t)}function L(e){if(A)return;let t=(N!=null&&N!==``?Number(N):0)+e;!y&&D!==`-`&&(t=Math.max(0,t)),D===`-`&&(t=Math.min(0,t)),I(t)}function R(e){if(A){j?.(e);return}if(e.key===`ArrowUp`){e.preventDefault(),L(e.shiftKey?k*10:k);return}if(e.key===`ArrowDown`){e.preventDefault(),L(e.shiftKey?-k*10:-k);return}j?.(e)}let z=D===`-`?`-`:D===`+`?`+`:S,B=O&&!A?l(`div`,{className:r.arrows,children:[c(t,{className:r.arrowBtn,tabIndex:-1,onMouseDown:e=>{e.preventDefault(),L(e.shiftKey?k*10:k)},children:c(a,{icon:s})}),c(t,{className:r.arrowBtn,tabIndex:-1,onMouseDown:e=>{e.preventDefault(),L(e.shiftKey?-k*10:-k)},children:c(a,{icon:o})})]}):null;return c(n,{label:h,className:i(r.numberInput,_),style:v,value:F,onChange:()=>{},formValidator:null,isValid:m?m.touched?!m.hasError():!0:!g,errorMessage:m?m.getCurrentErrorMessage()??``:g??``,placeholder:E,readOnly:A,suffix:B,inputMode:w===0?`numeric`:`decimal`,customInput:c(u,{onValueChange:e=>I(e.floatValue),allowNegative:D==null?y:!1,decimalSeparator:b,thousandSeparator:x,decimalScale:w,fixedDecimalScale:T,prefix:z,suffix:C,onKeyDown:O?R:j,...M})})}export{d as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../interactableDiv/index.mjs";import n from"../input/input.mjs";import r from"./numberInput.module.mjs";import i from"react";import a from"classnames";import{FontAwesomeIcon as o}from"@fortawesome/react-fontawesome";import{faChevronDown as s,faChevronUp as c}from"@fortawesome/free-solid-svg-icons";import{jsx as l,jsxs as u}from"react/jsx-runtime";import{NumericFormat as d}from"react-number-format";function f(f){let p=i.useRef(void 0),{value:m,onChange:h,formValidator:g,label:_,error:v,className:y,style:b,allowNegative:x=!1,decimalSeparator:S,thousandSeparator:C,prefix:w,suffix:T,decimalScale:E,fixedDecimalScale:D=!0,placeholder:O,sign:k,showArrows:A=!1,step:j=1,readOnly:M=!1,isRequired:N=!1,onKeyDown:P,...F}=e(`NumberInput`,f),[,I]=i.useState(0);i.useEffect(()=>{if(p.current=g,!g)return;let e=()=>I(e=>e+1);return g.registerOnUpdateListener(e),()=>{g.removeOnUpdateListener(e)}},[g]);let L=N||!!g?.validators.find(e=>e.validatorId===`required`),R=g==null?m:g.value,z=k!=null&&R!=null?Math.abs(Number(R)):R,B=z==null?``:String(z);function V(e){let t=e;t!==void 0&&(k===`-`&&(t=-Math.abs(t)),k===`+`&&(t=Math.abs(t))),g?.set(t??null),h?.(t)}function H(e){if(M)return;let t=(R!=null&&R!==``?Number(R):0)+e;!x&&k!==`-`&&(t=Math.max(0,t)),k===`-`&&(t=Math.min(0,t)),V(t)}function U(e){if(M){P?.(e);return}if(e.key===`ArrowUp`){e.preventDefault(),H(e.shiftKey?j*10:j);return}if(e.key===`ArrowDown`){e.preventDefault(),H(e.shiftKey?-j*10:-j);return}P?.(e)}let W=k===`-`?`-`:k===`+`?`+`:w,G=A&&!M?u(`div`,{className:r.arrows,children:[l(t,{className:r.arrowBtn,tabIndex:-1,onMouseDown:e=>{e.preventDefault(),H(e.shiftKey?j*10:j)},children:l(o,{icon:c})}),l(t,{className:r.arrowBtn,tabIndex:-1,onMouseDown:e=>{e.preventDefault(),H(e.shiftKey?-j*10:-j)},children:l(o,{icon:s})})]}):null;return l(n,{label:_,className:a(r.numberInput,y),style:b,value:B,onChange:()=>{},formValidator:null,isRequired:L,onBlur:()=>{p.current&&(p.current.touched=!0)},isValid:g?g.touched?!g.hasError():!0:!v,errorMessage:g?g.touched?g.getCurrentErrorMessage()??``:``:v??``,placeholder:O,readOnly:M,suffix:G,inputMode:E===0?`numeric`:`decimal`,customInput:l(d,{onValueChange:e=>V(e.floatValue),allowNegative:k==null?x:!1,decimalSeparator:S,thousandSeparator:C,decimalScale:E,fixedDecimalScale:D,prefix:W,suffix:T,onKeyDown:A?U:P,...F})})}export{f as default};
2
2
  //# sourceMappingURL=numberInput.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"numberInput.mjs","names":[],"sources":["../../../../package/common/numberInput/numberInput.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport React from 'react';\nimport cx from 'classnames';\nimport { NumericFormat, NumericFormatProps } from 'react-number-format';\nimport type { FormValidator } from 'services/formValidation';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './numberInput.module.pcss';\nimport Input from '../input';\nimport InteractableDiv from '../interactableDiv';\nimport { useComponentDefaults } from '../configProvider';\n\nexport interface NumberInputProps\n extends Omit<NumericFormatProps, 'onValueChange' | 'value' | 'customInput' | 'onChange' | 'step' | 'onKeyDown'> {\n value?: number | string;\n onChange?: (value: number | undefined) => void;\n formValidator?: FormValidator | null;\n label?: string;\n error?: string;\n className?: string;\n allowNegative?: boolean;\n decimalSeparator?: string;\n thousandSeparator?: string | boolean;\n prefix?: string;\n suffix?: string;\n decimalScale?: number;\n /**\n * Whether to pad the value to exactly `decimalScale` decimals. Default `true`\n * (e.g. with `decimalScale={2}`, `12` displays as `12.00`). Set `false` to make\n * `decimalScale` an upper limit only — the user may type fewer decimals and they\n * are kept as-is (`12` stays `12`, `12.1` stays `12.1`), while anything beyond\n * `decimalScale` is still truncated.\n */\n fixedDecimalScale?: boolean;\n placeholder?: string;\n sign?: '+' | '-';\n showArrows?: boolean;\n step?: number;\n readOnly?: boolean;\n onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;\n}\n\nfunction NumberInput(props: NumberInputProps): ReactElement {\n const {\n value,\n onChange,\n formValidator,\n label,\n error,\n className,\n style,\n allowNegative = false,\n decimalSeparator,\n thousandSeparator,\n prefix,\n suffix,\n decimalScale,\n fixedDecimalScale = true,\n placeholder,\n sign,\n showArrows = false,\n step = 1,\n readOnly = false,\n onKeyDown: onKeyDownProp,\n ...rest\n } = useComponentDefaults('NumberInput', props);\n const rawValue = formValidator != null ? formValidator.value as number | string : value;\n // When a sign is forced, display the absolute value — the prefix character carries the sign visually.\n const displayValue = sign != null && rawValue != null ? Math.abs(Number(rawValue)) : rawValue;\n const controlledValue = displayValue != null ? String(displayValue) : '';\n\n function handleValueChange(floatValue: number | undefined) {\n let out = floatValue;\n if (out !== undefined) {\n if (sign === '-') out = -Math.abs(out);\n if (sign === '+') out = Math.abs(out);\n }\n if (formValidator != null) formValidator.set(out ?? null);\n onChange?.(out);\n }\n\n function handleStep(delta: number) {\n if (readOnly) return;\n const current = rawValue != null && rawValue !== '' ? Number(rawValue) : 0;\n let next = current + delta;\n if (!allowNegative && sign !== '-') next = Math.max(0, next);\n if (sign === '-') next = Math.min(0, next);\n handleValueChange(next);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n if (readOnly) { onKeyDownProp?.(e); return; }\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n handleStep(e.shiftKey ? step * 10 : step);\n return;\n }\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n handleStep(e.shiftKey ? -step * 10 : -step);\n return;\n }\n onKeyDownProp?.(e);\n }\n\n const resolvedPrefix = sign === '-' ? '-' : sign === '+' ? '+' : prefix;\n\n const arrowSuffix = showArrows && !readOnly ? (\n <div className={styles.arrows}>\n <InteractableDiv\n className={styles.arrowBtn}\n tabIndex={-1}\n onMouseDown={(e) => { e.preventDefault(); handleStep(e.shiftKey ? step * 10 : step); }}\n >\n <FontAwesomeIcon icon={faChevronUp} />\n </InteractableDiv>\n <InteractableDiv\n className={styles.arrowBtn}\n tabIndex={-1}\n onMouseDown={(e) => { e.preventDefault(); handleStep(e.shiftKey ? -step * 10 : -step); }}\n >\n <FontAwesomeIcon icon={faChevronDown} />\n </InteractableDiv>\n </div>\n ) : null;\n\n return (\n <Input\n label={label}\n className={cx(styles.numberInput, className)}\n style={style}\n value={controlledValue}\n onChange={() => {}}\n formValidator={null}\n isValid={formValidator ? (formValidator.touched ? !formValidator.hasError() : true) : !error}\n errorMessage={formValidator ? (formValidator.getCurrentErrorMessage() ?? '') : (error ?? '')}\n placeholder={placeholder}\n readOnly={readOnly}\n suffix={arrowSuffix}\n inputMode={decimalScale === 0 ? 'numeric' : 'decimal'}\n customInput={\n <NumericFormat\n onValueChange={(vals) => handleValueChange(vals.floatValue)}\n allowNegative={sign != null ? false : allowNegative}\n decimalSeparator={decimalSeparator}\n thousandSeparator={thousandSeparator}\n decimalScale={decimalScale}\n fixedDecimalScale={fixedDecimalScale}\n prefix={resolvedPrefix}\n suffix={suffix}\n onKeyDown={showArrows ? handleKeyDown : onKeyDownProp}\n {...rest}\n />\n }\n />\n );\n}\n\nexport default NumberInput;\n"],"mappings":"0eA2CA,SAAS,EAAY,EAAuC,CAC1D,GAAM,CACN,QACA,WACA,gBACA,QACA,QACA,YACA,QACA,gBAAgB,GAChB,mBACA,oBACA,SACA,SACA,eACA,oBAAoB,GACpB,cACA,OACA,aAAa,GACb,OAAO,EACP,WAAW,GACX,UAAW,EACX,GAAG,GACC,EAAqB,cAAe,CAAK,EACvC,EAAW,GAAiB,KAAgD,EAAzC,EAAc,MAEjD,EAAe,GAAQ,MAAQ,GAAY,KAAO,KAAK,IAAI,OAAO,CAAQ,CAAC,EAAI,EAC/E,EAAkB,GAAgB,KAA8B,GAAvB,OAAO,CAAY,EAElE,SAAS,EAAkB,EAAgC,CACzD,IAAI,EAAM,EACN,IAAQ,IAAA,KACN,IAAS,MAAK,EAAM,CAAC,KAAK,IAAI,CAAG,GACjC,IAAS,MAAK,EAAO,KAAK,IAAI,CAAG,IAEnC,GAAqC,IAAI,GAAO,IAAI,EACxD,IAAW,CAAG,CAChB,CAEA,SAAS,EAAW,EAAe,CACjC,GAAI,EAAU,OAEd,IAAI,GADY,GAAY,MAAQ,IAAa,GAAK,OAAO,CAAQ,EAAI,GACpD,EACjB,CAAC,GAAiB,IAAS,MAAK,EAAO,KAAK,IAAI,EAAG,CAAI,GACvD,IAAS,MAAK,EAAO,KAAK,IAAI,EAAG,CAAI,GACzC,EAAkB,CAAI,CACxB,CAEA,SAAS,EAAc,EAA0C,CAC/D,GAAI,EAAU,CAAE,IAAgB,CAAC,EAAG,MAAQ,CAC5C,GAAI,EAAE,MAAQ,UAAW,CACvB,EAAE,eAAe,EACjB,EAAW,EAAE,SAAW,EAAO,GAAK,CAAI,EACxC,MACF,CACA,GAAI,EAAE,MAAQ,YAAa,CACzB,EAAE,eAAe,EACjB,EAAW,EAAE,SAAW,CAAC,EAAO,GAAK,CAAC,CAAI,EAC1C,MACF,CACA,IAAgB,CAAC,CACnB,CAEA,IAAM,EAAiB,IAAS,IAAM,IAAM,IAAS,IAAM,IAAM,EAE3D,EAAc,GAAc,CAAC,EACjC,EAAC,MAAD,CAAK,UAAW,EAAO,gBAAvB,CACE,EAAC,EAAD,CACE,UAAW,EAAO,SAClB,SAAU,GACV,YAAc,GAAM,CAAE,EAAE,eAAe,EAAG,EAAW,EAAE,SAAW,EAAO,GAAK,CAAI,CAAG,WAErF,EAAC,EAAD,CAAiB,KAAM,CAAc,CAAA,CACtB,CAAA,EACjB,EAAC,EAAD,CACE,UAAW,EAAO,SAClB,SAAU,GACV,YAAc,GAAM,CAAE,EAAE,eAAe,EAAG,EAAW,EAAE,SAAW,CAAC,EAAO,GAAK,CAAC,CAAI,CAAG,WAEvF,EAAC,EAAD,CAAiB,KAAM,CAAgB,CAAA,CACxB,CAAA,CACd,IACH,KAEJ,OACE,EAAC,EAAD,CACS,QACP,UAAW,EAAG,EAAO,YAAa,CAAS,EACpC,QACP,MAAO,EACP,aAAgB,CAAC,EACjB,cAAe,KACf,QAAS,EAAiB,EAAc,QAAU,CAAC,EAAc,SAAS,EAAI,GAAQ,CAAC,EACvF,aAAc,EAAiB,EAAc,uBAAuB,GAAK,GAAO,GAAS,GAC5E,cACH,WACV,OAAQ,EACR,UAAW,IAAiB,EAAI,UAAY,UAC5C,YACE,EAAC,EAAD,CACE,cAAgB,GAAS,EAAkB,EAAK,UAAU,EAC1D,cAAe,GAAQ,KAAe,EAAR,GACZ,mBACC,oBACL,eACK,oBACnB,OAAQ,EACA,SACR,UAAW,EAAa,EAAgB,EACxC,GAAI,CACL,CAAA,CAEJ,CAAA,CAEL"}
1
+ {"version":3,"file":"numberInput.mjs","names":[],"sources":["../../../../package/common/numberInput/numberInput.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport React from 'react';\nimport cx from 'classnames';\nimport { NumericFormat, NumericFormatProps } from 'react-number-format';\nimport type { FormValidator } from 'services/formValidation';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './numberInput.module.pcss';\nimport Input from '../input';\nimport InteractableDiv from '../interactableDiv';\nimport { useComponentDefaults } from '../configProvider';\n\nexport interface NumberInputProps\n extends Omit<NumericFormatProps, 'onValueChange' | 'value' | 'customInput' | 'onChange' | 'step' | 'onKeyDown'> {\n value?: number | string;\n onChange?: (value: number | undefined) => void;\n formValidator?: FormValidator | null;\n label?: string;\n error?: string;\n className?: string;\n allowNegative?: boolean;\n decimalSeparator?: string;\n thousandSeparator?: string | boolean;\n prefix?: string;\n suffix?: string;\n decimalScale?: number;\n /**\n * Whether to pad the value to exactly `decimalScale` decimals. Default `true`\n * (e.g. with `decimalScale={2}`, `12` displays as `12.00`). Set `false` to make\n * `decimalScale` an upper limit only — the user may type fewer decimals and they\n * are kept as-is (`12` stays `12`, `12.1` stays `12.1`), while anything beyond\n * `decimalScale` is still truncated.\n */\n fixedDecimalScale?: boolean;\n placeholder?: string;\n sign?: '+' | '-';\n showArrows?: boolean;\n step?: number;\n readOnly?: boolean;\n isRequired?: boolean;\n onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;\n}\n\nfunction NumberInput(props: NumberInputProps): ReactElement {\n const fvRef = React.useRef<FormValidator | null | undefined>(undefined);\n const {\n value,\n onChange,\n formValidator,\n label,\n error,\n className,\n style,\n allowNegative = false,\n decimalSeparator,\n thousandSeparator,\n prefix,\n suffix,\n decimalScale,\n fixedDecimalScale = true,\n placeholder,\n sign,\n showArrows = false,\n step = 1,\n readOnly = false,\n isRequired = false,\n onKeyDown: onKeyDownProp,\n ...rest\n } = useComponentDefaults('NumberInput', props);\n const [, forceUpdate] = React.useState(0);\n React.useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n const listener = () => forceUpdate((n) => n + 1);\n formValidator.registerOnUpdateListener(listener);\n return () => { formValidator.removeOnUpdateListener(listener); };\n }, [formValidator]);\n const computedIsRequired = isRequired || !!formValidator?.validators.find(\n (v) => (v as { validatorId?: string }).validatorId === 'required'\n );\n const rawValue = formValidator != null ? formValidator.value as number | string : value;\n // When a sign is forced, display the absolute value — the prefix character carries the sign visually.\n const displayValue = sign != null && rawValue != null ? Math.abs(Number(rawValue)) : rawValue;\n const controlledValue = displayValue != null ? String(displayValue) : '';\n\n function handleValueChange(floatValue: number | undefined) {\n let out = floatValue;\n if (out !== undefined) {\n if (sign === '-') out = -Math.abs(out);\n if (sign === '+') out = Math.abs(out);\n }\n if (formValidator != null) formValidator.set(out ?? null);\n onChange?.(out);\n }\n\n function handleStep(delta: number) {\n if (readOnly) return;\n const current = rawValue != null && rawValue !== '' ? Number(rawValue) : 0;\n let next = current + delta;\n if (!allowNegative && sign !== '-') next = Math.max(0, next);\n if (sign === '-') next = Math.min(0, next);\n handleValueChange(next);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n if (readOnly) { onKeyDownProp?.(e); return; }\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n handleStep(e.shiftKey ? step * 10 : step);\n return;\n }\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n handleStep(e.shiftKey ? -step * 10 : -step);\n return;\n }\n onKeyDownProp?.(e);\n }\n\n const resolvedPrefix = sign === '-' ? '-' : sign === '+' ? '+' : prefix;\n\n const arrowSuffix = showArrows && !readOnly ? (\n <div className={styles.arrows}>\n <InteractableDiv\n className={styles.arrowBtn}\n tabIndex={-1}\n onMouseDown={(e) => { e.preventDefault(); handleStep(e.shiftKey ? step * 10 : step); }}\n >\n <FontAwesomeIcon icon={faChevronUp} />\n </InteractableDiv>\n <InteractableDiv\n className={styles.arrowBtn}\n tabIndex={-1}\n onMouseDown={(e) => { e.preventDefault(); handleStep(e.shiftKey ? -step * 10 : -step); }}\n >\n <FontAwesomeIcon icon={faChevronDown} />\n </InteractableDiv>\n </div>\n ) : null;\n\n return (\n <Input\n label={label}\n className={cx(styles.numberInput, className)}\n style={style}\n value={controlledValue}\n onChange={() => {}}\n formValidator={null}\n isRequired={computedIsRequired}\n onBlur={() => { if (fvRef.current) fvRef.current.touched = true; }}\n isValid={formValidator ? (formValidator.touched ? !formValidator.hasError() : true) : !error}\n errorMessage={formValidator ? (formValidator.touched ? (formValidator.getCurrentErrorMessage() ?? '') : '') : (error ?? '')}\n placeholder={placeholder}\n readOnly={readOnly}\n suffix={arrowSuffix}\n inputMode={decimalScale === 0 ? 'numeric' : 'decimal'}\n customInput={\n <NumericFormat\n onValueChange={(vals) => handleValueChange(vals.floatValue)}\n allowNegative={sign != null ? false : allowNegative}\n decimalSeparator={decimalSeparator}\n thousandSeparator={thousandSeparator}\n decimalScale={decimalScale}\n fixedDecimalScale={fixedDecimalScale}\n prefix={resolvedPrefix}\n suffix={suffix}\n onKeyDown={showArrows ? handleKeyDown : onKeyDownProp}\n {...rest}\n />\n }\n />\n );\n}\n\nexport default NumberInput;\n"],"mappings":"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"}