@elcrm/form 0.1.2 → 0.1.4

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.
Files changed (111) hide show
  1. package/README.md +162 -204
  2. package/dist/Form.d.ts +21 -3
  3. package/dist/assets/styles/Check.module.css +1 -1
  4. package/dist/assets/styles/Code.module.css +1 -1
  5. package/dist/assets/styles/Color.module.css +1 -1
  6. package/dist/assets/styles/Drag.module.css +1 -1
  7. package/dist/assets/styles/Field.module.css +1 -1
  8. package/dist/assets/styles/FieldGroup.module.css +1 -0
  9. package/dist/assets/styles/File.module.css +1 -1
  10. package/dist/assets/styles/Form.module.css +1 -1
  11. package/dist/assets/styles/Radio.module.css +1 -1
  12. package/dist/assets/styles/Rating.module.css +1 -1
  13. package/dist/assets/styles/Rich.module.css +1 -1
  14. package/dist/assets/styles/Select.module.css +1 -1
  15. package/dist/assets/styles/Tabs.module.css +1 -0
  16. package/dist/assets/styles/Tags.module.css +1 -1
  17. package/dist/assets/styles/Time.module.css +1 -1
  18. package/dist/core/Field.d.ts +38 -10
  19. package/dist/core/Field.js +2 -2
  20. package/dist/dark.css +34 -11
  21. package/dist/fields/Card.d.ts +26 -0
  22. package/dist/fields/Card.js +1 -0
  23. package/dist/fields/Check.d.ts +20 -2
  24. package/dist/fields/Check.js +1 -1
  25. package/dist/fields/Code.d.ts +26 -4
  26. package/dist/fields/Code.js +1 -1
  27. package/dist/fields/Color.d.ts +21 -13
  28. package/dist/fields/Color.js +1 -1
  29. package/dist/fields/ColorPanel.d.ts +20 -0
  30. package/dist/fields/ColorPanel.js +1 -0
  31. package/dist/fields/Date.d.ts +16 -2
  32. package/dist/fields/Date.js +1 -1
  33. package/dist/fields/DateCalendar.d.ts +26 -0
  34. package/dist/fields/DateCalendar.js +1 -0
  35. package/dist/fields/Display.d.ts +15 -5
  36. package/dist/fields/Display.js +2 -1
  37. package/dist/fields/DragDrop.d.ts +27 -4
  38. package/dist/fields/DragDrop.js +1 -1
  39. package/dist/fields/Email.d.ts +18 -3
  40. package/dist/fields/Email.js +1 -1
  41. package/dist/fields/FieldGroup.d.ts +127 -0
  42. package/dist/fields/FieldGroup.js +1 -0
  43. package/dist/fields/File.d.ts +14 -1
  44. package/dist/fields/File.js +1 -1
  45. package/dist/fields/Hidden.d.ts +7 -2
  46. package/dist/fields/Hidden.js +1 -1
  47. package/dist/fields/Input.d.ts +10 -5
  48. package/dist/fields/Input.js +1 -1
  49. package/dist/fields/Mask.d.ts +14 -1
  50. package/dist/fields/Mask.js +1 -1
  51. package/dist/fields/Modal.d.ts +20 -3
  52. package/dist/fields/Modal.js +1 -1
  53. package/dist/fields/Money.d.ts +12 -1
  54. package/dist/fields/Money.js +1 -1
  55. package/dist/fields/NativeTextField.d.ts +9 -5
  56. package/dist/fields/NativeTextField.js +1 -1
  57. package/dist/fields/Numeric.d.ts +10 -8
  58. package/dist/fields/Numeric.js +1 -1
  59. package/dist/fields/Options.d.ts +24 -5
  60. package/dist/fields/Options.js +1 -1
  61. package/dist/fields/Password.d.ts +11 -0
  62. package/dist/fields/Password.js +1 -1
  63. package/dist/fields/Percent.d.ts +10 -6
  64. package/dist/fields/Percent.js +1 -1
  65. package/dist/fields/Phone.d.ts +13 -1
  66. package/dist/fields/Phone.js +1 -1
  67. package/dist/fields/Radio.d.ts +17 -1
  68. package/dist/fields/Radio.js +1 -1
  69. package/dist/fields/Range.d.ts +19 -6
  70. package/dist/fields/Range.js +1 -1
  71. package/dist/fields/Rating.d.ts +13 -1
  72. package/dist/fields/Rating.js +1 -1
  73. package/dist/fields/RichText.d.ts +10 -2
  74. package/dist/fields/RichText.js +1 -1
  75. package/dist/fields/Select.d.ts +21 -0
  76. package/dist/fields/Select.js +1 -1
  77. package/dist/fields/Tabs.d.ts +45 -0
  78. package/dist/fields/Tabs.js +1 -0
  79. package/dist/fields/Tags.d.ts +13 -1
  80. package/dist/fields/Tags.js +1 -1
  81. package/dist/fields/Textarea.d.ts +10 -1
  82. package/dist/fields/Textarea.js +1 -1
  83. package/dist/fields/Time.d.ts +13 -4
  84. package/dist/fields/Time.js +1 -1
  85. package/dist/fields/TimePicker.d.ts +24 -0
  86. package/dist/fields/TimePicker.js +1 -0
  87. package/dist/fields/Url.d.ts +11 -1
  88. package/dist/fields/cardUtils.d.ts +37 -0
  89. package/dist/fields/cardUtils.js +1 -0
  90. package/dist/fields/colorUtils.d.ts +29 -0
  91. package/dist/fields/colorUtils.js +1 -0
  92. package/dist/fields/dateUtils.d.ts +32 -0
  93. package/dist/fields/dateUtils.js +1 -0
  94. package/dist/fields/emailUtils.d.ts +4 -0
  95. package/dist/fields/emailUtils.js +1 -0
  96. package/dist/fields/timeUtils.d.ts +23 -0
  97. package/dist/fields/timeUtils.js +1 -0
  98. package/dist/fields/type.d.ts +97 -26
  99. package/dist/hooks/use.d.ts +32 -13
  100. package/dist/index.d.ts +21 -9
  101. package/dist/index.js +2 -2
  102. package/dist/index.umd.js +3 -2
  103. package/dist/light.css +35 -12
  104. package/dist/package.js +1 -1
  105. package/dist/style.css +17 -13
  106. package/dist/styles/Code.module.js +1 -1
  107. package/dist/styles/Color.module.js +1 -1
  108. package/dist/styles/Field.module.js +1 -1
  109. package/dist/styles/FieldGroup.module.js +1 -0
  110. package/dist/styles/Tabs.module.js +1 -0
  111. package/package.json +1 -1
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import i,{asEditableClipboard as a}from"../events/onEvent.js";import{isEmptyTextLike as o}from"./visibility.js";import{createFieldEmit as s}from"./emit.js";import c from"react";import{jsx as l,jsxs as u}from"react/jsx-runtime";function d({value:n,form:d,onValue:m,name:h=``,placeholder:g=``,label:_=``,hidden:v=!1,disabled:y=!1,onBlur:b,className:x=``,after:S=``,before:C=``,error:w=``,inputmode:T=`text`,maxLength:E,spellCheck:D=!0,native:O=!1,autoComplete:k,inputType:A=`text`,id:j,size:M=`md`}){let{value:N,version:P}=r(d,h,n),F=!y,I=typeof N==`string`||typeof N==`number`?String(N):``,L=c.useRef(null),R=c.useRef(null),z=c.useRef(!1);c.useLayoutEffect(()=>{if(O)return;let e=R.current;e&&e.textContent!==I&&(e.textContent=I)},[O,I,P]),c.useEffect(()=>{if(!O)return;let e=L.current;e&&e.value!==I&&(e.value=I)},[O,I]);let B=s(d,h,m),V=e=>{let t=e.target;B((t.textContent||``).trim())},H=e=>{B(e.target.value)},U=e=>{let t=e.target;E&&(t.textContent||``).trim().length>=E&&e.key!==`Backspace`&&e.preventDefault(),e.key===`Enter`&&e.preventDefault()},W=e=>{e.key===`Enter`&&e.preventDefault()},G=e=>i.Paste(E||0,a(e));if(v&&o(N))return``;let K=e=>{i.Blur(e),b?.({value:(e.target.textContent||``).trim(),name:h}),z.current=!1},q=e=>{b?.({value:(e.target.value||``).trim(),name:h})},J=e=>{z.current=!0,i.Focus({target:e.currentTarget})},Y={};return g&&(Y.placeholder=g),F&&(Y.edit=``),O?u(t,{type:`input`,label:_,error:w,id:j,size:M,element_blok:{className:[x||``]},element_input:{className:[e.w],props:{"data-disabled":y||!F?`true`:void 0}},children:[C?l(`span`,{className:e.a,children:C}):null,l(f,{inputRef:L,name:h,displayString:I,placeholder:g,maxLength:E,spellCheck:D,disabled:y,editable:F,autoComplete:k,inputType:A,inputmode:T,label:_,onChangeNative:H,handleBlurNative:q,onKeyDownNative:W}),S?l(`span`,{className:e.a,children:S}):null]}):u(t,{type:`input`,label:_,error:w,id:j,size:M,element_blok:{className:[x]},element_input:{className:[e.w]},children:[C?l(`span`,{className:e.a,children:C}):null,l(p,{ceRef:R,editable:F,label:_,placeholder:g,spellCheck:D,inputmode:T,dd:Y,onBlur:K,onFocus:J,onPaste:G,onInput:V,onKeyDown:U}),S?l(`span`,{className:e.a,children:S}):null]})}function f({inputRef:t,name:r,displayString:i,placeholder:a,maxLength:o,spellCheck:s,disabled:c,editable:u,autoComplete:d,inputType:f,inputmode:p,label:m,onChangeNative:h,handleBlurNative:g,onKeyDownNative:_}){let v=n();return l(`div`,{className:e.x,children:l(`input`,{id:v?.controlId,ref:t,className:e.y,type:f,name:r||void 0,defaultValue:i,placeholder:a,maxLength:o,spellCheck:s,disabled:c,readOnly:c,autoComplete:d,inputMode:p||`text`,"aria-label":m?void 0:a||`Текст`,"aria-describedby":v?.describedBy,"aria-invalid":v?.errorId?!0:void 0,"aria-disabled":c||!u?!0:void 0,tabIndex:c?-1:0,onChange:h,onBlur:g,onKeyDown:_})})}function p({ceRef:e,editable:t,label:r,placeholder:i,spellCheck:a,inputmode:o,dd:s,onBlur:c,onFocus:u,onPaste:d,onInput:f,onKeyDown:p}){let m=n();return l(`div`,{ref:e,id:m?.controlId,role:`textbox`,"aria-multiline":`false`,"aria-label":r?void 0:i||`Текст`,"aria-describedby":m?.describedBy,"aria-invalid":m?.errorId?!0:void 0,"aria-disabled":!t,tabIndex:t?0:-1,onBlur:c,onFocus:u,onPaste:d,onInput:f,onKeyDown:p,spellCheck:a,inputMode:o||`text`,contentEditable:t?`plaintext-only`:!1,suppressContentEditableWarning:!0,...s})}var m=c.memo(d);export{m as default};
1
+ import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import{createFieldEmit as i}from"./emit.js";import a,{asEditableClipboard as o}from"../events/onEvent.js";import{isEmptyTextLike as s}from"./visibility.js";import c from"react";import{jsx as l,jsxs as u}from"react/jsx-runtime";function d({value:n,form:d,onValue:m,name:h=``,placeholder:g=``,label:_=``,hidden:v=!1,disabled:y=!1,onBlur:b,className:x=``,after:S=``,before:C=``,error:w=``,inputmode:T=`text`,maxLength:E,spellCheck:D=!0,native:O=!1,autoComplete:k,inputType:A=`text`,id:j,size:M=`m`}){let{value:N,version:P}=r(d,h,n),F=!y,I=typeof N==`string`||typeof N==`number`?String(N):``,L=c.useRef(null),R=c.useRef(null),z=c.useRef(!1);c.useLayoutEffect(()=>{if(O)return;let e=R.current;e&&e.textContent!==I&&(e.textContent=I)},[O,I,P]),c.useEffect(()=>{if(!O)return;let e=L.current;e&&e.value!==I&&(e.value=I)},[O,I]);let B=i(d,h,m),V=e=>{let t=e.target;B((t.textContent||``).trim())},H=e=>{B(e.target.value)},U=e=>{let t=e.target;E&&(t.textContent||``).trim().length>=E&&e.key!==`Backspace`&&e.preventDefault(),e.key===`Enter`&&e.preventDefault()},W=e=>{e.key===`Enter`&&e.preventDefault()},G=e=>a.Paste(E||0,o(e));if(v&&s(N))return``;let K=e=>{a.Blur(e),b?.({value:(e.target.textContent||``).trim(),name:h}),z.current=!1},q=e=>{b?.({value:(e.target.value||``).trim(),name:h})},J=e=>{z.current=!0,a.Focus({target:e.currentTarget})},Y={};return g&&(Y.placeholder=g),F&&(Y.edit=``),O?u(t,{type:`input`,label:_,error:w,id:j,size:M,element_blok:{className:[x||``]},element_input:{className:[e.w],props:{"data-disabled":y||!F?`true`:void 0}},children:[C?l(`span`,{className:e.a,children:C}):null,l(f,{inputRef:L,name:h,displayString:I,placeholder:g,maxLength:E,spellCheck:D,disabled:y,editable:F,autoComplete:k,inputType:A,inputmode:T,label:_,onChangeNative:H,handleBlurNative:q,onKeyDownNative:W}),S?l(`span`,{className:e.a,children:S}):null]}):u(t,{type:`input`,label:_,error:w,id:j,size:M,element_blok:{className:[x]},element_input:{className:[e.w],props:{"data-disabled":y||!F?`true`:void 0}},children:[C?l(`span`,{className:e.a,children:C}):null,l(p,{ceRef:R,editable:F,label:_,placeholder:g,spellCheck:D,inputmode:T,dd:Y,onBlur:K,onFocus:J,onPaste:G,onInput:V,onKeyDown:U}),S?l(`span`,{className:e.a,children:S}):null]})}function f({inputRef:t,name:r,displayString:i,placeholder:a,maxLength:o,spellCheck:s,disabled:c,editable:u,autoComplete:d,inputType:f,inputmode:p,label:m,onChangeNative:h,handleBlurNative:g,onKeyDownNative:_}){let v=n();return l(`div`,{className:e.x,children:l(`input`,{id:v?.controlId,ref:t,className:e.y,type:f,name:r||void 0,defaultValue:i,placeholder:a,maxLength:o,spellCheck:s,disabled:c,readOnly:c,autoComplete:d,inputMode:p||`text`,"aria-label":m?void 0:a||`Текст`,"aria-describedby":v?.describedBy,"aria-invalid":v?.errorId?!0:void 0,"aria-disabled":c||!u?!0:void 0,tabIndex:c?-1:0,onChange:h,onBlur:g,onKeyDown:_})})}function p({ceRef:e,editable:t,label:r,placeholder:i,spellCheck:a,inputmode:o,dd:s,onBlur:c,onFocus:u,onPaste:d,onInput:f,onKeyDown:p}){let m=n();return l(`div`,{ref:e,id:m?.controlId,role:`textbox`,"aria-multiline":`false`,"aria-label":r?void 0:i||`Текст`,"aria-describedby":m?.describedBy,"aria-invalid":m?.errorId?!0:void 0,"aria-disabled":!t,tabIndex:t?0:-1,onBlur:c,onFocus:u,onPaste:d,onInput:f,onKeyDown:p,spellCheck:a,inputMode:o||`text`,contentEditable:t?`plaintext-only`:!1,suppressContentEditableWarning:!0,...s})}var m=c.memo(d);export{m as default};
@@ -1,7 +1,20 @@
1
1
  import { TInput } from './type';
2
- type TMask = TInput & {
2
+ /**
3
+ * Маска ввода. **В форме — только цифры**; на экране шаблон `format`, `_` = слот цифры.
4
+ *
5
+ * @example
6
+ * <MaskField name="inn" form={form} label="ИНН" format="____________" />
7
+ */
8
+ export type TMask = TInput & {
9
+ /**
10
+ * Шаблон, например `+_(___) ___-__-__` или `99.99.9999`.
11
+ * Цифры в шаблоне — фиксированные, `_` — ввод.
12
+ */
3
13
  format?: string;
4
14
  };
15
+ /**
16
+ * Поле с маской. Не путать с PhoneField (маски стран).
17
+ */
5
18
  declare function MaskField({ value, form, onValue, onBlur: onBlurField, name, format, placeholder, label, error, hidden, disabled, className, after, before, inputmode, view, }: TMask): import("react/jsx-runtime").JSX.Element;
6
19
  declare namespace MaskField {
7
20
  var displayName: string;
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import r,{asEditableClipboard as i}from"../events/onEvent.js";import{isEmptyTextLike as a}from"./visibility.js";import o from"react";import{Fragment as s,jsx as c,jsxs as l}from"react/jsx-runtime";function u(e){let t=window.getSelection();if(!t||t.rangeCount===0)return 0;let n=t.getRangeAt(0);if(!e.contains(n.startContainer))return 0;let r=document.createRange();return r.selectNodeContents(e),r.setEnd(n.startContainer,n.startOffset),r.toString().length}function d(e,t){if(t<=0)return 0;let n=0;for(let r=0;r<e.length;r++)if(/\d/.test(e[r])&&(n++,n===t))return r+1;return e.length}function f({value:f=``,form:p,onValue:m,onBlur:h,name:g=``,format:_=`+_(___) ___-__-__`,placeholder:v=``,label:y=``,error:b=``,hidden:x=!1,disabled:S=!1,className:C=``,after:w=``,before:T=``,inputmode:E=`numeric`,view:D}){let O=!S,{value:k,version:A}=n(p,g,f),j=o.useRef(null),M=o.useRef(!1),N=_,P=!0,F=0,I=(e,t)=>{let n=t.firstChild;if(!n||n.nodeType!==Node.TEXT_NODE)return;let r=n.textContent?.length??0,i=Math.max(0,Math.min(e,r)),a=document.createRange(),o=window.getSelection();o&&(a.setStart(n,i),a.collapse(!0),o.removeAllRanges(),o.addRange(a),t.focus())},L=e=>r.PasteOne(i(e)),R=e=>{N=_,P=!0,F=0;let t=0,n=``,r=e.replace(/\D/g,``);r===``&&(P=!0);let i=r.split(``),a=``;i.forEach(e=>{P&&(a+=e,P&&(F=(``+a).length,N=_.replace(RegExp(`[0-9]`,`g`),`_`),n=``),F>(``+a).length&&(P=!0,N=_.replace(RegExp(`[0-9]`,`g`),`_`),n=``))});let o=N.replace(/\D/g,``);return o.length>=r.length&&(r=o),{q:N.replace(/[_\d]/g,function(){return r.charAt(t++)||`_`}),i:t,v:r,f:n}};o.useLayoutEffect(()=>{if(M.current)return;let e=j.current;if(!e)return;let t=R(String(k||``));e.textContent!==t.q&&(e.textContent=t.q)},[k,A,_]),R(String(k||``));let z=e=>{let t=e.target,n=t.textContent||``,r=u(t),i=n.slice(0,r).replace(/\D/g,``).length,a=R(n);t.textContent=a.q;let o=d(a.q,i);a.q.length>0&&queueMicrotask(()=>{I(Math.min(o,a.q.length),t)});let s={value:a.q.replace(/\D/g,``),name:g};p&&g&&p.onValue(s),m&&m!==p?.onValue&&m(s)},B=e=>{e.key===`Enter`&&e.preventDefault()},V=e=>{r.Blur(e),h&&h({value:(e.target.textContent??``).replace(/\D/g,``),name:g}),M.current=!1},H=e=>{M.current=!0,r.Focus({target:e.currentTarget})},U={};v&&(U.placeholder=v),U.inputMode=E??`numeric`;let W=String(k??``).replace(/\D/g,``);return x&&a(W)?c(s,{}):l(t,{type:`input`,label:y,error:b,element_blok:{className:[C]},element_input:{className:[e.w]},children:[T?c(`span`,{className:e.a,children:T}):null,c(`div`,{ref:j,onPaste:L,onInput:z,onKeyDown:B,onBlur:V,onFocus:H,role:`textbox`,spellCheck:!1,"aria-label":y||v||g||`Маска`,"aria-disabled":!O,tabIndex:S?-1:0,"data-disabled":!O,contentEditable:O?`plaintext-only`:!1,suppressContentEditableWarning:!0,...U}),w?c(`span`,{className:e.a,children:w}):null]})}f.displayName=`MaskField`;export{f as default};
1
+ import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import{createFieldEmit as r}from"./emit.js";import i,{asEditableClipboard as a}from"../events/onEvent.js";import{isEmptyTextLike as o}from"./visibility.js";import s from"react";import{Fragment as c,jsx as l,jsxs as u}from"react/jsx-runtime";function d(e){let t=window.getSelection();if(!t||t.rangeCount===0)return 0;let n=t.getRangeAt(0);if(!e.contains(n.startContainer))return 0;let r=document.createRange();return r.selectNodeContents(e),r.setEnd(n.startContainer,n.startOffset),r.toString().length}function f(e,t){if(t<=0)return 0;let n=0;for(let r=0;r<e.length;r++)if(/\d/.test(e[r])&&(n++,n===t))return r+1;return e.length}function p({value:p=``,form:m,onValue:h,onBlur:g,name:_=``,format:v=`+_(___) ___-__-__`,placeholder:y=``,label:b=``,error:x=``,hidden:S=!1,disabled:C=!1,className:w=``,after:T=``,before:E=``,inputmode:D=`numeric`,view:O}){let k=!C,{value:A,version:j}=n(m,_,p),M=s.useRef(null),N=s.useRef(!1),P=v,F=!0,I=0,L=(e,t)=>{let n=t.firstChild;if(!n||n.nodeType!==Node.TEXT_NODE)return;let r=n.textContent?.length??0,i=Math.max(0,Math.min(e,r)),a=document.createRange(),o=window.getSelection();o&&(a.setStart(n,i),a.collapse(!0),o.removeAllRanges(),o.addRange(a),t.focus())},R=e=>i.PasteOne(a(e)),z=e=>{P=v,F=!0,I=0;let t=0,n=``,r=e.replace(/\D/g,``);r===``&&(F=!0);let i=r.split(``),a=``;i.forEach(e=>{F&&(a+=e,F&&(I=(``+a).length,P=v.replace(RegExp(`[0-9]`,`g`),`_`),n=``),I>(``+a).length&&(F=!0,P=v.replace(RegExp(`[0-9]`,`g`),`_`),n=``))});let o=P.replace(/\D/g,``);return o.length>=r.length&&(r=o),{q:P.replace(/[_\d]/g,function(){return r.charAt(t++)||`_`}),i:t,v:r,f:n}};s.useLayoutEffect(()=>{if(N.current)return;let e=M.current;if(!e)return;let t=z(String(A||``));e.textContent!==t.q&&(e.textContent=t.q)},[A,j,v]),z(String(A||``));let B=r(m,_,h),V=e=>{let t=e.target,n=t.textContent||``,r=d(t),i=n.slice(0,r).replace(/\D/g,``).length,a=z(n);t.textContent=a.q;let o=f(a.q,i);a.q.length>0&&queueMicrotask(()=>{L(Math.min(o,a.q.length),t)}),B(a.q.replace(/\D/g,``))},H=e=>{e.key===`Enter`&&e.preventDefault()},U=e=>{i.Blur(e),g&&g({value:(e.target.textContent??``).replace(/\D/g,``),name:_}),N.current=!1},W=e=>{N.current=!0,i.Focus({target:e.currentTarget})},G={};y&&(G.placeholder=y),G.inputMode=D??`numeric`;let K=String(A??``).replace(/\D/g,``);return S&&o(K)?l(c,{}):u(t,{type:`input`,label:b,error:x,element_blok:{className:[w]},element_input:{className:[e.w],props:{"data-disabled":C||!k?`true`:void 0}},children:[E?l(`span`,{className:e.a,children:E}):null,l(`div`,{ref:M,onPaste:R,onInput:V,onKeyDown:H,onBlur:U,onFocus:W,role:`textbox`,spellCheck:!1,"aria-label":b||y||_||`Маска`,"aria-disabled":!k,tabIndex:C?-1:0,"data-disabled":k?void 0:`true`,contentEditable:k?`plaintext-only`:!1,suppressContentEditableWarning:!0,...G}),T?l(`span`,{className:e.a,children:T}):null]})}p.displayName=`MaskField`;export{p as default};
@@ -1,12 +1,24 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { UseFormApi } from '../hooks/use';
3
3
  import { TValue } from './type';
4
- interface Input {
4
+ /**
5
+ * Одно значение из модалки приложения (`Form.Init.onModal`).
6
+ *
7
+ * **В форме:** `string` или кортеж `[id, подпись]`.
8
+ *
9
+ * **Элементы:** капсула с текстом выбранного; клик → `modal` (`"module.name"`, обязателен).
10
+ *
11
+ * @example
12
+ * <ModalField name="city" form={form} label="Город" modal="geo.city" />
13
+ */
14
+ export type TModal = {
15
+ /** Строка или `[id, подпись]` — в капсуле показывается подпись. */
5
16
  value?: string | [string | number, string];
6
17
  form?: UseFormApi;
7
18
  onValue?: (data: TValue) => void | Promise<void>;
8
19
  name: string;
9
20
  placeholder?: string;
21
+ /** Подпись над капсулой */
10
22
  label?: string;
11
23
  error?: string;
12
24
  hidden?: boolean;
@@ -15,10 +27,15 @@ interface Input {
15
27
  before?: ReactNode;
16
28
  view?: string;
17
29
  className?: string;
30
+ /** Обязательно: `"module.modalName"` → {@link Form.Init} `onModal`. */
18
31
  modal: string;
32
+ /** Доп. данные в payload модалки */
19
33
  options?: Record<string | number, unknown>;
20
- }
21
- declare function ModalField({ value, form, onValue, name, placeholder, label, error, hidden, disabled, after, before, view, modal, options, className, }: Input): import("react/jsx-runtime").JSX.Element;
34
+ };
35
+ /**
36
+ * Поле-триггер модалки. Без `Form.Init` колбэк — no-op.
37
+ */
38
+ declare function ModalField({ value, form, onValue, name, placeholder, label, error, hidden, disabled, after, before, view, modal, options, className, }: TModal): import("react/jsx-runtime").JSX.Element;
22
39
  declare namespace ModalField {
23
40
  var displayName: string;
24
41
  }
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import{isEmptyTextLike as r}from"./visibility.js";import{useFormInit as i}from"../FormInitContext.js";import"react";import{Fragment as a,jsx as o,jsxs as s}from"react/jsx-runtime";function c({value:c,form:l,onValue:u,name:d,placeholder:f=``,label:p,error:m,hidden:h=!1,disabled:g=!1,after:_,before:v,view:y,modal:b,options:x,className:S}){let{onModal:C}=i(),{value:w}=n(l,d,c),T=w,E=e=>e?Array.isArray(e)?e[1]||``:e:``,D=e=>{if(Array.isArray(e)&&e.length>=2)return[e[0],String(e[1]??``)];if(typeof e==`object`&&e){let t=e;if(t.id!==void 0&&t.name!==void 0)return[t.id,t.name]}return String(e??``)},O=e=>{let t={value:D(e),name:d};l&&d&&l.setValue(t),u&&u!==l?.onValue&&u(t)},k=()=>{if(g||!b)return;let e=b.split(`.`);if(e.length<2)return;let t=Array.isArray(T)?T[0]:T;C({module:e[0],modalName:e[1],callback:O,onValue:O,options:x,fieldName:d,value:t})},A={};f&&(A.placeholder=f);let j=r(E(T));return h&&j?o(a,{}):s(t,{type:`input`,label:p,element_blok:{className:[S||``]},error:m,element_input:{className:[e.w],props:{onClick:k}},children:[v?o(`span`,{className:e.a,children:v}):null,o(`div`,{...A,children:E(T)}),_?o(`span`,{className:e.a,children:_}):null]})}c.displayName=`ModalField`;export{c as default};
1
+ import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import{createFieldEmit as r}from"./emit.js";import{isEmptyTextLike as i}from"./visibility.js";import{useFormInit as a}from"../FormInitContext.js";import"react";import{Fragment as o,jsx as s,jsxs as c}from"react/jsx-runtime";function l({value:l,form:u,onValue:d,name:f,placeholder:p=``,label:m,error:h,hidden:g=!1,disabled:_=!1,after:v,before:y,view:b,modal:x,options:S,className:C}){let{onModal:w}=a(),{value:T}=n(u,f,l),E=T,D=e=>e?Array.isArray(e)?e[1]||``:e:``,O=e=>{if(Array.isArray(e)&&e.length>=2)return[e[0],String(e[1]??``)];if(typeof e==`object`&&e){let t=e;if(t.id!==void 0&&t.name!==void 0)return[t.id,t.name]}return String(e??``)},k=e=>{r(u,f,d)(O(e),!0)},A=()=>{if(_||!x)return;let e=x.split(`.`);if(e.length<2)return;let t=Array.isArray(E)?E[0]:E;w({module:e[0],modalName:e[1],callback:k,onValue:k,options:S,fieldName:f,value:t})},j={};p&&(j.placeholder=p);let M=i(D(E));return g&&M?s(o,{}):c(t,{type:`input`,label:m,element_blok:{className:[C||``]},error:h,element_input:{className:[e.w],props:{onClick:A,"data-disabled":_?`true`:void 0}},children:[y?s(`span`,{className:e.a,children:y}):null,s(`div`,{...j,children:D(E)}),v?s(`span`,{className:e.a,children:v}):null]})}l.displayName=`ModalField`;export{l as default};
@@ -1,5 +1,13 @@
1
1
  import { TInput } from './type';
2
- type TMoney = TInput & {
2
+ /**
3
+ * Деньги. В UI — сумма с разделителями; **в форме — целое × `course`** (копейки при `course={100}`).
4
+ *
5
+ * **Элементы:** contentEditable + опционально кнопка очистки (`isClear`) в капсуле.
6
+ *
7
+ * @example
8
+ * <MoneyField name="sum" form={form} label="Сумма" course={100} />
9
+ */
10
+ export type TMoney = TInput & {
3
11
  /** Курс для отображения (множитель при записи в форму) */
4
12
  course?: number;
5
13
  /** Кнопка очистки */
@@ -7,6 +15,9 @@ type TMoney = TInput & {
7
15
  /** Режим фильтра символов при вводе */
8
16
  type?: string;
9
17
  };
18
+ /**
19
+ * Поле суммы. Клавиатура `decimal`.
20
+ */
10
21
  declare function MoneyField({ value, form, onValue, name, placeholder, label, error, hidden, disabled, onBlur: onBlurField, className, after, before, inputmode, course, view, type, isClear, }: TMoney): import("react/jsx-runtime").JSX.Element | "";
11
22
  declare namespace MoneyField {
12
23
  var displayName: string;
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import r,{pastePlainTextIntoSelection as i}from"../events/onEvent.js";import{isEmptyTextLike as a}from"./visibility.js";import o from"react";import{jsx as s,jsxs as c}from"react/jsx-runtime";function l(e){let t=window.getSelection();if(!t||t.rangeCount===0)return 0;let n=t.getRangeAt(0);if(!e.contains(n.startContainer))return 0;let r=document.createRange();return r.selectNodeContents(e),r.setEnd(n.startContainer,n.startOffset),r.toString().length}function u(e,t,n){let r=Math.max(0,Math.min(t,e.length));return n(e.slice(0,r)).length}function d({value:d,form:p,onValue:m,name:h=``,placeholder:g=``,label:_=``,error:v=``,hidden:y=!1,disabled:b=!1,onBlur:x,className:S=``,after:C=``,before:w=``,inputmode:T=`decimal`,course:E=100,view:D,type:O,isClear:k=!1}){let{value:A,version:j}=n(p,h||``,d),M=p&&h?A:d,N=o.useRef(null),P=o.useRef(!1);o.useLayoutEffect(()=>{if(P.current)return;let e=N.current;if(!e)return;let t=M!=null&&(typeof M==`number`?!0:!a(String(M))),n=!g||t?f(M??``,E):``;e.textContent!==n&&(e.textContent=n)},[M,j,g,E]);let F=e=>O===`multi`?e.replace(/[^+\d.+-]/g,``):e.replace(/[^+\d.]/g,``),I=(e,t)=>{let n=t.firstChild;if(!n||n.nodeType!==Node.TEXT_NODE)return;let r=n.textContent?.length??0,i=Math.max(0,Math.min(e,r)),a=document.createRange(),o=window.getSelection();o&&(a.setStart(n,i),a.collapse(!0),o.removeAllRanges(),o.addRange(a),t.focus())},L=e=>{let t=e.target,n=t.textContent||``,r=l(t),i=F(n),a=u(n,r,F),o={value:Number(i||0)*E,name:h};p&&h&&p.onValue(o),m&&m!==p?.onValue&&m(o),t.textContent=i,i.length>0&&queueMicrotask(()=>{I(Math.min(a,i.length),t)})},R=e=>{let t=e.target;r.Blur(e),(t.textContent||``)===``&&(t.textContent=`0`);let n={value:Number(F(t.textContent||``))*E,name:h};p&&h&&p.setValue(n),x?.(n),m&&m!==p?.onValue&&m(n),t.textContent=f(F(t.textContent||``).trim()||`0`),P.current=!1},z=e=>{P.current=!0;let t=e.target;t.textContent=F(t.textContent||``),r.Focus({target:e.currentTarget})},B=e=>{let t=e.currentTarget.previousElementSibling;t&&(t.textContent=``);let n={value:0,name:h};p&&h&&p.setValue(n),m&&m!==p?.onValue&&m(n)},V=e=>{e.key===`Enter`&&e.preventDefault()},H=e=>{e.preventDefault(),i(F(e.clipboardData?.getData(`text/plain`)??``),e.currentTarget)},U=!b,W=M==null||(typeof M==`number`?!1:a(String(M??``)));if(y&&W)return``;let G={};return G.inputMode=T??`decimal`,g&&(G.placeholder=g),U&&(G.edit=``),c(t,{type:`input`,label:_,error:v,element_blok:{className:[S]},element_input:{className:[e.w]},children:[w?s(`span`,{className:e.a,children:w}):null,s(`div`,{ref:N,...G,onInput:L,onPaste:H,onBlur:R,onKeyDown:V,onFocus:z,role:`textbox`,spellCheck:!1,"aria-label":_||g||`Сумма`,"aria-disabled":!U,tabIndex:b?-1:0,contentEditable:U?`plaintext-only`:!1,suppressContentEditableWarning:!0}),k&&s(`button`,{type:`button`,onClick:B,"aria-label":`Очистить поле`,children:`x`}),C?s(`span`,{className:e.a,children:C}):null]})}d.displayName=`MoneyField`;function f(e,t){let n;if(typeof e==`string`){let t=e.replace(/\s/g,``).replace(`,`,`.`);n=parseFloat(t===``?`0`:t)}else n=Number(e??0);return Number.isNaN(n)&&(n=0),t!=null&&t>0&&(n/=t),n.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g,`$1 `)}export{d as default};
1
+ import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import{createFieldEmit as r}from"./emit.js";import i,{pastePlainTextIntoSelection as a}from"../events/onEvent.js";import{isEmptyTextLike as o}from"./visibility.js";import s from"react";import{jsx as c,jsxs as l}from"react/jsx-runtime";function u(e){let t=window.getSelection();if(!t||t.rangeCount===0)return 0;let n=t.getRangeAt(0);if(!e.contains(n.startContainer))return 0;let r=document.createRange();return r.selectNodeContents(e),r.setEnd(n.startContainer,n.startOffset),r.toString().length}function d(e,t,n){let r=Math.max(0,Math.min(t,e.length));return n(e.slice(0,r)).length}function f({value:f,form:m,onValue:h,name:g=``,placeholder:_=``,label:v=``,error:y=``,hidden:b=!1,disabled:x=!1,onBlur:S,className:C=``,after:w=``,before:T=``,inputmode:E=`decimal`,course:D=100,view:O,type:k,isClear:A=!1}){let{value:j,version:M}=n(m,g||``,f),N=m&&g?j:f,P=s.useRef(null),F=s.useRef(!1);s.useLayoutEffect(()=>{if(F.current)return;let e=P.current;if(!e)return;let t=N!=null&&(typeof N==`number`?!0:!o(String(N))),n=!_||t?p(N??``,D):``;e.textContent!==n&&(e.textContent=n)},[N,M,_,D]);let I=e=>k===`multi`?e.replace(/[^+\d.+-]/g,``):e.replace(/[^+\d.]/g,``),L=(e,t)=>{let n=t.firstChild;if(!n||n.nodeType!==Node.TEXT_NODE)return;let r=n.textContent?.length??0,i=Math.max(0,Math.min(e,r)),a=document.createRange(),o=window.getSelection();o&&(a.setStart(n,i),a.collapse(!0),o.removeAllRanges(),o.addRange(a),t.focus())},R=r(m,g,h),z=e=>{let t=e.target,n=t.textContent||``,r=u(t),i=I(n),a=d(n,r,I);R(Number(i||0)*D),t.textContent=i,i.length>0&&queueMicrotask(()=>{L(Math.min(a,i.length),t)})},B=e=>{let t=e.target;i.Blur(e),(t.textContent||``)===``&&(t.textContent=`0`);let n=Number(I(t.textContent||``))*D;R(n,!0),S?.({value:n,name:g}),t.textContent=p(I(t.textContent||``).trim()||`0`),F.current=!1},V=e=>{F.current=!0;let t=e.target;t.textContent=I(t.textContent||``),i.Focus({target:e.currentTarget})},H=e=>{let t=e.currentTarget.previousElementSibling;t&&(t.textContent=``),R(0,!0)},U=e=>{e.key===`Enter`&&e.preventDefault()},W=e=>{e.preventDefault(),a(I(e.clipboardData?.getData(`text/plain`)??``),e.currentTarget)},G=!x,K=N==null||(typeof N==`number`?!1:o(String(N??``)));if(b&&K)return``;let q={};return q.inputMode=E??`decimal`,_&&(q.placeholder=_),G&&(q.edit=``),l(t,{type:`input`,label:v,error:y,element_blok:{className:[C]},element_input:{className:[e.w],props:{"data-disabled":x||!G?`true`:void 0}},children:[T?c(`span`,{className:e.a,children:T}):null,c(`div`,{ref:P,...q,onInput:z,onPaste:W,onBlur:B,onKeyDown:U,onFocus:V,role:`textbox`,spellCheck:!1,"aria-label":v||_||`Сумма`,"aria-disabled":!G,tabIndex:x?-1:0,contentEditable:G?`plaintext-only`:!1,suppressContentEditableWarning:!0}),A&&c(`button`,{type:`button`,onClick:H,"aria-label":`Очистить поле`,children:`x`}),w?c(`span`,{className:e.a,children:w}):null]})}f.displayName=`MoneyField`;function p(e,t){let n;if(typeof e==`string`){let t=e.replace(/\s/g,``).replace(`,`,`.`);n=parseFloat(t===``?`0`:t)}else n=Number(e??0);return Number.isNaN(n)&&(n=0),t!=null&&t>0&&(n/=t),n.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g,`$1 `)}export{f as default};
@@ -1,15 +1,19 @@
1
1
  import { TInput } from './type';
2
+ /**
3
+ * Внутренний каркас для {@link EmailField} / {@link UrlField}.
4
+ * Не экспортируется из пакета — снаружи используйте готовые поля.
5
+ */
2
6
  export type TNativeTextField = TInput & {
3
- /** data-field / визуальный тип обёртки */
7
+ /** `data-field` на корне (email / url). */
4
8
  fieldType: string;
5
- /** type у input */
9
+ /** HTML `type` у `<input>`. */
6
10
  inputType: "email" | "url" | "text" | "search" | "tel";
7
- /** fallback для aria-label, если нет label/placeholder */
11
+ /** aria-label, если нет `label` и `placeholder`. */
8
12
  defaultAriaLabel: string;
9
13
  };
10
14
  /**
11
- * Общее нативное текстовое поле (Email / Url и т.п.).
12
- * Подпись и ошибка связываются через Field a11y (htmlFor / aria-describedby).
15
+ * Нативный `<input>` внутри той же капсулы, что у остальных полей.
16
+ * **Элементы:** `label` капсула (`before` | input | `after`) → `error`.
13
17
  */
14
18
  declare function NativeTextField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, maxLength, autoComplete, inputmode, id, size, fieldType, inputType, defaultAriaLabel, }: TNativeTextField): import("react/jsx-runtime").JSX.Element | null;
15
19
  export default NativeTextField;
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import{isEmptyTextLike as i}from"./visibility.js";import{createFieldEmit as a}from"./emit.js";import o from"react";import{jsx as s,jsxs as c}from"react/jsx-runtime";function l({value:n=``,form:l,onValue:d,onBlur:f,name:p=``,placeholder:m=``,label:h=``,error:g=``,hidden:_=!1,disabled:v=!1,className:y=``,after:b=``,before:x=``,maxLength:S,autoComplete:C,inputmode:w,id:T,size:E=`md`,fieldType:D,inputType:O,defaultAriaLabel:k}){let{value:A,version:j}=r(l,p,n),M=!v,N=typeof A==`string`||typeof A==`number`?String(A):``,P=o.useRef(null),F=a(l,p,d);return o.useEffect(()=>{let e=P.current;!e||e.value===N||(e.value=N)},[N,j]),_&&i(A)?null:c(t,{type:D,label:h,error:g,id:T,size:E,element_blok:{className:[y||``]},element_input:{className:[e.w],props:{"data-disabled":v||!M?`true`:void 0}},children:[x?s(`span`,{className:e.a,children:x}):null,s(u,{inputRef:P,name:p,display:N,placeholder:m,maxLength:S,disabled:v,editable:M,autoComplete:C,inputMode:w,inputType:O,label:h,defaultAriaLabel:k,emit:F,onBlurField:f}),b?s(`span`,{className:e.a,children:b}):null]})}function u({inputRef:t,name:r,display:i,placeholder:a,maxLength:o,disabled:c,editable:l,autoComplete:u,inputMode:d,inputType:f,label:p,defaultAriaLabel:m,emit:h,onBlurField:g}){let _=n();return s(`div`,{className:e.x,children:s(`input`,{id:_?.controlId,ref:t,className:e.y,type:f,name:r||void 0,defaultValue:i,placeholder:a,maxLength:o,disabled:c,readOnly:!l,autoComplete:u,inputMode:d,spellCheck:!1,"aria-label":p?void 0:a||m,"aria-describedby":_?.describedBy,"aria-invalid":_?.errorId?!0:void 0,onChange:e=>h(e.target.value),onBlur:e=>{let t=(e.target.value||``).trim();h(t,!0),g?.({value:t,name:r})},onKeyDown:e=>{e.key===`Enter`&&e.preventDefault()}})})}export{l as default};
1
+ import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import{createFieldEmit as i}from"./emit.js";import{isEmptyTextLike as a}from"./visibility.js";import o from"react";import{jsx as s,jsxs as c}from"react/jsx-runtime";function l({value:n=``,form:l,onValue:d,onBlur:f,name:p=``,placeholder:m=``,label:h=``,error:g=``,hidden:_=!1,disabled:v=!1,className:y=``,after:b=``,before:x=``,maxLength:S,autoComplete:C,inputmode:w,id:T,size:E=`m`,fieldType:D,inputType:O,defaultAriaLabel:k}){let{value:A,version:j}=r(l,p,n),M=!v,N=typeof A==`string`||typeof A==`number`?String(A):``,P=o.useRef(null),F=i(l,p,d);return o.useEffect(()=>{let e=P.current;!e||e.value===N||(e.value=N)},[N,j]),_&&a(A)?null:c(t,{type:D,label:h,error:g,id:T,size:E,element_blok:{className:[y||``]},element_input:{className:[e.w],props:{"data-disabled":v||!M?`true`:void 0}},children:[x?s(`span`,{className:e.a,children:x}):null,s(u,{inputRef:P,name:p,display:N,placeholder:m,maxLength:S,disabled:v,editable:M,autoComplete:C,inputMode:w,inputType:O,label:h,defaultAriaLabel:k,emit:F,onBlurField:f}),b?s(`span`,{className:e.a,children:b}):null]})}function u({inputRef:t,name:r,display:i,placeholder:a,maxLength:o,disabled:c,editable:l,autoComplete:u,inputMode:d,inputType:f,label:p,defaultAriaLabel:m,emit:h,onBlurField:g}){let _=n();return s(`div`,{className:e.x,children:s(`input`,{id:_?.controlId,ref:t,className:e.y,type:f,name:r||void 0,defaultValue:i,placeholder:a,maxLength:o,disabled:c,readOnly:!l,autoComplete:u,inputMode:d,spellCheck:!1,"aria-label":p?void 0:a||m,"aria-describedby":_?.describedBy,"aria-invalid":_?.errorId?!0:void 0,onChange:e=>h(e.target.value),onBlur:e=>{let t=(e.target.value||``).trim();h(t,!0),g?.({value:t,name:r})},onKeyDown:e=>{e.key===`Enter`&&e.preventDefault()}})})}export{l as default};
@@ -1,18 +1,20 @@
1
1
  import { TInput } from './type';
2
2
  /**
3
- * NumberField — целые цифры как **строка** в форме (`"123"`).
3
+ * Целые цифры как **строка** в форме (`"123"`), не `number`.
4
4
  *
5
- * **Не путать с PercentField:**
6
- * - сюда в форму пишется **строка цифр**, не `number`;
7
- * - проп **`max`** (и `maxLength`) — лимит **символов**, не верхняя граница числа;
8
- * - дробных нет (только `\d`).
5
+ * `max` / `maxLength` — лимит **символов**, не максимум числа.
6
+ * Для 0–100 / `number` используйте {@link PercentField}.
9
7
  *
10
- * Для процентов / clamp 0–100 / `number` используйте **`PercentField`**.
8
+ * @example
9
+ * <NumberField name="qty" form={form} label="Кол-во" max={6} />
11
10
  */
12
- type TNumeric = TInput & {
13
- /** Макс. число символов (если нет `maxLength`). Не числовой максимум значения. */
11
+ export type TNumeric = TInput & {
12
+ /** Макс. число символов (если нет `maxLength`). Не верхняя граница значения. */
14
13
  max?: number;
15
14
  };
15
+ /**
16
+ * Поле целых цифр (строка в form).
17
+ */
16
18
  declare function NumberField({ value, form, onValue, name, placeholder, label, hidden, disabled, onBlur: onBlurField, className, after, before, error, size, inputmode, maxLength, max, view, }: TNumeric): import("react/jsx-runtime").JSX.Element | null;
17
19
  declare namespace NumberField {
18
20
  var displayName: string;
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import i,{asEditableClipboard as a}from"../events/onEvent.js";import{isEmptyTextLike as o}from"./visibility.js";import s from"react";import{jsx as c,jsxs as l}from"react/jsx-runtime";function u({value:n,form:u,onValue:f,name:p=``,placeholder:m=``,label:h=``,hidden:g=!1,disabled:_=!1,onBlur:v,className:y=``,after:b=``,before:x=``,error:S=``,size:C=`md`,inputmode:w=`numeric`,maxLength:T,max:E,view:D}){let O=!_,{value:k,version:A}=r(u,p,n);m=m===void 0?``:m,E=E===void 0?99:E;let j=k!=null&&k!==``?String(k):``,M=s.useRef(null),N=s.useRef(!1);s.useLayoutEffect(()=>{if(N.current)return;let e=M.current;e&&e.textContent!==j&&(e.textContent=j)},[j,A]);let P=T??E,F=(e,t)=>{e.textContent!==t&&(e.textContent=t,queueMicrotask(()=>{let n=e.firstChild;if(n&&n.nodeType===Node.TEXT_NODE){let e=t.length,r=window.getSelection(),i=document.createRange();i.setStart(n,e),i.collapse(!0),r?.removeAllRanges(),r?.addRange(i)}else t||(e.innerHTML=`<br>`)}))},I=e=>{let t=e.currentTarget,n=(t.textContent||``).replace(/\D/g,``);P>0&&n.length>P&&(n=n.slice(0,P)),F(t,n);let r={value:n,name:p};u&&p&&u.onValue(r),f&&f!==u?.onValue&&f(r)},L=e=>{N.current=!0;let t=e.currentTarget;t.textContent=(t.textContent||``).replace(/\D/g,``),i.Focus({target:e.currentTarget})},R=e=>{if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`v`||e.key===`Backspace`)return;let t=(e.currentTarget.textContent??``).replace(/\D/g,``).length;P>0&&t>=P&&e.key.length===1&&/\d/.test(e.key)&&e.preventDefault(),e.key===`Enter`&&e.preventDefault(),e.key.length===1&&!/\d/.test(e.key)&&!e.metaKey&&!e.ctrlKey&&e.preventDefault()},z=e=>{i.PasteDigits(P,a(e)),queueMicrotask(()=>{let e=M.current;if(!e)return;let t=(e.textContent||``).replace(/\D/g,``);P>0&&t.length>P&&(t=t.slice(0,P)),F(e,t),u&&p&&u.onValue({value:t,name:p})})},B=e=>{e.preventDefault()},V=e=>{i.Blur(e);let t=(e.currentTarget.textContent||``).replace(/\D/g,``);e.currentTarget.textContent!==t&&(e.currentTarget.textContent=t),v?.({value:t,name:p}),N.current=!1},H={};return O&&(H.edit=``),H.inputMode=w??`numeric`,m&&(H.placeholder=m),g&&o(k)?null:l(t,{type:`numeric`,label:h,error:S,size:C,element_blok:{className:[y||``]},element_input:{className:[e.w]},children:[x?c(`span`,{className:e.a,children:x}):null,c(d,{divRef:M,editable:O,label:h,placeholder:m,dd:H,onPaste:z,onDrop:B,onInput:I,onFocus:L,onBlur:V,onKeyDown:R}),b?c(`span`,{className:e.a,children:b}):null]})}function d({divRef:e,editable:t,label:r,placeholder:i,dd:a,onPaste:o,onDrop:s,onInput:l,onFocus:u,onBlur:d,onKeyDown:f}){let p=n();return c(`div`,{ref:e,id:p?.controlId,onPaste:o,onDrop:s,onDragOver:e=>e.preventDefault(),onInput:l,onFocus:u,onBlur:d,onKeyDown:f,spellCheck:!1,role:`textbox`,"aria-multiline":`false`,tabIndex:t?0:-1,"aria-label":r?void 0:i||`Число`,"aria-describedby":p?.describedBy,"aria-invalid":p?.errorId?!0:void 0,contentEditable:t?`plaintext-only`:!1,suppressContentEditableWarning:!0,...a})}u.displayName=`NumberField`;export{u as default};
1
+ import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import{createFieldEmit as i}from"./emit.js";import a,{asEditableClipboard as o}from"../events/onEvent.js";import{isEmptyTextLike as s}from"./visibility.js";import c from"react";import{jsx as l,jsxs as u}from"react/jsx-runtime";function d({value:n,form:d,onValue:p,name:m=``,placeholder:h=``,label:g=``,hidden:_=!1,disabled:v=!1,onBlur:y,className:b=``,after:x=``,before:S=``,error:C=``,size:w=`m`,inputmode:T=`numeric`,maxLength:E,max:D,view:O}){let k=!v,{value:A,version:j}=r(d,m,n);h=h===void 0?``:h,D=D===void 0?99:D;let M=A!=null&&A!==``?String(A):``,N=c.useRef(null),P=c.useRef(!1);c.useLayoutEffect(()=>{if(P.current)return;let e=N.current;e&&e.textContent!==M&&(e.textContent=M)},[M,j]);let F=E??D,I=(e,t)=>{e.textContent!==t&&(e.textContent=t,queueMicrotask(()=>{let n=e.firstChild;if(n&&n.nodeType===Node.TEXT_NODE){let e=t.length,r=window.getSelection(),i=document.createRange();i.setStart(n,e),i.collapse(!0),r?.removeAllRanges(),r?.addRange(i)}else t||(e.innerHTML=`<br>`)}))},L=i(d,m,p),R=e=>{let t=e.currentTarget,n=(t.textContent||``).replace(/\D/g,``);F>0&&n.length>F&&(n=n.slice(0,F)),I(t,n),L(n)},z=e=>{P.current=!0;let t=e.currentTarget;t.textContent=(t.textContent||``).replace(/\D/g,``),a.Focus({target:e.currentTarget})},B=e=>{if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`v`||e.key===`Backspace`)return;let t=(e.currentTarget.textContent??``).replace(/\D/g,``).length;F>0&&t>=F&&e.key.length===1&&/\d/.test(e.key)&&e.preventDefault(),e.key===`Enter`&&e.preventDefault(),e.key.length===1&&!/\d/.test(e.key)&&!e.metaKey&&!e.ctrlKey&&e.preventDefault()},V=e=>{a.PasteDigits(F,o(e)),queueMicrotask(()=>{let e=N.current;if(!e)return;let t=(e.textContent||``).replace(/\D/g,``);F>0&&t.length>F&&(t=t.slice(0,F)),I(e,t),L(t)})},H=e=>{e.preventDefault()},U=e=>{a.Blur(e);let t=(e.currentTarget.textContent||``).replace(/\D/g,``);e.currentTarget.textContent!==t&&(e.currentTarget.textContent=t),y?.({value:t,name:m}),P.current=!1},W={};return k&&(W.edit=``),W.inputMode=T??`numeric`,h&&(W.placeholder=h),_&&s(A)?null:u(t,{type:`numeric`,label:g,error:C,size:w,element_blok:{className:[b||``]},element_input:{className:[e.w],props:{"data-disabled":v||!k?`true`:void 0}},children:[S?l(`span`,{className:e.a,children:S}):null,l(f,{divRef:N,editable:k,label:g,placeholder:h,dd:W,onPaste:V,onDrop:H,onInput:R,onFocus:z,onBlur:U,onKeyDown:B}),x?l(`span`,{className:e.a,children:x}):null]})}function f({divRef:e,editable:t,label:r,placeholder:i,dd:a,onPaste:o,onDrop:s,onInput:c,onFocus:u,onBlur:d,onKeyDown:f}){let p=n();return l(`div`,{ref:e,id:p?.controlId,onPaste:o,onDrop:s,onDragOver:e=>e.preventDefault(),onInput:c,onFocus:u,onBlur:d,onKeyDown:f,spellCheck:!1,role:`textbox`,"aria-multiline":`false`,tabIndex:t?0:-1,"aria-label":r?void 0:i||`Число`,"aria-disabled":t?void 0:!0,"aria-describedby":p?.describedBy,"aria-invalid":p?.errorId?!0:void 0,contentEditable:t?`plaintext-only`:!1,suppressContentEditableWarning:!0,...a})}d.displayName=`NumberField`;export{d as default};
@@ -1,31 +1,50 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { UseFormApi } from '../hooks/use';
3
3
  import { TValue } from './type';
4
- interface Input {
4
+ /**
5
+ * Выбор через модалку приложения (`Form.Init.onModal`).
6
+ *
7
+ * **В форме:** зависит от `outFormat`: строка ключей, массив или объект-флаги.
8
+ *
9
+ * **Элементы:** капсула-колонка выбранных подписей (`options[id].label`). Клик открывает модалку
10
+ * `modal` вида `"module.name"` (или `module` + `modal`).
11
+ *
12
+ * Нужен {@link Form.Init}.
13
+ *
14
+ * @example
15
+ * <OptionsField name="users" form={form} label="Сотрудники" modal="crm.pickUser" outFormat="string" />
16
+ */
17
+ export type TOptions = {
5
18
  value?: string;
6
19
  form?: UseFormApi;
7
20
  onValue?: (data: TValue) => void | Promise<void>;
8
21
  name: string;
9
22
  placeholder?: string;
10
- /** Подпись поля */
11
23
  label?: string;
12
24
  error?: string;
13
25
  hidden?: boolean;
14
- /** true — блок выбора не открывается */
15
26
  disabled?: boolean;
16
27
  after?: ReactNode;
17
28
  before?: ReactNode;
18
29
  view?: string;
19
30
  className?: string;
31
+ /** Имя модуля модалки, если `modal` без точки */
20
32
  module?: string;
33
+ /** `"module.modalName"` или имя модалки вместе с `module` */
21
34
  modal?: string;
35
+ /** Подписи выбранных ключей: `{ [id]: { label } }` */
22
36
  options?: Record<string, {
23
37
  label?: string;
24
38
  }>;
39
+ /** Как писать выбор в форму. @default зависит от текущего value */
25
40
  outFormat?: "array" | "string" | "object";
41
+ /** Разделитель ключей при `outFormat="string"`. @default "," */
26
42
  separator?: string;
27
- }
28
- declare function OptionsField({ value, form, onValue, name, placeholder, separator, label, error, hidden, disabled, outFormat, after, before, modal, options, className, }: Input): import("react/jsx-runtime").JSX.Element;
43
+ };
44
+ /**
45
+ * Список выбранных значений; клик по капсуле открывает модалку приложения.
46
+ */
47
+ declare function OptionsField({ value, form, onValue, name, placeholder, separator, label, error, hidden, disabled, outFormat, after, before, modal, options, className, }: TOptions): import("react/jsx-runtime").JSX.Element;
29
48
  declare namespace OptionsField {
30
49
  var displayName: string;
31
50
  }
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import{useFormInit as r}from"../FormInitContext.js";import{Fragment as i,jsx as a,jsxs as o}from"react/jsx-runtime";var s=(e,t=`,`)=>(e!==void 0&&e!==``?e.split(t):[]).filter(e=>e!==``).reduce((e,t)=>(e[t]=!0,e),{});function c({value:c,form:l,onValue:u,name:d,placeholder:f=``,separator:p=`,`,label:m,error:h,hidden:g=!1,disabled:_=!1,outFormat:v=`object`,after:y,before:b,modal:x,options:S,className:C}){let{onModal:w}=r(),{value:T}=n(l,d,c),E=T,D=typeof E==`string`?s(E,p):E&&typeof E==`object`?E:{},O=()=>{if(_||!x)return;let e=x.split(`.`);w({module:e[0],modalName:e[1],callback:e=>{let t=e;if(u)switch(v===`array`||v===`string`&&Object.keys(t).filter(e=>t[e]).join(p),v){case`array`:u!==l?.onValue&&u({value:Object.keys(t),name:d});break;case`string`:u!==l?.onValue&&u({value:Object.keys(t).filter(e=>t[e]).join(p),name:d});break;default:u!==l?.onValue&&u({value:t,name:d})}},onValue:u,options:S,fieldName:d,value:D})},k={};f&&(k.placeholder=f);let A=Object.keys(D).length===0;return g&&A?a(i,{}):o(t,{type:`group`,label:m,error:h,element_blok:{className:[C||``]},element_input:{className:[e.g],props:{onClick:O}},children:[b?a(`span`,{className:e.a,children:b}):null,Object.keys(D).map(e=>a(`div`,{children:S?.[e]?.label},e)),y?a(`span`,{className:e.a,children:y}):null]})}c.displayName=`OptionsField`;export{c as default};
1
+ import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import{createFieldEmit as r}from"./emit.js";import{useFormInit as i}from"../FormInitContext.js";import{Fragment as a,jsx as o,jsxs as s}from"react/jsx-runtime";var c=(e,t=`,`)=>(e!==void 0&&e!==``?e.split(t):[]).filter(e=>e!==``).reduce((e,t)=>(e[t]=!0,e),{});function l({value:l,form:u,onValue:d,name:f,placeholder:p=``,separator:m=`,`,label:h,error:g,hidden:_=!1,disabled:v=!1,outFormat:y=`object`,after:b,before:x,modal:S,options:C,className:w}){let{onModal:T}=i(),{value:E}=n(u,f,l),D=E,O=typeof D==`string`?c(D,m):D&&typeof D==`object`?D:{},k=()=>{if(v||!S)return;let e=S.split(`.`);T({module:e[0],modalName:e[1],callback:e=>{let t=e,n=y===`array`?Object.keys(t):y===`string`?Object.keys(t).filter(e=>t[e]).join(m):t;r(u,f,d)(n,!0)},onValue:d,options:C,fieldName:f,value:O})},A={};p&&(A.placeholder=p);let j=Object.keys(O).length===0;return _&&j?o(a,{}):s(t,{type:`options`,label:h,error:g,element_blok:{className:[w||``]},element_input:{className:[e.g],props:{onClick:k,"data-disabled":v?`true`:void 0}},children:[x?o(`span`,{className:e.a,children:x}):null,Object.keys(O).map(e=>o(`div`,{children:C?.[e]?.label},e)),b?o(`span`,{className:e.a,children:b}):null]})}l.displayName=`OptionsField`;export{l as default};
@@ -1,4 +1,15 @@
1
1
  import { TPasswordField } from './type';
2
+ /**
3
+ * Пароль с переключателем видимости (кнопка-глаз в слоте `after`).
4
+ *
5
+ * **В форме:** `string`.
6
+ *
7
+ * **Элементы:** капсула + `<input type="password"|text>` + кнопка глаза.
8
+ * Проп `native` **скрывает весь компонент** (не делает input) — см. {@link TPasswordField}.
9
+ *
10
+ * @example
11
+ * <PasswordField name="password" form={form} label="Пароль" autoComplete="current-password" />
12
+ */
2
13
  declare function PasswordField({ value, form, onValue, name, placeholder, label, error, hidden, disabled, onBlur: onBlurField, className, after, before, native, maxLength, eyes, id, size, }: TPasswordField): import("react/jsx-runtime").JSX.Element | "";
3
14
  declare namespace PasswordField {
4
15
  var displayName: string;
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import i from"../events/onEvent.js";import{isEmptyTextLike as a}from"./visibility.js";import o from"react";import{jsx as s,jsxs as c}from"react/jsx-runtime";function l(){return c(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":!0,children:[s(`path`,{d:`M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z`}),s(`circle`,{cx:`12`,cy:`12`,r:`3`})]})}function u(){return c(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":!0,children:[s(`path`,{d:`M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24`}),s(`line`,{x1:`1`,y1:`1`,x2:`23`,y2:`23`})]})}function d({value:n,form:d,onValue:p,name:m=``,placeholder:h=``,label:g,error:_,hidden:v=!1,disabled:y=!1,onBlur:b,className:x,after:S=``,before:C=``,native:w=!1,maxLength:T,eyes:E,id:D,size:O=`md`}){let{value:k}=r(d,m,n),[A,j]=o.useState(!1),M=o.useRef(null),N=typeof k==`string`?k:k==null?``:String(k);o.useEffect(()=>{let e=M.current;e&&e.value!==N&&(e.value=N)},[N]);let P=e=>{let t={value:e,name:m};d&&m&&d.onValue(t),p&&p!==d?.onValue&&p(t)},F=e=>{P(e.target.value)},I=e=>{e.key===`Enter`&&e.preventDefault()},L=e=>{i.Blur(e),b?.({value:(e.target.value||``).trim(),name:m||``})};if(w)return``;let R=!y;if(v&&a(N))return``;let z=E?.[0]??s(l,{}),B=E?.[1]??s(u,{});return c(t,{type:`input`,label:g,error:_,id:D,size:O,element_blok:{className:[x||``]},element_input:{className:[e.w],props:{"data-disabled":y||!R?`true`:void 0}},children:[C?s(`span`,{className:e.a,children:C}):null,s(f,{inputRef:M,passwordVisible:A,currentValue:N,disabled:y,editable:R,maxLength:T,placeholder:h,label:g,onChangeInput:F,keyDown:I,handleBlur:L}),s(`button`,{type:`button`,className:e.a,tabIndex:y?-1:0,"aria-label":A?`Скрыть пароль`:`Показать пароль`,"aria-pressed":A,disabled:y,onClick:()=>!y&&j(!A),children:A?B:z}),S?s(`span`,{className:e.a,children:S}):null]})}function f({inputRef:t,passwordVisible:r,currentValue:i,disabled:a,editable:o,maxLength:c,placeholder:l,label:u,onChangeInput:d,keyDown:f,handleBlur:p}){let m=n();return s(`div`,{className:e.x,children:s(`input`,{id:m?.controlId,className:e.y,type:r?`text`:`password`,defaultValue:i,ref:t,onChange:d,onKeyDown:f,onBlur:p,disabled:a,readOnly:a,maxLength:c,spellCheck:!1,autoComplete:`current-password`,"aria-label":u?void 0:l||`Пароль`,"aria-describedby":m?.describedBy,"aria-invalid":m?.errorId?!0:void 0,"aria-disabled":a||!o,tabIndex:a?-1:0,placeholder:l})})}d.displayName=`PasswordField`;export{d as default};
1
+ import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import{createFieldEmit as i}from"./emit.js";import a from"../events/onEvent.js";import{isEmptyTextLike as o}from"./visibility.js";import s from"react";import{jsx as c,jsxs as l}from"react/jsx-runtime";function u(){return l(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":!0,children:[c(`path`,{d:`M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z`}),c(`circle`,{cx:`12`,cy:`12`,r:`3`})]})}function d(){return l(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":!0,children:[c(`path`,{d:`M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24`}),c(`line`,{x1:`1`,y1:`1`,x2:`23`,y2:`23`})]})}function f({value:n,form:f,onValue:m,name:h=``,placeholder:g=``,label:_,error:v,hidden:y=!1,disabled:b=!1,onBlur:x,className:S,after:C=``,before:w=``,native:T=!1,maxLength:E,eyes:D,id:O,size:k=`m`}){let{value:A}=r(f,h,n),[j,M]=s.useState(!1),N=s.useRef(null),P=typeof A==`string`?A:A==null?``:String(A);s.useEffect(()=>{let e=N.current;e&&e.value!==P&&(e.value=P)},[P]);let F=i(f,h,m),I=e=>{F(e.target.value)},L=e=>{e.key===`Enter`&&e.preventDefault()},R=e=>{a.Blur(e),x?.({value:(e.target.value||``).trim(),name:h||``})};if(T)return``;let z=!b;if(y&&o(P))return``;let B=D?.[0]??c(u,{}),V=D?.[1]??c(d,{});return l(t,{type:`input`,label:_,error:v,id:O,size:k,element_blok:{className:[S||``]},element_input:{className:[e.w],props:{"data-disabled":b||!z?`true`:void 0}},children:[w?c(`span`,{className:e.a,children:w}):null,c(p,{inputRef:N,passwordVisible:j,currentValue:P,disabled:b,editable:z,maxLength:E,placeholder:g,label:_,onChangeInput:I,keyDown:L,handleBlur:R}),c(`button`,{type:`button`,className:e.a,tabIndex:b?-1:0,"aria-label":j?`Скрыть пароль`:`Показать пароль`,"aria-pressed":j,disabled:b,onClick:()=>!b&&M(!j),children:j?V:B}),C?c(`span`,{className:e.a,children:C}):null]})}function p({inputRef:t,passwordVisible:r,currentValue:i,disabled:a,editable:o,maxLength:s,placeholder:l,label:u,onChangeInput:d,keyDown:f,handleBlur:p}){let m=n();return c(`div`,{className:e.x,children:c(`input`,{id:m?.controlId,className:e.y,type:r?`text`:`password`,defaultValue:i,ref:t,onChange:d,onKeyDown:f,onBlur:p,disabled:a,readOnly:a,maxLength:s,spellCheck:!1,autoComplete:`current-password`,"aria-label":u?void 0:l||`Пароль`,"aria-describedby":m?.describedBy,"aria-invalid":m?.errorId?!0:void 0,"aria-disabled":a||!o,tabIndex:a?-1:0,placeholder:l})})}f.displayName=`PasswordField`;export{f as default};
@@ -1,11 +1,12 @@
1
1
  import { TInput } from './type';
2
- /** PercentField — процент как **number** в форме (не строка).
2
+ /**
3
+ * Процент как **`number`** в форме (не строка).
3
4
  *
4
- * Отличия от NumberField:
5
- * - значение: `number` (или `""` / пусто), не строка цифр;
6
- * - `min`/`max` — границы **числа** (по умолчанию 0–100), clamp на blur;
7
- * - `decimals` — дробная часть;
8
- * - справа по умолчанию аффикс `%`.
5
+ * Отличия от {@link NumberField}: значение `number`; `min`/`max` — границы числа (по умолчанию 0–100);
6
+ * `decimals` дробная часть; справа по умолчанию аффикс `%`.
7
+ *
8
+ * @example
9
+ * <PercentField name="vat" form={form} label="НДС" min={0} max={100} decimals={2} />
9
10
  */
10
11
  export type TPercent = TInput & {
11
12
  min?: number;
@@ -13,6 +14,9 @@ export type TPercent = TInput & {
13
14
  /** Допускать дробную часть */
14
15
  decimals?: number;
15
16
  };
17
+ /**
18
+ * Поле процента. Не путать с {@link NumberField} (там строка цифр).
19
+ */
16
20
  declare function PercentField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, min, max, decimals, inputmode, }: TPercent): import("react/jsx-runtime").JSX.Element | null;
17
21
  declare namespace PercentField {
18
22
  var displayName: string;
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import r,{asEditableClipboard as i}from"../events/onEvent.js";import a from"react";import{jsx as o,jsxs as s}from"react/jsx-runtime";function c(e,t,n){return Number.isFinite(e)?Math.min(n,Math.max(t,e)):t}function l(e,t){let n=e.replace(`,`,`.`).replace(/[^\d.]/g,``);if(!n)return null;let r=Number(n);if(!Number.isFinite(r))return null;if(t<=0)return Math.round(r);let i=10**t;return Math.round(r*i)/i}function u(e,t){return Number.isFinite(e)?String(t<=0?Math.round(e):Number(e.toFixed(t))):``}function d({value:d=0,form:f,onValue:p,onBlur:m,name:h=``,placeholder:g=`0`,label:_=``,error:v=``,hidden:y=!1,disabled:b=!1,className:x=``,after:S,before:C=``,min:w=0,max:T=100,decimals:E=0,inputmode:D=`decimal`}){let{value:O,version:k}=n(f,h,d),A=!b,j=c(Number(O),w,T),M=O==null||O===``?``:u(j,E),N=a.useRef(null),P=a.useRef(!1);a.useLayoutEffect(()=>{if(P.current)return;let e=N.current;e&&e.textContent!==M&&(e.textContent=M)},[M,k]);let F=(e,t=!1)=>{let n={value:e,name:h};if(f&&h)if(t){let t=f.getValue(h);Object.is(t,e)?f.onValue(n):f.setValue(n)}else f.onValue(n);p&&p!==f?.onValue&&p(n)},I=e=>{let t=(e.currentTarget.textContent||``).replace(/[^\d.,]/g,``);e.currentTarget.textContent!==t&&(e.currentTarget.textContent=t);let n=l(t,E);if(n===null){F(``);return}F(c(n,w,T))},L=e=>{r.Blur(e),P.current=!1;let t=l(e.currentTarget.textContent||``,E),n=t===null?w:c(t,w,T),i=u(n,E);e.currentTarget.textContent!==i&&(e.currentTarget.textContent=i),F(n,!0),m?.({value:n,name:h})};if(y&&(O==null||O===``))return null;let R={};return g&&(R.placeholder=g),A&&(R.edit=``),R.inputMode=D||`decimal`,s(t,{type:`percent`,label:_,error:v,element_blok:{className:[x||``]},element_input:{className:[e.w],props:{"data-disabled":b||!A?`true`:void 0}},children:[C?o(`span`,{className:e.a,children:C}):null,o(`div`,{ref:N,onInput:I,onFocus:e=>{P.current=!0,r.Focus({target:e.currentTarget})},onBlur:L,onPaste:e=>r.Paste(12,i(e)),onKeyDown:e=>{e.key===`Enter`&&e.preventDefault(),e.key.length===1&&!/[\d.,]/.test(e.key)&&!e.metaKey&&!e.ctrlKey&&e.preventDefault()},spellCheck:!1,role:`textbox`,tabIndex:A?0:-1,"aria-label":_||g||`Процент`,contentEditable:A?`plaintext-only`:!1,suppressContentEditableWarning:!0,...R}),S===void 0?o(`span`,{className:e.a,children:`%`}):o(`span`,{className:e.a,children:S})]})}d.displayName=`PercentField`;export{d as default};
1
+ import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import{createFieldEmit as r}from"./emit.js";import i,{asEditableClipboard as a}from"../events/onEvent.js";import o from"react";import{jsx as s,jsxs as c}from"react/jsx-runtime";function l(e,t,n){return Number.isFinite(e)?Math.min(n,Math.max(t,e)):t}function u(e,t){let n=e.replace(`,`,`.`).replace(/[^\d.]/g,``);if(!n)return null;let r=Number(n);if(!Number.isFinite(r))return null;if(t<=0)return Math.round(r);let i=10**t;return Math.round(r*i)/i}function d(e,t){return Number.isFinite(e)?String(t<=0?Math.round(e):Number(e.toFixed(t))):``}function f({value:f=0,form:p,onValue:m,onBlur:h,name:g=``,placeholder:_=`0`,label:v=``,error:y=``,hidden:b=!1,disabled:x=!1,className:S=``,after:C,before:w=``,min:T=0,max:E=100,decimals:D=0,inputmode:O=`decimal`}){let{value:k,version:A}=n(p,g,f),j=!x,M=l(Number(k),T,E),N=k==null||k===``?``:d(M,D),P=o.useRef(null),F=o.useRef(!1);o.useLayoutEffect(()=>{if(F.current)return;let e=P.current;e&&e.textContent!==N&&(e.textContent=N)},[N,A]);let I=r(p,g,m),L=e=>{let t=(e.currentTarget.textContent||``).replace(/[^\d.,]/g,``);e.currentTarget.textContent!==t&&(e.currentTarget.textContent=t);let n=u(t,D);if(n===null){I(``);return}I(l(n,T,E))},R=e=>{i.Blur(e),F.current=!1;let t=u(e.currentTarget.textContent||``,D),n=t===null?T:l(t,T,E),r=d(n,D);e.currentTarget.textContent!==r&&(e.currentTarget.textContent=r),I(n,!0),h?.({value:n,name:g})};if(b&&(k==null||k===``))return null;let z={};return _&&(z.placeholder=_),j&&(z.edit=``),z.inputMode=O||`decimal`,c(t,{type:`percent`,label:v,error:y,element_blok:{className:[S||``]},element_input:{className:[e.w],props:{"data-disabled":x||!j?`true`:void 0}},children:[w?s(`span`,{className:e.a,children:w}):null,s(`div`,{ref:P,onInput:L,onFocus:e=>{F.current=!0,i.Focus({target:e.currentTarget})},onBlur:R,onPaste:e=>i.Paste(12,a(e)),onKeyDown:e=>{e.key===`Enter`&&e.preventDefault(),e.key.length===1&&!/[\d.,]/.test(e.key)&&!e.metaKey&&!e.ctrlKey&&e.preventDefault()},spellCheck:!1,role:`textbox`,tabIndex:j?0:-1,"aria-label":v||_||`Процент`,contentEditable:j?`plaintext-only`:!1,suppressContentEditableWarning:!0,...z}),C===void 0?s(`span`,{className:e.a,children:`%`}):s(`span`,{className:e.a,children:C})]})}f.displayName=`PercentField`;export{f as default};
@@ -1,5 +1,17 @@
1
1
  import { TInput } from './type';
2
- /** PhoneField — телефон с маской; полный каталог стран подгружается при фокусе. */
2
+ /**
3
+ * Телефон с маской по стране. В форму пишутся **только цифры** (без `+` и скобок).
4
+ *
5
+ * **В форме:** `string` цифр.
6
+ *
7
+ * **Элементы:** капсула, contentEditable по шаблону; полный каталог масок — lazy при фокусе.
8
+ * Копирование может вызвать `Form.Init.onNotice`.
9
+ *
10
+ * Пропы — {@link TInput}.
11
+ *
12
+ * @example
13
+ * <PhoneField name="phone" form={form} label="Телефон" />
14
+ */
3
15
  declare function PhoneField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, inputmode, id, }: TInput): import("react/jsx-runtime").JSX.Element | null;
4
16
  declare namespace PhoneField {
5
17
  var displayName: string;
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import i,{asEditableClipboard as a}from"../events/onEvent.js";import{isEmptyTextLike as o}from"./visibility.js";import{PHONE_MASK_DEFAULTS as s}from"../mask/phoneDefaults.js";import{useFormInit as c}from"../FormInitContext.js";import l from"react";import{jsx as u,jsxs as d}from"react/jsx-runtime";var f={...s},p=!1,m=null;function h(){return p?Promise.resolve(!1):m||(m=import(`../mask/MaskPhone.js`).then(e=>(f={...s,...e.default},p=!0,!0)),m)}function g(e){let t=window.getSelection();if(!t||t.rangeCount===0)return 0;let n=t.getRangeAt(0);if(!e.contains(n.startContainer))return 0;let r=document.createRange();return r.selectNodeContents(e),r.setEnd(n.startContainer,n.startOffset),r.toString().length}function _(e,t){if(t<=0)return 0;let n=0;for(let r=0;r<e.length;r++)if(/\d/.test(e[r])&&(n++,n===t))return r+1;return e.length}function v(e){let t=`+_(___) ___-__-__`,n=!0,r=0,i=0,a=``,o=e.replace(/\D/g,``);o===``&&(n=!0);let s=o.split(``),c=``;s.forEach(e=>{n&&(c+=e,f[c]!==void 0&&n?(n=!1,t=f[c].mask.replace(RegExp(`[0-9]`,`g`),`_`),a=f[c].code):(n&&(r=(``+c).length,t=`+${c}_(___) ___-__-__`.replace(RegExp(`[0-9]`,`g`),`_`),a=``),r>(``+c).length&&(n=!0,t=`+${c}_(___) ___-__-__`.replace(RegExp(`[0-9]`,`g`),`_`),a=``)))});let l=t.replace(/\D/g,``);return l.length>=o.length&&(o=l),{q:t.replace(/[_\d]/g,function(){return o.charAt(i++)||`_`}),i,v:o,f:a}}function y({value:n,form:s,onValue:f,onBlur:p,name:m=``,placeholder:y=``,label:x=``,error:S=``,hidden:C=!1,disabled:w=!1,className:T=``,after:E=``,before:D=``,inputmode:O=`tel`,id:k}){let{onNotice:A}=c(),j=!w,{value:M,version:N}=r(s,m,n),[,P]=l.useState(0),F=l.useRef(null),I=l.useRef(!1),L=(e,t)=>{let n=t.firstChild;if(!n||n.nodeType!==Node.TEXT_NODE)return;let r=n.textContent?.length??0,i=Math.max(0,Math.min(e,r)),a=document.createRange(),o=window.getSelection();o&&(a.setStart(n,i),a.collapse(!0),o.removeAllRanges(),o.addRange(a),t.focus())},R=e=>{let t=e.target,n=t.textContent||``,r=g(t),i=n.slice(0,r).replace(/\D/g,``).length,a=v(n);t.textContent=a.q;let o=_(a.q,i);a.q.length>0&&queueMicrotask(()=>{L(Math.min(o,a.q.length),t)});let c={value:a.q.replace(/\D/g,``),name:m||``};s&&m&&s.onValue(c),f&&f!==s?.onValue&&f(c)},z=e=>i.PasteOne(a(e));l.useLayoutEffect(()=>{if(I.current)return;let e=F.current;if(!e)return;let t=v(String(M||``));e.textContent!==t.q&&(e.textContent=t.q)},[M,N]);let B=e=>{e.preventDefault();let t=e.target;navigator.clipboard.writeText((t.textContent||``).replace(/\D/g,``)).then(function(){A(`Данные в буфер обмене`)},function(e){})},V=e=>{e.key===`Enter`&&e.preventDefault()},H=e=>{i.Blur(e),p&&p({value:(e.target.textContent||``).replace(/\D/g,``),name:m||``}),I.current=!1},U=e=>{I.current=!0,i.Focus({target:e.currentTarget}),h().then(e=>{if(!e)return;P(e=>e+1);let t=F.current;if(!t||document.activeElement!==t)return;let n=t.textContent||``,r=g(t),i=n.slice(0,r).replace(/\D/g,``).length,a=v(n);t.textContent!==a.q&&(t.textContent=a.q,queueMicrotask(()=>{L(Math.min(_(a.q,i),a.q.length),t)}))})},W={};y&&(W.placeholder=y),W.inputMode=O??`tel`;let G=String(M??``).replace(/\D/g,``);return C&&o(G)?null:d(t,{type:`input`,label:x,error:S,id:k,element_blok:{className:[T]},element_input:{className:[e.w]},children:[D?u(`span`,{className:e.a,children:D}):null,u(b,{divRef:F,editable:j,disabled:w,label:x,placeholder:y,dd:W,onPaste:z,onInput:R,onKeyDown:V,onContextMenu:B,onBlur:H,onFocus:U}),E?u(`span`,{className:e.a,children:E}):null]})}function b({divRef:e,editable:t,disabled:r,label:i,placeholder:a,dd:o,onPaste:s,onInput:c,onKeyDown:l,onContextMenu:d,onBlur:f,onFocus:p}){let m=n();return u(`div`,{ref:e,id:m?.controlId,onPaste:s,onInput:c,onKeyDown:l,onContextMenu:d,onBlur:f,onFocus:p,spellCheck:!1,role:`textbox`,"aria-label":i?void 0:a||`Телефон`,"aria-describedby":m?.describedBy,"aria-invalid":m?.errorId?!0:void 0,"aria-disabled":!t,tabIndex:r?-1:0,"data-disabled":!t,contentEditable:t?`plaintext-only`:!1,suppressContentEditableWarning:!0,...o})}y.displayName=`PhoneField`;export{y as default};
1
+ import e from"../styles/Field.module.js";import t,{useFieldA11y as n}from"../core/Field.js";import{useFormFieldState as r}from"../hooks/use.js";import{createFieldEmit as i}from"./emit.js";import a,{asEditableClipboard as o}from"../events/onEvent.js";import{isEmptyTextLike as s}from"./visibility.js";import{PHONE_MASK_DEFAULTS as c}from"../mask/phoneDefaults.js";import{useFormInit as l}from"../FormInitContext.js";import u from"react";import{jsx as d,jsxs as f}from"react/jsx-runtime";var p={...c},m=!1,h=null;function g(){return m?Promise.resolve(!1):h||(h=import(`../mask/MaskPhone.js`).then(e=>(p={...c,...e.default},m=!0,!0)),h)}function _(e){let t=window.getSelection();if(!t||t.rangeCount===0)return 0;let n=t.getRangeAt(0);if(!e.contains(n.startContainer))return 0;let r=document.createRange();return r.selectNodeContents(e),r.setEnd(n.startContainer,n.startOffset),r.toString().length}function v(e,t){if(t<=0)return 0;let n=0;for(let r=0;r<e.length;r++)if(/\d/.test(e[r])&&(n++,n===t))return r+1;return e.length}function y(e){let t=`+_(___) ___-__-__`,n=!0,r=0,i=0,a=``,o=e.replace(/\D/g,``);o===``&&(n=!0);let s=o.split(``),c=``;s.forEach(e=>{n&&(c+=e,p[c]!==void 0&&n?(n=!1,t=p[c].mask.replace(RegExp(`[0-9]`,`g`),`_`),a=p[c].code):(n&&(r=(``+c).length,t=`+${c}_(___) ___-__-__`.replace(RegExp(`[0-9]`,`g`),`_`),a=``),r>(``+c).length&&(n=!0,t=`+${c}_(___) ___-__-__`.replace(RegExp(`[0-9]`,`g`),`_`),a=``)))});let l=t.replace(/\D/g,``);return l.length>=o.length&&(o=l),{q:t.replace(/[_\d]/g,function(){return o.charAt(i++)||`_`}),i,v:o,f:a}}function b({value:n,form:c,onValue:p,onBlur:m,name:h=``,placeholder:b=``,label:S=``,error:C=``,hidden:w=!1,disabled:T=!1,className:E=``,after:D=``,before:O=``,inputmode:k=`tel`,id:A}){let{onNotice:j}=l(),M=!T,{value:N,version:P}=r(c,h,n),[,F]=u.useState(0),I=u.useRef(null),L=u.useRef(!1),R=(e,t)=>{let n=t.firstChild;if(!n||n.nodeType!==Node.TEXT_NODE)return;let r=n.textContent?.length??0,i=Math.max(0,Math.min(e,r)),a=document.createRange(),o=window.getSelection();o&&(a.setStart(n,i),a.collapse(!0),o.removeAllRanges(),o.addRange(a),t.focus())},z=i(c,h,p),B=e=>{let t=e.target,n=t.textContent||``,r=_(t),i=n.slice(0,r).replace(/\D/g,``).length,a=y(n);t.textContent=a.q;let o=v(a.q,i);a.q.length>0&&queueMicrotask(()=>{R(Math.min(o,a.q.length),t)}),z(a.q.replace(/\D/g,``))},V=e=>a.PasteOne(o(e));u.useLayoutEffect(()=>{if(L.current)return;let e=I.current;if(!e)return;let t=y(String(N||``));e.textContent!==t.q&&(e.textContent=t.q)},[N,P]);let H=e=>{e.preventDefault();let t=e.target;navigator.clipboard.writeText((t.textContent||``).replace(/\D/g,``)).then(function(){j(`Данные в буфер обмене`)},function(e){})},U=e=>{e.key===`Enter`&&e.preventDefault()},W=e=>{a.Blur(e),m&&m({value:(e.target.textContent||``).replace(/\D/g,``),name:h||``}),L.current=!1},G=e=>{L.current=!0,a.Focus({target:e.currentTarget}),g().then(e=>{if(!e)return;F(e=>e+1);let t=I.current;if(!t||document.activeElement!==t)return;let n=t.textContent||``,r=_(t),i=n.slice(0,r).replace(/\D/g,``).length,a=y(n);t.textContent!==a.q&&(t.textContent=a.q,queueMicrotask(()=>{R(Math.min(v(a.q,i),a.q.length),t)}))})},K={};b&&(K.placeholder=b),K.inputMode=k??`tel`;let q=String(N??``).replace(/\D/g,``);return w&&s(q)?null:f(t,{type:`input`,label:S,error:C,id:A,element_blok:{className:[E]},element_input:{className:[e.w],props:{"data-disabled":T||!M?`true`:void 0}},children:[O?d(`span`,{className:e.a,children:O}):null,d(x,{divRef:I,editable:M,disabled:T,label:S,placeholder:b,dd:K,onPaste:V,onInput:B,onKeyDown:U,onContextMenu:H,onBlur:W,onFocus:G}),D?d(`span`,{className:e.a,children:D}):null]})}function x({divRef:e,editable:t,disabled:r,label:i,placeholder:a,dd:o,onPaste:s,onInput:c,onKeyDown:l,onContextMenu:u,onBlur:f,onFocus:p}){let m=n();return d(`div`,{ref:e,id:m?.controlId,onPaste:s,onInput:c,onKeyDown:l,onContextMenu:u,onBlur:f,onFocus:p,spellCheck:!1,role:`textbox`,"aria-label":i?void 0:a||`Телефон`,"aria-describedby":m?.describedBy,"aria-invalid":m?.errorId?!0:void 0,"aria-disabled":!t,tabIndex:r?-1:0,"data-disabled":t?void 0:`true`,contentEditable:t?`plaintext-only`:!1,suppressContentEditableWarning:!0,...o})}b.displayName=`PhoneField`;export{b as default};
@@ -10,12 +10,28 @@ type RadioOptionArrayItem = {
10
10
  s?: number;
11
11
  };
12
12
  type RadioOptions = RadioOptionObject | RadioOptionArrayItem[];
13
+ /**
14
+ * Группа радиокнопок.
15
+ *
16
+ * **В форме:** `string | number` (id выбранного пункта).
17
+ *
18
+ * **Элементы:** капсула-`radiogroup` → кнопки `role="radio"`.
19
+ * Опции как у Select: `{ n, s }` / `{ i|id, n }`. `inline` — в ряд. `align` — кружок vs текст.
20
+ *
21
+ * @example
22
+ * <RadioField name="sex" form={form} label="Пол" options={[{ i: "m", n: "М" }, { i: "f", n: "Ж" }]} />
23
+ */
13
24
  export type TRadio = TInput & {
14
25
  options?: RadioOptions;
15
26
  /** Горизонтальный ряд вместо колонки */
16
27
  inline?: boolean;
28
+ /** Кружок: top | center | bottom относительно текста. По умолчанию center */
29
+ align?: "top" | "center" | "bottom";
17
30
  };
18
- declare function RadioField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, options, inline, }: TRadio): import("react/jsx-runtime").JSX.Element | null;
31
+ /**
32
+ * Радиогруппа. Один выбранный id в форме.
33
+ */
34
+ declare function RadioField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, options, inline, align, }: TRadio): import("react/jsx-runtime").JSX.Element | null;
19
35
  declare namespace RadioField {
20
36
  var displayName: string;
21
37
  }
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import r from"../styles/Radio.module.js";import i from"react";import{jsx as a,jsxs as o}from"react/jsx-runtime";function s(e){return e?Array.isArray(e)?e.map(e=>({id:e.id??e.i??``,label:e.n||``,hidden:e.s===0})).filter(e=>e.label.length>0&&e.id!==``):Object.keys(e).map(t=>{let n=e[t],r=Number(t);return{id:Number.isFinite(r)&&String(r)===t?r:t,label:n?.n||``,hidden:n?.s===0}}).filter(e=>e.label.length>0):[]}function c(e,t){return e===t?!0:String(e)===String(t)}function l({value:l=``,form:u,onValue:d,onBlur:f,name:p=``,placeholder:m=``,label:h=``,error:g=``,hidden:_=!1,disabled:v=!1,className:y=``,after:b=``,before:x=``,options:S,inline:C=!1}){let{value:w}=n(u,p,l),T=!v,E=s(S).filter(e=>!e.hidden),D=i.useId(),O=e=>{let t={value:e,name:p};u&&p&&u.setValue(t),d&&d!==u?.onValue&&d(t)};return _&&(w==null||w===``)?null:o(t,{type:`radio`,label:h,error:g,element_blok:{className:[y||``]},element_input:{className:[r.d,C?r.i:``],props:{"data-disabled":v||!T?`true`:void 0,role:`radiogroup`,"aria-label":h||m||`Выбор`}},children:[x?a(`span`,{className:e.a,children:x}):null,a(`div`,{children:E.map(e=>{let t=c(w,e.id);return o(`button`,{type:`button`,className:r.t,role:`radio`,"aria-checked":t,"aria-disabled":v||!T?!0:void 0,disabled:v||!T,name:D,onClick:()=>{T&&O(e.id)},onBlur:()=>{!f||!p||f({value:u?u.getValue(p,w):w,name:p})},children:[a(`span`,{className:r.o,"aria-hidden":!0,children:t?a(`span`,{className:r.f}):null}),a(`span`,{className:r.x,children:e.label})]},String(e.id))})}),b?a(`span`,{className:e.a,children:b}):null]})}l.displayName=`RadioField`;export{l as default};
1
+ import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import{createFieldEmit as r}from"./emit.js";import i from"../styles/Radio.module.js";import a from"react";import{jsx as o,jsxs as s}from"react/jsx-runtime";function c(e){return e?Array.isArray(e)?e.map(e=>({id:e.id??e.i??``,label:e.n||``,hidden:e.s===0})).filter(e=>e.label.length>0&&e.id!==``):Object.keys(e).map(t=>{let n=e[t],r=Number(t);return{id:Number.isFinite(r)&&String(r)===t?r:t,label:n?.n||``,hidden:n?.s===0}}).filter(e=>e.label.length>0):[]}function l(e,t){return e===t?!0:String(e)===String(t)}function u({value:u=``,form:d,onValue:f,onBlur:p,name:m=``,placeholder:h=``,label:g=``,error:_=``,hidden:v=!1,disabled:y=!1,className:b=``,after:x=``,before:S=``,options:C,inline:w=!1,align:T=`center`}){let{value:E}=n(d,m,u),D=!y,O=c(C).filter(e=>!e.hidden),k=a.useId(),A=e=>{r(d,m,f)(e,!0)};return v&&(E==null||E===``)?null:s(t,{type:`radio`,label:g,error:_,element_blok:{className:[b||``]},element_input:{className:[i.d,w?i.i:``],props:{"data-disabled":y||!D?`true`:void 0,role:`radiogroup`,"aria-label":g||h||`Выбор`}},children:[S?o(`span`,{className:e.a,children:S}):null,o(`div`,{children:O.map(e=>{let t=l(E,e.id);return s(`button`,{type:`button`,className:i.t,role:`radio`,"aria-checked":t,"aria-disabled":y||!D?!0:void 0,disabled:y||!D,"data-align":T,name:k,onClick:()=>{D&&A(e.id)},onBlur:()=>{!p||!m||p({value:d?d.getValue(m,E):E,name:m})},children:[o(`span`,{className:i.o,"aria-hidden":!0,children:t?o(`span`,{className:i.f}):null}),o(`span`,{className:i.x,children:e.label})]},String(e.id))})}),x?o(`span`,{className:e.a,children:x}):null]})}u.displayName=`RadioField`;export{u as default};
@@ -1,16 +1,29 @@
1
1
  import { TInput } from './type';
2
- /** Поле «диапазон»: кастомный трек (div), визуально как «таблетка» с заливкой, без нативного range */
2
+ /** `bar` толстая «таблетка» с заливкой; `line` тонкая линия и круглый thumb */
3
+ export type TRangeVariant = "bar" | "line";
4
+ /**
5
+ * Слайдер. **В форме:** `number`.
6
+ *
7
+ * **Элементы:** капсула как у Input → трек (`bar` таблетка / `line` + thumb). Не нативный `<input type="range">`.
8
+ *
9
+ * @example
10
+ * <RangeField name="vol" form={form} label="Громкость" min={0} max={100} variant="bar" />
11
+ */
3
12
  export type TRange = TInput & {
4
13
  min?: number;
5
14
  max?: number;
6
15
  step?: number;
16
+ /**
17
+ * `bar` — iOS-прогресс (заливка слева),
18
+ * `line` — тонкий трек и кружок (как системный range).
19
+ */
20
+ variant?: TRangeVariant;
7
21
  };
8
- /** @deprecated — используйте `TRange` */
9
- export type TProgress = TRange;
10
- declare function RangeField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, min, max, step, }: TRange): import("react/jsx-runtime").JSX.Element | null;
22
+ /**
23
+ * Диапазон. Клавиши стрелок при фокусе на треке.
24
+ */
25
+ declare function RangeField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, min, max, step, variant, }: TRange): import("react/jsx-runtime").JSX.Element | null;
11
26
  declare namespace RangeField {
12
27
  var displayName: string;
13
28
  }
14
29
  export default RangeField;
15
- /** Псевдоним для обратной совместимости */
16
- export { RangeField as ProgressField };
@@ -1 +1 @@
1
- import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import r from"react";import{jsx as i,jsxs as a}from"react/jsx-runtime";function o(e,t,n){let r=e;return Number.isFinite(r)||(r=t),Math.min(n,Math.max(t,r))}function s(e,t,n,r){return o(!Number.isFinite(r)||r<=0?e:t+Math.round((e-t)/r)*r,t,n)}function c({value:c=0,form:l,onValue:u,onBlur:d,name:f=``,placeholder:p=``,label:m=``,error:h=``,hidden:g=!1,disabled:_=!1,className:v=``,after:y=``,before:b=``,min:x=0,max:S=100,step:C=1}){let{value:w}=n(l,f,c),T=o(Number(w),x,S),E=S===x?0:(T-x)/(S-x)*100,D=E>=99.999,O=!_,k=r.useRef(null),A=r.useCallback(e=>{let t={value:s(e,x,S,C),name:f||``};l&&f&&l.setValue(t),u&&u!==l?.onValue&&u(t)},[l,f,u,x,S,C]),j=r.useCallback(e=>{let t=k.current;if(!t)return x;let n=t.getBoundingClientRect(),r=n.width||1;return s(x+(e-n.left)/r*(S-x),x,S,C)},[x,S,C]),M=e=>{O&&(e.preventDefault(),e.currentTarget.setPointerCapture(e.pointerId),A(j(e.clientX)))},N=e=>{O&&e.currentTarget.hasPointerCapture(e.pointerId)&&A(j(e.clientX))},P=e=>{try{e.currentTarget.releasePointerCapture(e.pointerId)}catch{}},F=e=>{if(!O)return;let t=T;if(e.key===`ArrowRight`||e.key===`ArrowUp`)t=T+C;else if(e.key===`ArrowLeft`||e.key===`ArrowDown`)t=T-C;else if(e.key===`Home`)t=x;else if(e.key===`End`)t=S;else if(e.key===`PageUp`)t=T+C*10;else if(e.key===`PageDown`)t=T-C*10;else return;e.preventDefault(),A(s(t,x,S,C))},I=()=>{if(!d||!f)return;let e=l&&f?l.getValue(f,c):T;d({value:o(Number(e),x,S),name:f})};return g&&(w==null||w===``)?null:a(t,{type:`range`,label:m,error:h,element_blok:{className:[v||``]},element_input:{className:[e.w,e.r],props:{"data-disabled":_||!O?`true`:void 0}},children:[b?i(`span`,{className:e.a,children:b}):null,i(`div`,{children:i(`div`,{ref:k,className:e.k,role:`slider`,tabIndex:O?0:-1,"aria-label":m||p||`Диапазон`,"aria-valuemin":x,"aria-valuemax":S,"aria-valuenow":T,"data-disabled":_||!O?`true`:void 0,onPointerDown:M,onPointerMove:N,onPointerUp:P,onPointerCancel:P,onKeyDown:F,onBlur:I,children:i(`div`,{className:D?`${e.u} ${e.v}`:e.u,style:{width:`${E}%`},"aria-hidden":!0})})}),y?i(`span`,{className:e.a,children:y}):null]})}c.displayName=`RangeField`;export{c as default};
1
+ import e from"../styles/Field.module.js";import t from"../core/Field.js";import{useFormFieldState as n}from"../hooks/use.js";import{createFieldEmit as r}from"./emit.js";import i from"react";import{jsx as a,jsxs as o}from"react/jsx-runtime";function s(e,t,n){let r=e;return Number.isFinite(r)||(r=t),Math.min(n,Math.max(t,r))}function c(e,t,n,r){return s(!Number.isFinite(r)||r<=0?e:t+Math.round((e-t)/r)*r,t,n)}function l({value:l=0,form:u,onValue:d,onBlur:f,name:p=``,placeholder:m=``,label:h=``,error:g=``,hidden:_=!1,disabled:v=!1,className:y=``,after:b=``,before:x=``,min:S=0,max:C=100,step:w=1,variant:T=`bar`}){let{value:E}=n(u,p,l),D=s(Number(E),S,C),O=C===S?0:(D-S)/(C-S)*100,k=O>=99.999,A=!v,j=i.useRef(null),M=i.useCallback(e=>{let t=c(e,S,C,w);r(u,p,d)(t,!0)},[u,p,d,S,C,w]),N=i.useCallback(e=>{let t=j.current;if(!t)return S;let n=t.getBoundingClientRect(),r=n.width||1;return c(S+(e-n.left)/r*(C-S),S,C,w)},[S,C,w]),P=e=>{A&&(e.preventDefault(),e.currentTarget.setPointerCapture(e.pointerId),M(N(e.clientX)))},F=e=>{A&&e.currentTarget.hasPointerCapture(e.pointerId)&&M(N(e.clientX))},I=e=>{try{e.currentTarget.releasePointerCapture(e.pointerId)}catch{}},L=e=>{if(!A)return;let t=D;if(e.key===`ArrowRight`||e.key===`ArrowUp`)t=D+w;else if(e.key===`ArrowLeft`||e.key===`ArrowDown`)t=D-w;else if(e.key===`Home`)t=S;else if(e.key===`End`)t=C;else if(e.key===`PageUp`)t=D+w*10;else if(e.key===`PageDown`)t=D-w*10;else return;e.preventDefault(),M(c(t,S,C,w))},R=()=>{if(!f||!p)return;let e=u&&p?u.getValue(p,l):D;f({value:s(Number(e),S,C),name:p})};return _&&(E==null||E===``)?null:o(t,{type:`range`,label:h,error:g,element_blok:{className:[y||``]},element_input:{className:[e.w,e.r],props:{"data-disabled":v||!A?`true`:void 0,"data-variant":T}},children:[x?a(`span`,{className:e.a,children:x}):null,a(`div`,{children:o(`div`,{ref:j,className:e.k,role:`slider`,tabIndex:A?0:-1,"aria-label":h||m||`Диапазон`,"aria-valuemin":S,"aria-valuemax":C,"aria-valuenow":D,"data-disabled":v||!A?`true`:void 0,onPointerDown:P,onPointerMove:F,onPointerUp:I,onPointerCancel:I,onKeyDown:L,onBlur:R,children:[a(`div`,{className:k?`${e.u} ${e.v}`:e.u,style:{width:`${O}%`},"aria-hidden":!0}),T===`line`?a(`div`,{className:e.h,style:{left:`${O}%`},"aria-hidden":!0}):null]})}),b?a(`span`,{className:e.a,children:b}):null]})}l.displayName=`RangeField`;export{l as default};