@startlibs/form 1.0.11 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/AutoComplete.mjs +550 -0
- package/lib/AutoComplete.mjs.map +1 -0
- package/lib/Checkbox.mjs +76 -0
- package/lib/Checkbox.mjs.map +1 -0
- package/lib/Combobox.mjs +544 -0
- package/lib/Combobox.mjs.map +1 -0
- package/lib/ComboboxWithCustom.mjs +77 -0
- package/lib/ComboboxWithCustom.mjs.map +1 -0
- package/lib/DatePicker.mjs +625 -0
- package/lib/DatePicker.mjs.map +1 -0
- package/lib/EditableBox.mjs +496 -0
- package/lib/EditableBox.mjs.map +1 -0
- package/lib/Errors.mjs +176 -0
- package/lib/Errors.mjs.map +1 -0
- package/lib/ExpandableBox.mjs +209 -0
- package/lib/ExpandableBox.mjs.map +1 -0
- package/lib/Field.mjs +65 -0
- package/lib/Field.mjs.map +1 -0
- package/lib/FieldBox.mjs +80 -0
- package/lib/FieldBox.mjs.map +1 -0
- package/lib/Form.mjs +322 -0
- package/lib/Form.mjs.map +1 -0
- package/lib/FormValue.mjs +111 -0
- package/lib/FormValue.mjs.map +1 -0
- package/lib/InputboxGroup.mjs +104 -0
- package/lib/InputboxGroup.mjs.map +1 -0
- package/lib/Radiobox.mjs +67 -0
- package/lib/Radiobox.mjs.map +1 -0
- package/lib/RichText.mjs +634 -0
- package/lib/RichText.mjs.map +1 -0
- package/lib/TextInput.mjs +359 -0
- package/lib/TextInput.mjs.map +1 -0
- package/lib/alt/checkbox/SimpleCheckbox.mjs +82 -0
- package/lib/alt/checkbox/SimpleCheckbox.mjs.map +1 -0
- package/lib/alt/checkbox/ToggleCheckbox.mjs +68 -0
- package/lib/alt/checkbox/ToggleCheckbox.mjs.map +1 -0
- package/lib/alt/radiobox/CleanTabRadiobox.mjs +44 -0
- package/lib/alt/radiobox/CleanTabRadiobox.mjs.map +1 -0
- package/lib/alt/radiobox/IconRadioBox.mjs +52 -0
- package/lib/alt/radiobox/IconRadioBox.mjs.map +1 -0
- package/lib/alt/radiobox/SimpleRadiobox.mjs +61 -0
- package/lib/alt/radiobox/SimpleRadiobox.mjs.map +1 -0
- package/lib/alt/radiobox/TabRadiobox.mjs +54 -0
- package/lib/alt/radiobox/TabRadiobox.mjs.map +1 -0
- package/lib/enhanceInput.mjs +131 -0
- package/lib/enhanceInput.mjs.map +1 -0
- package/lib/index.cjs +5345 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.mjs +28 -0
- package/lib/index.mjs.map +1 -0
- package/lib/useConfirmDialog.mjs +117 -0
- package/lib/useConfirmDialog.mjs.map +1 -0
- package/lib/useDraftConfirmation.mjs +56 -0
- package/lib/useDraftConfirmation.mjs.map +1 -0
- package/lib/validation.mjs +91 -0
- package/lib/validation.mjs.map +1 -0
- package/lib/withFormImageInput.mjs +281 -0
- package/lib/withFormImageInput.mjs.map +1 -0
- package/package.json +44 -25
- package/src/AutoComplete.jsx +642 -0
- package/src/Checkbox.jsx +45 -0
- package/src/Combobox.jsx +606 -0
- package/src/ComboboxWithCustom.jsx +68 -0
- package/src/DatePicker.jsx +733 -0
- package/src/EditableBox.jsx +502 -0
- package/src/Errors.jsx +174 -0
- package/src/ExpandableBox.jsx +207 -0
- package/src/Field.jsx +76 -0
- package/src/FieldBox.jsx +136 -0
- package/src/Form.jsx +291 -0
- package/src/FormValue.jsx +67 -0
- package/src/IconRadioBoxOldHubt.jsx +93 -0
- package/src/InputboxGroup.jsx +121 -0
- package/src/Radiobox.jsx +33 -0
- package/src/RichText.jsx +812 -0
- package/src/TextInput.jsx +519 -0
- package/src/alt/checkbox/SimpleCheckbox.jsx +162 -0
- package/src/alt/checkbox/ToggleCheckbox.jsx +143 -0
- package/src/alt/radiobox/CleanTabRadiobox.jsx +46 -0
- package/src/alt/radiobox/IconRadioBox.jsx +93 -0
- package/src/alt/radiobox/SimpleRadiobox.jsx +153 -0
- package/src/alt/radiobox/TabRadiobox.jsx +73 -0
- package/src/enhanceInput.jsx +107 -0
- package/src/index.js +27 -0
- package/src/useConfirmDialog.jsx +105 -0
- package/src/useDraftConfirmation.jsx +60 -0
- package/src/validation.js +92 -0
- package/src/withFormImageInput.jsx +297 -0
- package/.babelrc +0 -28
- package/lib/index.js +0 -6255
- package/rollup.config.js +0 -43
- package/yarn-error.log +0 -1607
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, {useContext, useEffect, useState, useMemo} from 'react'
|
|
2
|
+
import {useUpdateEffect} from '@startlibs/core'
|
|
3
|
+
import {ifUndefined, callIfFunction, getUID} from '@startlibs/utils'
|
|
4
|
+
import {FormContext, useFormMeta, useFormValue} from './Form'
|
|
5
|
+
import _ from 'lodash/fp'
|
|
6
|
+
import {TransitionDiv,SwitchDiv} from '@startlibs/components'
|
|
7
|
+
|
|
8
|
+
export const FormValue = ({path,children,inputs,format=_.identity}) => {
|
|
9
|
+
const [value,setValue] = useFormValue(path,inputs || [])
|
|
10
|
+
return ifUndefined(callIfFunction(children,format(value),setValue),_.isObject(value) ? null : value,null)
|
|
11
|
+
}
|
|
12
|
+
export const IfFormValue = ({path,children,inputs,check = _.identity,invert,...rest}) => {
|
|
13
|
+
const [value,setValue] = useFormValue(path,inputs || [])
|
|
14
|
+
const doInvert = (v) => invert ? !v : !!v
|
|
15
|
+
return <TransitionDiv {...rest}>{
|
|
16
|
+
doInvert(callIfFunction(check,value))
|
|
17
|
+
? ifUndefined(callIfFunction(children,value,setValue),_.isObject(value) ? null : value,null)
|
|
18
|
+
: null
|
|
19
|
+
}</TransitionDiv>
|
|
20
|
+
}
|
|
21
|
+
export const IfFormValueUpdate = ({path,children,updatePath}) => {
|
|
22
|
+
const [readValue] = useFormValue(path,[])
|
|
23
|
+
const [,setValue] = useFormValue(updatePath,[])
|
|
24
|
+
useUpdateEffect(() => {
|
|
25
|
+
setValue(callIfFunction(children,readValue))
|
|
26
|
+
},[readValue])
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
export const SwitchOnFormValue = ({path,children,inputs,on,off,check,invert,map = _.identity,...rest}) => {
|
|
30
|
+
const [value,setValue] = useFormValue(path,inputs || [])
|
|
31
|
+
const doInvert = (v) => invert ? !v : v
|
|
32
|
+
const isOn = (check || invert ) ? doInvert(callIfFunction(check,value)) : value
|
|
33
|
+
const mappedValue = map(value)
|
|
34
|
+
const onKey = useMemo(() => getUID() , [isOn,mappedValue])
|
|
35
|
+
return <SwitchDiv on={onKey} {...rest}>{
|
|
36
|
+
isOn
|
|
37
|
+
? (on && on[mappedValue])
|
|
38
|
+
? callIfFunction(on[mappedValue],value,setValue)
|
|
39
|
+
: ifUndefined(callIfFunction(on,value,setValue),_.isObject(value) ? null : value,null)
|
|
40
|
+
: ifUndefined(callIfFunction(off,value,setValue),_.isObject(value) ? null : value,null)
|
|
41
|
+
}</SwitchDiv>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const FormMeta = ({path,children,inputs}) => {
|
|
45
|
+
const [value,setValue] = useFormMeta(path,inputs || [])
|
|
46
|
+
return ifUndefined(callIfFunction(children,value,setValue),value,null)
|
|
47
|
+
}
|
|
48
|
+
export const IfFormMeta = ({path,children,inputs,check = _.identity,invert,...rest}) => {
|
|
49
|
+
const [value,setValue] = useFormMeta(path,inputs || [])
|
|
50
|
+
const doInvert = (v) => invert ? !v : !!v
|
|
51
|
+
return <TransitionDiv {...rest}>{
|
|
52
|
+
doInvert(callIfFunction(check,value))
|
|
53
|
+
? ifUndefined(callIfFunction(children,value,setValue),_.isObject(value) ? null : value,null)
|
|
54
|
+
: null
|
|
55
|
+
}</TransitionDiv>
|
|
56
|
+
}
|
|
57
|
+
export const LazyFormValues = ({value,format = _.identity, children}) => {
|
|
58
|
+
const currentValue = value.read()
|
|
59
|
+
const [loaded,setLoaded] = useState(false)
|
|
60
|
+
const formUtils = useContext(FormContext)
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
formUtils.setValues(format(currentValue), false)
|
|
63
|
+
setLoaded(getUID)
|
|
64
|
+
return () => value.refresh()
|
|
65
|
+
}, [])
|
|
66
|
+
return callIfFunction(children,loaded)
|
|
67
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import styled, {css} from 'styled-components'
|
|
3
|
+
import {Icon} from '@startlibs/components'
|
|
4
|
+
import {enhanceInput} from './enhanceInput'
|
|
5
|
+
import {customTheme,getColor} from '@startlibs/utils'
|
|
6
|
+
|
|
7
|
+
const Text = styled.div`
|
|
8
|
+
flex-grow: 1;
|
|
9
|
+
padding: 0.5rem;
|
|
10
|
+
min-height: 3rem;
|
|
11
|
+
align-content: center;
|
|
12
|
+
|
|
13
|
+
display: flex;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
align-items: center;
|
|
16
|
+
|
|
17
|
+
-ms-flex-positive: 1;
|
|
18
|
+
display: -ms-flexbox;
|
|
19
|
+
-ms-flex-line-pack: center;
|
|
20
|
+
-ms-flex-align: center;
|
|
21
|
+
-ms-flex-pack: center;
|
|
22
|
+
-ms-flex-direction: column;
|
|
23
|
+
|
|
24
|
+
background-color: transparent;
|
|
25
|
+
border-top: 1px solid ${getColor('gray150')};
|
|
26
|
+
text-align: center;
|
|
27
|
+
`
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
export const StyledIconRadioBox = styled(({className, setFromField, name, tabIndex, icon, value, label, fieldValue}) =>
|
|
31
|
+
<label className={className}>
|
|
32
|
+
<input type="radio" value={fieldValue} name={name} tabIndex={tabIndex}
|
|
33
|
+
onChange={setFromField} checked={value === fieldValue}/>
|
|
34
|
+
<Icon icon={icon}/>
|
|
35
|
+
<Text>
|
|
36
|
+
{label}
|
|
37
|
+
</Text>
|
|
38
|
+
</label>
|
|
39
|
+
)`
|
|
40
|
+
width: 100%;
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
border: 1px solid ${getColor('gray150')};
|
|
44
|
+
color: ${getColor('gray150')};
|
|
45
|
+
border-radius: 5px;
|
|
46
|
+
background-color: #fff;
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
|
|
49
|
+
${props => props.value === props.fieldValue ? css`
|
|
50
|
+
border-color: ${getColor('main')};
|
|
51
|
+
color: ${getColor('main')};
|
|
52
|
+
${Text} {
|
|
53
|
+
background-color: ${getColor('main')};
|
|
54
|
+
border-top-color: ${getColor('main')};
|
|
55
|
+
color:#fff;
|
|
56
|
+
}
|
|
57
|
+
` : css`
|
|
58
|
+
:hover ${Text} {
|
|
59
|
+
background-color: ${getColor('gray150')};
|
|
60
|
+
color: #fff;
|
|
61
|
+
}
|
|
62
|
+
`}
|
|
63
|
+
|
|
64
|
+
${Icon} {
|
|
65
|
+
font-size: 100px;
|
|
66
|
+
line-height: 72px;
|
|
67
|
+
margin: 0.5rem auto;
|
|
68
|
+
text-align: center;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
input {
|
|
72
|
+
opacity: 0;
|
|
73
|
+
position: absolute;
|
|
74
|
+
left: -20000000px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
input:focus ~ ${Icon}::after {
|
|
78
|
+
content: '';
|
|
79
|
+
position: absolute;
|
|
80
|
+
top: -4px;
|
|
81
|
+
right: -4px;
|
|
82
|
+
left: -4px;
|
|
83
|
+
bottom: -4px;
|
|
84
|
+
border-radius: 7px;
|
|
85
|
+
border: 2px solid rgba(0, 0, 0, 0.2);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
${customTheme("IconRadioBox")}
|
|
89
|
+
`
|
|
90
|
+
|
|
91
|
+
export const IconRadioBox = enhanceInput(StyledIconRadioBox)
|
|
92
|
+
|
|
93
|
+
IconRadioBox.Text = Text
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import {callIfFunction} from '@startlibs/utils'
|
|
4
|
+
import styled, {css} from 'styled-components'
|
|
5
|
+
|
|
6
|
+
import {Field} from './Field'
|
|
7
|
+
import {SimpleCheckbox} from './alt/checkbox/SimpleCheckbox'
|
|
8
|
+
import {SimpleRadiobox} from './alt/radiobox/SimpleRadiobox'
|
|
9
|
+
import {SplitColumnsContainer} from '@startlibs/components'
|
|
10
|
+
import _ from "lodash/fp";
|
|
11
|
+
|
|
12
|
+
export const InputboxGroup = styled(({path, className, column, as = column ? SplitColumnsContainer : 'div', children, label, descText,helpText,mandatory,margin, ...rest}) => {
|
|
13
|
+
const size = React.Children.count(children)
|
|
14
|
+
const Wrapper = as
|
|
15
|
+
const boxes = <Wrapper className={className}>{
|
|
16
|
+
React.Children.toArray(children).filter(child => child.props).map((child, i,arr) => React.cloneElement(child, {
|
|
17
|
+
isFirst: i === 0,
|
|
18
|
+
isLast: i === arr.length - 1,
|
|
19
|
+
index: i,
|
|
20
|
+
path,
|
|
21
|
+
...rest,
|
|
22
|
+
...child.props,
|
|
23
|
+
}))
|
|
24
|
+
}</Wrapper>
|
|
25
|
+
|
|
26
|
+
return label
|
|
27
|
+
? <Field label={label} mandatory={mandatory} descText={descText} helpText={helpText} margin={margin}>{boxes}</Field>
|
|
28
|
+
: boxes
|
|
29
|
+
})`
|
|
30
|
+
${props => props.wide && `
|
|
31
|
+
width: 100%;
|
|
32
|
+
display: flex;
|
|
33
|
+
label {
|
|
34
|
+
flex-grow: 1;
|
|
35
|
+
flex-basis: 0;
|
|
36
|
+
}
|
|
37
|
+
`}
|
|
38
|
+
${props => props.unevenlyWide && `
|
|
39
|
+
width: 100%;
|
|
40
|
+
display: flex;
|
|
41
|
+
label {
|
|
42
|
+
flex-grow: 1;
|
|
43
|
+
}
|
|
44
|
+
`}
|
|
45
|
+
${props => props.horizontal ? `
|
|
46
|
+
@supports (flex-wrap: wrap) {
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-wrap: wrap;
|
|
49
|
+
}
|
|
50
|
+
min-height: 3rem;
|
|
51
|
+
${SimpleRadiobox}, ${SimpleCheckbox} {
|
|
52
|
+
margin-right: 1.5rem;
|
|
53
|
+
margin-bottom: 0.5rem;
|
|
54
|
+
}
|
|
55
|
+
` : `
|
|
56
|
+
${SimpleRadiobox}, ${SimpleCheckbox} {
|
|
57
|
+
margin-bottom: 0.5rem;
|
|
58
|
+
:last-child {
|
|
59
|
+
margin-bottom: 1.5rem;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
`}
|
|
63
|
+
${props => props.framedBoxes && css`
|
|
64
|
+
${props => props.horizontal && `
|
|
65
|
+
margin: -4px;
|
|
66
|
+
width: calc(100% + 8px);
|
|
67
|
+
${SimpleRadiobox}, ${SimpleCheckbox} {
|
|
68
|
+
margin: 4px;
|
|
69
|
+
}
|
|
70
|
+
`}
|
|
71
|
+
`}
|
|
72
|
+
`
|
|
73
|
+
|
|
74
|
+
export const RadioboxGroup = InputboxGroup
|
|
75
|
+
export const CheckboxGroup = InputboxGroup
|
|
76
|
+
|
|
77
|
+
CheckboxGroup.createCheckManager = (path = []) => {
|
|
78
|
+
let lastSelected = null
|
|
79
|
+
const select = (itemOrItems,toggleValue) => {
|
|
80
|
+
lastSelected = _.isArray(itemOrItems) || _.isFunction(itemOrItems) ? lastSelected : itemOrItems
|
|
81
|
+
const items = _.isArray(itemOrItems) ? itemOrItems : [itemOrItems]
|
|
82
|
+
const intersects = (list) => path.length
|
|
83
|
+
? _.intersectionBy(path,list,items).length === items.length
|
|
84
|
+
: _.intersection(list,items).length === items.length
|
|
85
|
+
return (currentlySelected = []) =>
|
|
86
|
+
_.isFunction(itemOrItems)
|
|
87
|
+
? itemOrItems(currentlySelected)
|
|
88
|
+
: (toggleValue===false || (toggleValue !== true && intersects(currentlySelected)))
|
|
89
|
+
? (path.length ? _.differenceBy(path, currentlySelected, items) : _.difference(currentlySelected, items))
|
|
90
|
+
: (path.length ? _.uniqBy(path,currentlySelected.concat(items)) : _.uniq(currentlySelected.concat(items)))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const getIndex = (item,list) => {
|
|
94
|
+
const element = path.length ? _.intersectionBy(path, list, [item])[0] : item
|
|
95
|
+
return list.indexOf(element)
|
|
96
|
+
}
|
|
97
|
+
const shiftSelect = (availableItems,item) => {
|
|
98
|
+
const lastSelectedIndex = getIndex(lastSelected,callIfFunction(availableItems))
|
|
99
|
+
lastSelected = item
|
|
100
|
+
return (currentlySelected=[]) => {
|
|
101
|
+
if (lastSelectedIndex < 0) {
|
|
102
|
+
return select(item)(currentlySelected)
|
|
103
|
+
} else {
|
|
104
|
+
const removing = path.length ? _.intersectionBy(path, [item], currentlySelected).length : (currentlySelected?.indexOf(item)>=0)
|
|
105
|
+
const currentIndex = getIndex(item,callIfFunction(availableItems))
|
|
106
|
+
const firstIndex = currentIndex > lastSelectedIndex ? lastSelectedIndex : currentIndex
|
|
107
|
+
const lastIndex = currentIndex > lastSelectedIndex ? (currentIndex + 1) : (lastSelectedIndex + 1)
|
|
108
|
+
if (removing) {
|
|
109
|
+
return path.length
|
|
110
|
+
? _.differenceBy(path,currentlySelected,availableItems.slice(firstIndex,lastIndex))
|
|
111
|
+
: _.difference(currentlySelected,availableItems.slice(firstIndex,lastIndex))
|
|
112
|
+
} else {
|
|
113
|
+
return path.length
|
|
114
|
+
? _.unionBy(path,currentlySelected,availableItems.slice(firstIndex,lastIndex))
|
|
115
|
+
: _.union(currentlySelected,availableItems.slice(firstIndex,lastIndex))
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {select, shiftSelect}
|
|
121
|
+
}
|
package/src/Radiobox.jsx
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import styled from 'styled-components'
|
|
3
|
+
import {useInput} from './enhanceInput'
|
|
4
|
+
import {useToggle} from '@startlibs/core'
|
|
5
|
+
import {isTouchDevice} from '@startlibs/utils'
|
|
6
|
+
|
|
7
|
+
const HiddenInput = styled.input`
|
|
8
|
+
opacity: 0 !important;
|
|
9
|
+
position: absolute;
|
|
10
|
+
pointer-events: none;
|
|
11
|
+
`
|
|
12
|
+
|
|
13
|
+
export const Radiobox = ({className, children, disabled, isChecked, fieldValue, path, tabIndex = 1, raw, ...rest}) => {
|
|
14
|
+
const focused = useToggle()
|
|
15
|
+
const [value, , {setFromField, name, hasErrors}] = useInput({fieldValue, path, isChecked, ...rest}, raw)
|
|
16
|
+
const checked = isChecked ? isChecked(value) : value === fieldValue
|
|
17
|
+
return <label data-drag="false" onClick={(e) => {e.preventDefault();if (!disabled){setFromField()}}} className={className}>
|
|
18
|
+
{
|
|
19
|
+
!isTouchDevice() && <HiddenInput
|
|
20
|
+
onFocus={focused.open}
|
|
21
|
+
onBlur={focused.close}
|
|
22
|
+
disabled={disabled}
|
|
23
|
+
type="radio"
|
|
24
|
+
checked={checked}
|
|
25
|
+
value={fieldValue}
|
|
26
|
+
readOnly
|
|
27
|
+
name={name}
|
|
28
|
+
tabIndex={tabIndex}
|
|
29
|
+
/>
|
|
30
|
+
}
|
|
31
|
+
{children && children({disabled, checked, hasErrors, focused: focused.isOpen})}
|
|
32
|
+
</label>
|
|
33
|
+
}
|