@modul/mbui 0.0.1-beta-pv-50560-3e5e7e6f → 0.0.1-beta-pv-50520-a5f245c9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modul/mbui",
3
- "version": "0.0.1-beta-pv-50560-3e5e7e6f",
3
+ "version": "0.0.1-beta-pv-50520-a5f245c9",
4
4
  "packageManager": "yarn@3.5.1",
5
5
  "main": "src/index.ts",
6
6
  "scripts": {
@@ -13,8 +13,6 @@
13
13
  "src"
14
14
  ],
15
15
  "dependencies": {
16
- "accounting": "0.4.1",
17
- "modul-helpers": "0.1.108",
18
16
  "react-datepicker": "4.16.0",
19
17
  "react-imask": "7.1.3"
20
18
  },
@@ -0,0 +1,66 @@
1
+ import React, { FC, InputHTMLAttributes, ReactNode } from 'react'
2
+ import classnames from 'classnames'
3
+ interface ICheckbox extends InputHTMLAttributes<HTMLInputElement> {
4
+ switcher?: boolean
5
+ children?: ReactNode
6
+ childrenWrapperClassName?: string
7
+ labelClassName?: string
8
+ iconId?: string
9
+ onClick?: () => void
10
+ disabled?: boolean
11
+ }
12
+
13
+ const Checkbox: FC<ICheckbox> = ({
14
+ id,
15
+ name,
16
+ checked,
17
+ onChange,
18
+ onClick,
19
+ value = 'on',
20
+ switcher,
21
+ onBlur,
22
+ onFocus,
23
+ iconId,
24
+ children,
25
+ childrenWrapperClassName,
26
+ labelClassName,
27
+ disabled,
28
+ }) => {
29
+ const labelClasses = classnames('label-check', labelClassName, { _switcher: switcher })
30
+
31
+ const renderIcon = iconId && (
32
+ <i
33
+ className="icon"
34
+ id={iconId}
35
+ />
36
+ )
37
+
38
+ const renderChildren = children && <span className={childrenWrapperClassName}>{children}</span>
39
+
40
+ return (
41
+ <span onClick={onClick}>
42
+ <input
43
+ type="checkbox"
44
+ checked={checked}
45
+ name={name}
46
+ id={id}
47
+ onChange={onChange}
48
+ value={value}
49
+ onBlur={onBlur}
50
+ onFocus={onFocus}
51
+ disabled={disabled}
52
+ />
53
+
54
+ <label
55
+ htmlFor={id}
56
+ className={labelClasses}
57
+ data-checked={checked}
58
+ >
59
+ {renderIcon}
60
+ {renderChildren}
61
+ </label>
62
+ </span>
63
+ )
64
+ }
65
+
66
+ export default Checkbox
@@ -0,0 +1,3 @@
1
+ import Checkbox from './Checkbox'
2
+
3
+ export { Checkbox }
package/src/index.ts CHANGED
@@ -2,7 +2,6 @@ import { Button } from './Base/Buttons'
2
2
  import { TextLink } from './Base/Links'
3
3
  import { DatePicker } from './DatePicker'
4
4
  import { Input } from './Base/Input'
5
- import { AmountFormat } from './Base/AmountFormat'
6
- import { AmountInput } from './Base/AmountInput'
5
+ import { Checkbox } from './Base/Checkbox'
7
6
 
8
- export { Button, TextLink, DatePicker, Input, AmountFormat, AmountInput }
7
+ export { Button, TextLink, DatePicker, Input, Checkbox }
@@ -1,46 +0,0 @@
1
- import React from 'react'
2
- import { validateHelper } from 'modul-helpers'
3
- import accounting from 'accounting'
4
- import { CurrencySymbol } from '../CurrencySymbol'
5
-
6
- interface AmountFormatProps {
7
- value: string | number
8
- currency?: string
9
- precision?: number
10
- def?: string
11
- className?: string
12
- whiteSpace?: string
13
- }
14
-
15
- //FIXME: def
16
- const AmountFormat: React.FC<AmountFormatProps> = ({
17
- value,
18
- currency = 'RUR',
19
- precision = 2,
20
- def = '',
21
- className = '',
22
- whiteSpace = '&nbsp;',
23
- }) => {
24
- const clearValue = (value: string) => (value.replace ? value.replace(/[^0-9.,]+/g, '').replace(',', '.') : value)
25
-
26
- const formattedValue = React.useMemo(() => {
27
- const numericValue = parseFloat(clearValue(String(value)))
28
- return !isNaN(numericValue) ? accounting.formatNumber(numericValue, precision, whiteSpace) : def
29
- }, [value, precision, whiteSpace, def])
30
-
31
- //FIXME: возможно просто вернуть null
32
- if (validateHelper.isEmpty(value)) {
33
- return null
34
- // return <span className={className}>{def}</span>
35
- }
36
-
37
- //FIXME: dangerouslySetInnerHTML ???
38
- return (
39
- <span className={className}>
40
- {formattedValue}&nbsp;
41
- {currency && <CurrencySymbol value={currency} />}
42
- </span>
43
- )
44
- }
45
-
46
- export default AmountFormat
@@ -1,3 +0,0 @@
1
- import AmountFormat from './AmountFormat'
2
-
3
- export { AmountFormat }
@@ -1,127 +0,0 @@
1
- import React, { useState, useEffect, forwardRef, ForwardedRef, ChangeEvent, KeyboardEvent, useCallback } from 'react'
2
- import accounting from 'accounting'
3
- import { numberHelper } from 'modul-helpers'
4
- import { calculateStart, cleanValue, parseFloatOrNull } from './utils'
5
- import { useForwardedRef } from './hooks'
6
- import { CombinedChangeEventHandler } from './types'
7
-
8
- const { trimValidLength } = numberHelper
9
-
10
- accounting.settings = {
11
- number: {
12
- decimal: ',',
13
- },
14
- }
15
-
16
- interface IAmountInput extends React.InputHTMLAttributes<HTMLInputElement> {
17
- value?: string | number
18
- precision?: number
19
- onChange?: CombinedChangeEventHandler
20
- }
21
-
22
- const AmountInput = forwardRef<HTMLInputElement, IAmountInput>(
23
- (
24
- { onChange, precision = 2, value, type = 'text', ...props }: IAmountInput,
25
- ref: ForwardedRef<HTMLInputElement>
26
- ) => {
27
- const innerRef = useForwardedRef(ref)
28
- //Состояния для отслеживания текущего значения и позиции курсора
29
- const [viewValue, setViewValue] = useState<string>('')
30
- const [startPos, setStartPos] = useState<number | null>(null)
31
-
32
- //Функция для обработки и форматирования входного значения
33
- const parseValue = useCallback(
34
- (val: string | number | undefined): { viewValue: string; startPos: number | null } => {
35
- const el = innerRef.current
36
- const cleanedValue = cleanValue(val === undefined || val === null ? '' : val.toString(), false)
37
- const clean = trimValidLength(cleanedValue, '.', precision)
38
- const parsedValue = parseFloatOrNull(clean)
39
- const formattedValue = parsedValue ? accounting.formatNumber(parsedValue, precision, ' ') : ''
40
-
41
- // Инициализация стартовой позиции для курсора
42
- let parsedStartPos = el?.selectionStart || null
43
-
44
- // Вычисление новой позиции курсора при изменении значения
45
- if (parsedValue && el && formattedValue.length !== clean.length) {
46
- parsedStartPos = calculateStart(el.selectionStart, clean, formattedValue)
47
- }
48
-
49
- // Формирование отформатированного значения для отображения
50
- let parsedViewValue = formattedValue
51
-
52
- // Обработка случая, когда значение равно нулю или пусто
53
- if (!parsedValue) {
54
- if (!/^0[,.]?0*/.test(clean)) {
55
- parsedViewValue = ''
56
- } else {
57
- parsedViewValue = clean.replace('.', ',')
58
- if (parsedViewValue === '0' || parsedViewValue === '0,' || parsedViewValue === '0,0') {
59
- parsedViewValue = `0,${[...Array(precision)].map(() => '0').join('')}`
60
- parsedStartPos = calculateStart(el.selectionStart, clean, parsedViewValue)
61
- }
62
- }
63
- }
64
-
65
- // Возвращение отформатированного значения и позиции курсора
66
- return { viewValue: parsedViewValue, startPos: parsedStartPos }
67
- },
68
- [innerRef, precision]
69
- )
70
-
71
- //для обновления значений при изменении входного значения
72
- useEffect(() => {
73
- const { viewValue: parsedViewValue, startPos: parsedStartPos } = parseValue(value)
74
- setViewValue(parsedViewValue)
75
- setStartPos(parsedStartPos)
76
- }, [value, parseValue])
77
-
78
- // для установки позиции курсора при изменении startPos
79
- useEffect(() => {
80
- if (startPos !== null && innerRef.current) {
81
- innerRef.current.setSelectionRange(startPos, startPos)
82
- }
83
- }, [startPos, innerRef])
84
-
85
- const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
86
- const el = innerRef.current
87
- const isDeletingKey = e.key === 'Backspace'
88
- const inputValue = el?.value || ''
89
- const prevCharValue = inputValue[el.selectionStart - 1]
90
-
91
- // Проверка на удаление пробела или десятичного разделителя
92
- const isDeletingWhiteSpace = isDeletingKey && el.selectionStart >= 2 && /\s/g.test(prevCharValue)
93
- const isDeletingDecimalSeparator = isDeletingKey && prevCharValue === ','
94
-
95
- // Вычисление новой позиции курсора после удаления
96
- const newStartPos = isDeletingDecimalSeparator || isDeletingWhiteSpace ? el.selectionStart - 1 : null
97
-
98
- // Установка новой позиции курсора и вызов onChange
99
- if (newStartPos !== startPos) {
100
- setStartPos(newStartPos)
101
- }
102
-
103
- onChange?.(viewValue, e)
104
- }
105
-
106
- const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
107
- const inputValue = e.target.value
108
- const { viewValue: parsedViewValue, startPos: parsedStartPos } = parseValue(inputValue)
109
- setViewValue(parsedViewValue)
110
- setStartPos(parsedStartPos)
111
- onChange?.(parsedViewValue, e)
112
- }
113
-
114
- return (
115
- <input
116
- type={type}
117
- ref={innerRef}
118
- value={viewValue}
119
- onKeyDown={handleKeyDown}
120
- onChange={handleChange}
121
- {...props}
122
- />
123
- )
124
- }
125
- )
126
-
127
- export default AmountInput
@@ -1,16 +0,0 @@
1
- import React, { useEffect } from 'react'
2
-
3
- export function useForwardedRef<T>(ref: React.ForwardedRef<T>) {
4
- const innerRef = React.useRef<T>(null)
5
-
6
- useEffect(() => {
7
- if (!ref) return
8
- if (typeof ref === 'function') {
9
- ref(innerRef.current)
10
- } else {
11
- ref.current = innerRef.current
12
- }
13
- }, [ref])
14
-
15
- return innerRef
16
- }
@@ -1,3 +0,0 @@
1
- import AmountInput from './AmountInput'
2
-
3
- export { AmountInput }
@@ -1,8 +0,0 @@
1
- import { ChangeEvent, KeyboardEvent, ChangeEventHandler } from 'react'
2
-
3
- type CustomChangeEventHandler = (
4
- value: string,
5
- e?: ChangeEvent<HTMLInputElement> | KeyboardEvent<HTMLInputElement>
6
- ) => void
7
-
8
- export type CombinedChangeEventHandler = ChangeEventHandler<HTMLInputElement> & CustomChangeEventHandler
@@ -1,26 +0,0 @@
1
- export function cleanValue(val, ignoreSpace = true) {
2
- let res = ignoreSpace ? val.replace(/[^0-9.,]+/g, '') : val.replace(/[^0-9., ]+/g, '')
3
- res = res.replace(/,/g, '.').replace('-', '')
4
- const dotPos = res.indexOf('.')
5
- if (dotPos > -1) {
6
- const output = res.split('.')
7
- res = output.shift() + '.' + output.join('')
8
- }
9
- return res
10
- }
11
-
12
- export function calculateStart(start, originValue, formattedValue) {
13
- const substr = originValue.substring(0, start).replace(/ /g, '')
14
- let regex = '^'
15
-
16
- for (let i = 0, len = substr.length; i < len; i++) {
17
- regex += substr[i] + ' {0,1}'
18
- }
19
- const match = new RegExp(regex).exec(formattedValue)
20
- return (match && match[0].length) || 0
21
- }
22
-
23
- export function parseFloatOrNull(val) {
24
- const result = parseFloat(cleanValue(val))
25
- return isNaN(result) ? null : result
26
- }
@@ -1,15 +0,0 @@
1
- import React from 'react'
2
- import { currencySymbols } from './enums'
3
-
4
- interface CurrencySymbolProps {
5
- value: string
6
- }
7
-
8
- const CurrencySymbol: React.FC<CurrencySymbolProps> = ({ value }) => {
9
- const symbol = currencySymbols[value] || value
10
- const currencyClass = currencySymbols[value] ? 'currency-iso' : ''
11
-
12
- return <span className={currencyClass}>{symbol}</span>
13
- }
14
-
15
- export default CurrencySymbol
@@ -1,7 +0,0 @@
1
- export enum currencySymbols {
2
- USD = '$',
3
- EUR = '€',
4
- CNY = '¥',
5
- RUB = '₽',
6
- RUR = '₽',
7
- }
@@ -1,3 +0,0 @@
1
- import CurrencySymbol from './CurrencySymbol'
2
-
3
- export { CurrencySymbol }