@autobusal/common 0.0.40 → 0.0.41

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 (61) hide show
  1. package/ApiDetails/ApiDetails.tsx +50 -0
  2. package/ApiDetails/Content.tsx +44 -0
  3. package/ApiDetails/Devpos.tsx +139 -0
  4. package/ApiDetails/services.ts +38 -0
  5. package/ApiDetails/types.ts +13 -0
  6. package/Avatar.tsx +28 -0
  7. package/BackTo.tsx +28 -4
  8. package/ContactInfo/ContactInfo.tsx +40 -0
  9. package/ContactInfo/styles.ts +33 -0
  10. package/File/File.tsx +7 -3
  11. package/IpLogs/IpLogs.tsx +47 -0
  12. package/IpLogs/View.tsx +48 -0
  13. package/IpLogs/services.ts +27 -0
  14. package/IpLogs/styles.ts +10 -0
  15. package/Loading/Loading.tsx +29 -14
  16. package/Loading/styles.ts +9 -0
  17. package/Modal/Modal.tsx +3 -2
  18. package/Pagination/Pagination.tsx +2 -1
  19. package/Password/Password.tsx +3 -2
  20. package/Report/Report.tsx +39 -0
  21. package/Report/Send.tsx +55 -0
  22. package/Report/services.ts +18 -0
  23. package/Report/styles.ts +31 -0
  24. package/Seats/ChooseSeat.tsx +1 -1
  25. package/Seats/Preview.tsx +2 -2
  26. package/Seats/styles.ts +1 -43
  27. package/Table/Actions/Actions.tsx +40 -0
  28. package/Table/Actions/Get.tsx +49 -0
  29. package/Table/Actions/Icon.tsx +54 -0
  30. package/Table/Actions/styles.ts +22 -0
  31. package/Table/Header/Header.tsx +46 -0
  32. package/Table/Header/Sort.tsx +33 -0
  33. package/Table/Header/styles.ts +48 -0
  34. package/Table/Paginate.tsx +34 -0
  35. package/Table/Row.tsx +20 -0
  36. package/Table/Rows/Loading.tsx +22 -0
  37. package/Table/Rows/NotFound.tsx +22 -0
  38. package/Table/Rows/Rows.tsx +62 -0
  39. package/Table/Rows/styles.ts +31 -0
  40. package/Table/Table.tsx +74 -0
  41. package/Table/Top/Search.tsx +36 -0
  42. package/Table/Top/Top.tsx +44 -0
  43. package/Table/Top/styles.ts +32 -0
  44. package/Table/browseUrl.ts +21 -0
  45. package/Table/styles.ts +28 -0
  46. package/Table/types.ts +11 -0
  47. package/Viewer/Actions.tsx +58 -50
  48. package/Viewer/Data.tsx +71 -6
  49. package/Viewer/Item.tsx +8 -79
  50. package/Viewer/Items/CheckboxList.tsx +53 -30
  51. package/Viewer/Items/DatePicker.tsx +70 -0
  52. package/Viewer/Items/Dropdown.tsx +12 -6
  53. package/Viewer/Items/Linked.tsx +27 -0
  54. package/Viewer/Items/TextareaHtml.tsx +51 -24
  55. package/Viewer/Items/styles.ts +73 -0
  56. package/Viewer/Viewer.tsx +22 -15
  57. package/Viewer/styles.ts +21 -1
  58. package/Viewer/types.ts +11 -8
  59. package/index.ts +18 -2
  60. package/package.json +1 -1
  61. package/Pagination/types.ts +0 -12
@@ -0,0 +1,22 @@
1
+ import { TFunction } from 'i18next';
2
+ import { RiEmotionUnhappyLine } from 'react-icons/ri';
3
+ import { ContainerNotFound } from './styles';
4
+
5
+ interface Props {
6
+ length: number
7
+ t: TFunction<'common'>
8
+ }
9
+
10
+ const NotFound = ({ length, t }: Props): JSX.Element => (
11
+ <tbody>
12
+ <tr>
13
+ <td colSpan={ length }>
14
+ <ContainerNotFound>
15
+ <RiEmotionUnhappyLine />{ t('table.no_data', { ns: 'common' }) }
16
+ </ContainerNotFound>
17
+ </td>
18
+ </tr>
19
+ </tbody>
20
+ );
21
+
22
+ export default NotFound;
@@ -0,0 +1,62 @@
1
+ import { TFunction } from 'i18next';
2
+ import { NavigateFunction } from 'react-router-dom';
3
+ import Loading from './Loading';
4
+ import NotFound from './NotFound';
5
+ import Actions from '../Actions/Actions';
6
+ import { Tr } from './styles';
7
+
8
+ interface Props {
9
+ url: string
10
+ urlWith?: string
11
+ data?: JSX.Element[]
12
+ loading: boolean
13
+ colLength: number
14
+ t: TFunction<'common'>
15
+ actions?: string[]
16
+ handlers?: any
17
+ navigate: NavigateFunction
18
+ }
19
+
20
+ const Rows = ({ url, urlWith, data, loading, colLength, t, actions, handlers, navigate }: Props): JSX.Element => {
21
+ if (loading) {
22
+ return <Loading length={ colLength } t={ t } />;
23
+ }
24
+
25
+ if (data?.length === 0) {
26
+ return <NotFound length={ colLength } t={ t } />;
27
+ }
28
+
29
+ const isViewable = actions?.includes('view');
30
+
31
+ const onClick = (id: number): void => {
32
+ if (isViewable) {
33
+ navigate(`${ url }/manage/${ id }${ urlWith ? `?${ urlWith }` : '' }`);
34
+ }
35
+ };
36
+
37
+ const columns = data?.map((item, index) => (
38
+ <Tr key={ index } $viewable={ isViewable } onClick={ () => onClick(item.props.id) }>
39
+ { item }
40
+
41
+ { (actions !== undefined && actions.length > 0) && (
42
+ <Actions
43
+ id={ item.props.id }
44
+ url={ url }
45
+ urlWith={ urlWith }
46
+ available={ actions }
47
+ t={ t }
48
+ handlers={ handlers }
49
+ navigate={ navigate }
50
+ />
51
+ ) }
52
+ </Tr>
53
+ ));
54
+
55
+ return (
56
+ <tbody>
57
+ { columns }
58
+ </tbody>
59
+ );
60
+ };
61
+
62
+ export default Rows;
@@ -0,0 +1,31 @@
1
+ import styled, { css } from 'styled-components';
2
+
3
+ export const ContainerLoading = styled.div`
4
+ padding: 25px 0;
5
+ `;
6
+
7
+ export const ContainerNotFound = styled(ContainerLoading)`
8
+ display: flex;
9
+ justify-content: center;
10
+ align-items: center;
11
+ gap: 8px;
12
+ font-size: ${ props => props.theme.size.s };
13
+ color: ${ props => props.theme.font.faded };
14
+ `;
15
+
16
+ export const Tr = styled.tr<{ $viewable?: boolean }>`
17
+ ${ props => props.$viewable && css`
18
+ cursor: pointer;
19
+ ` }
20
+
21
+ text-align: center;
22
+
23
+ & > td:first-of-type {
24
+ text-align: left;
25
+ font-weight: 700;
26
+ }
27
+
28
+ &:hover {
29
+ background: ${ props => props.theme.background.neutral };
30
+ }
31
+ `;
@@ -0,0 +1,74 @@
1
+ import { TFunction } from 'i18next';
2
+ import Top from './Top/Top';
3
+ import Header from './Header/Header';
4
+ import Rows from './Rows/Rows';
5
+ import Paginate from './Paginate';
6
+ import { Container, Content, Inner, ContainerTable } from './styles';
7
+ import { ColumnData, SortingData } from './types';
8
+ import { useNavigate } from 'react-router-dom';
9
+ import { PaginationData } from '@modules/Providers/types/pagination';
10
+
11
+ interface Props {
12
+ url: string
13
+ urlWith?: string
14
+ columns: ColumnData[]
15
+ rows?: JSX.Element[]
16
+ pages?: PaginationData<any>
17
+ sorting?: SortingData
18
+ search?: string | null
19
+ loading: boolean
20
+ t: TFunction<'common'>
21
+ actions?: string[]
22
+ extra?: JSX.Element
23
+ handlers?: any
24
+ }
25
+
26
+ const Table = ({ url, urlWith, columns, rows, pages, sorting, search, loading, t, actions, extra, handlers }: Props): JSX.Element => {
27
+ const navigate = useNavigate();
28
+
29
+ const colLength = columns.length + 1;
30
+
31
+ return (
32
+ <Container className="box">
33
+ <Top
34
+ url={ url }
35
+ urlWith={ urlWith }
36
+ search={ search }
37
+ t={ t }
38
+ actions={ actions }
39
+ extra={ extra }
40
+ navigate={ navigate }
41
+ />
42
+
43
+ <Content>
44
+ <Inner>
45
+ <ContainerTable cellPadding={ 0 } cellSpacing={ 0 }>
46
+ <Header
47
+ url={ url }
48
+ data={ columns }
49
+ sorting={ sorting }
50
+ t={ t }
51
+ actions={ actions }
52
+ />
53
+
54
+ <Rows
55
+ url={ url }
56
+ urlWith={ urlWith }
57
+ data={ rows }
58
+ loading={ loading }
59
+ colLength={ colLength }
60
+ t={ t }
61
+ actions={ actions }
62
+ handlers={ handlers }
63
+ navigate={ navigate }
64
+ />
65
+
66
+ <Paginate data={ pages } colLength={ colLength } t={ t } />
67
+ </ContainerTable>
68
+ </Inner>
69
+ </Content>
70
+ </Container>
71
+ );
72
+ };
73
+
74
+ export default Table;
@@ -0,0 +1,36 @@
1
+ import { FormEvent, useState } from 'react';
2
+ import { NavigateFunction } from 'react-router-dom';
3
+ import { TFunction } from 'i18next';
4
+ import { parseUrl } from '../browseUrl';
5
+
6
+ interface Props {
7
+ value?: string | null
8
+ url: string
9
+ t: TFunction<'common'>
10
+ navigate: NavigateFunction
11
+ }
12
+
13
+ const Search = ({ value, url, t, navigate }: Props): JSX.Element => {
14
+ const [ q, setQ ] = useState<string>(String(value ?? ''));
15
+
16
+ const handleSubmit = (event: FormEvent<HTMLFormElement>): void => {
17
+ event.preventDefault();
18
+
19
+ const search = parseUrl({ page: 1, q });
20
+
21
+ navigate(`${ url }${ search }`);
22
+ }
23
+
24
+ return (
25
+ <form onSubmit={ handleSubmit }>
26
+ <input
27
+ type="text"
28
+ value={ q }
29
+ placeholder={ t('table.search', { ns: 'common' }) }
30
+ onChange={ (event) => setQ(event.target.value) }
31
+ />
32
+ </form>
33
+ );
34
+ };
35
+
36
+ export default Search;
@@ -0,0 +1,44 @@
1
+ import { TFunction } from 'i18next';
2
+ import { NavigateFunction } from 'react-router-dom';
3
+ import { BsPlusCircleFill } from 'react-icons/bs';
4
+ import Search from './Search';
5
+ import { Container, LinkTop } from './styles';
6
+
7
+ interface Props {
8
+ url: string
9
+ urlWith?: string
10
+ search?: string | null
11
+ t: TFunction<'common'>
12
+ actions?: string[]
13
+ extra?: JSX.Element
14
+ navigate: NavigateFunction
15
+ }
16
+
17
+ const Top = ({ url, urlWith, search, t, actions, extra, navigate }: Props): (JSX.Element | null) => {
18
+ if (actions === undefined) {
19
+ return null;
20
+ }
21
+
22
+ return (
23
+ <Container>
24
+ { actions.includes('create') && (
25
+ <LinkTop to={ `${ url }/manage/0${ urlWith ? `?${ urlWith }` : '' }` }>
26
+ <BsPlusCircleFill />{ t('table.actions.new', { ns: 'common' }) }
27
+ </LinkTop>
28
+ ) }
29
+
30
+ { actions.includes('extra') && extra }
31
+
32
+ { actions.includes('search') && (
33
+ <Search
34
+ value={ search }
35
+ url={ url }
36
+ t={ t }
37
+ navigate={ navigate }
38
+ />
39
+ ) }
40
+ </Container>
41
+ );
42
+ };
43
+
44
+ export default Top;
@@ -0,0 +1,32 @@
1
+ import styled from 'styled-components';
2
+ import { Link } from 'react-router-dom';
3
+
4
+ export const Container = styled.div`
5
+ display: flex;
6
+ justify-content: space-between;
7
+ align-items: center;
8
+ flex-wrap: wrap;
9
+ gap: 20px;
10
+ padding: 15px;
11
+ `;
12
+
13
+ export const LinkTop = styled(Link)`
14
+ display: flex;
15
+ gap: 6px;
16
+ height: 38px;
17
+ align-items: center;
18
+ justify-content: center;
19
+ padding: 0 20px;
20
+ font-weight: 700;
21
+ color: ${ props => props.theme.primary.contrast };
22
+ background: ${ props => props.theme.primary.normal };
23
+ border: 1px solid ${ props => props.theme.primary.normal };
24
+ border-radius: 100px;
25
+ cursor: pointer;
26
+ transition: all 0.3s ease;
27
+
28
+ &:hover {
29
+ text-decoration: none;
30
+ box-shadow: 0 4px 15px ${ props => props.theme.primary.normal };
31
+ }
32
+ `;
@@ -0,0 +1,21 @@
1
+ import queryString from 'query-string';
2
+
3
+ export const parseUrl = (replace: any): string => {
4
+ const query = queryString.parse(location.search);
5
+
6
+ Object.keys(replace).map(param => {
7
+ query[param] = replace[param]
8
+ });
9
+
10
+ const params = Object.keys(query).map(param => (
11
+ `${ param }=${ query[param] }`
12
+ ));
13
+
14
+ const url = params.join('&');
15
+
16
+ return `?${ url }`
17
+ };
18
+
19
+ export const getUrl = (): any => (
20
+ queryString.parse(location.search)
21
+ );
@@ -0,0 +1,28 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ padding: 0 !important;
5
+ `;
6
+
7
+ export const Content = styled.div`
8
+ overflow-x: auto;
9
+ `;
10
+
11
+ export const Inner = styled.div`
12
+ min-width: 750px;
13
+ `;
14
+
15
+ export const ContainerTable = styled.table`
16
+ width: 100%;
17
+ font-size: ${ props => props.theme.size.s };
18
+ `;
19
+
20
+ export const Td = styled.td`
21
+ padding: 10px 16px;
22
+ border-top: 1px solid ${ props => props.theme.background.neutral };
23
+ `;
24
+
25
+ export const ContainerPaginate = styled.div`
26
+ padding: 10px 16px;
27
+ border-top: 1px solid ${ props => props.theme.background.neutral };
28
+ `;
package/Table/types.ts ADDED
@@ -0,0 +1,11 @@
1
+ export interface ColumnData {
2
+ name: string
3
+ width?: number
4
+ slug?: string
5
+ type?: 'az'
6
+ }
7
+
8
+ export interface SortingData {
9
+ slug: string
10
+ order: 'asc' | 'desc'
11
+ }
@@ -1,48 +1,53 @@
1
1
  import { TFunction } from 'i18next';
2
2
  import { BiEditAlt, BiTrash, BiSend } from 'react-icons/bi';
3
- // import { RiSave2Line, RiCheckFill, RiSearchLine } from 'react-icons/ri';
4
- // import { BsPlusCircleFill } from 'react-icons/bs';
3
+ import { RiSave2Line, RiCheckFill, RiSearchLine } from 'react-icons/ri';
4
+ import { BsPlusCircleFill } from 'react-icons/bs';
5
5
  import { ContainerActions } from './styles';
6
6
  import { ActionData } from './types';
7
7
  import { Button } from '@autobusal/common';
8
8
 
9
9
  interface Props {
10
+ id: number
10
11
  available: string[]
11
12
  loading?: boolean
12
13
  t: TFunction<'common'>
14
+ onDelete?: () => void
13
15
  }
14
16
 
15
- const Actions = ({ available, loading, t }: Props): JSX.Element => {
17
+ const Actions = ({ id, available, loading, t, onDelete }: Props): JSX.Element => {
18
+ const options: ActionData[] = [];
16
19
 
17
- // function Actions({ id, actions, status, t, deleter }) {
18
- let options: ActionData[] = [];
19
-
20
- // const askDeletion = () => {
21
- // if (window.confirm(t('general:table.confirm'))) {
22
- // deleter();
23
- // }
24
- // };
20
+ const onAskDelete = (): void => {
21
+ if (window.confirm(t('table.confirm', { ns: 'common' }))) {
22
+ if (onDelete) {
23
+ onDelete();
24
+ }
25
+ }
26
+ };
25
27
 
26
- // if (actions.includes('add')) {
27
- // options.push({
28
- // label: t('general:table.action.add'),
29
- // icon: <BsPlusCircleFill />
30
- // });
31
- // }
28
+ if (available.includes('add')) {
29
+ options.push({
30
+ label: t('table.actions.add', { ns: 'common' }),
31
+ icon: <BsPlusCircleFill />,
32
+ type: 'submit'
33
+ });
34
+ }
32
35
 
33
- // if (actions.includes('save')) {
34
- // options.push({
35
- // label: t('general:table.action.save'),
36
- // icon: <RiSave2Line />
37
- // });
38
- // }
36
+ if (available.includes('save')) {
37
+ options.push({
38
+ label: t('table.actions.save', { ns: 'common' }),
39
+ icon: <RiSave2Line />,
40
+ type: 'submit'
41
+ });
42
+ }
39
43
 
40
- // if (actions.includes('send')) {
41
- // options.push({
42
- // label: t('general:table.action.send'),
43
- // icon: <BiSend />
44
- // });
45
- // }
44
+ if (available.includes('send')) {
45
+ options.push({
46
+ label: t('table.actions.send', { ns: 'common' }),
47
+ icon: <BiSend />,
48
+ type: 'submit'
49
+ });
50
+ }
46
51
 
47
52
  if (available.includes('update')) {
48
53
  options.push({
@@ -52,39 +57,42 @@ const Actions = ({ available, loading, t }: Props): JSX.Element => {
52
57
  });
53
58
  }
54
59
 
55
- // if (actions.includes('approve')) {
56
- // options.push({
57
- // label: t('general:table.action.approve'),
58
- // icon: <RiCheckFill />
59
- // });
60
- // }
60
+ if (available.includes('approve')) {
61
+ options.push({
62
+ label: t('table.actions.approve', { ns: 'common' }),
63
+ icon: <RiCheckFill />,
64
+ type: 'submit'
65
+ });
66
+ }
61
67
 
62
- // if (actions.includes('delete') && id > 0) {
63
- // options.push({
64
- // label: t('general:table.action.delete'),
65
- // icon: <BiTrash />,
66
- // type: 'button',
67
- // className: "delete",
68
- // handler: askDeletion
69
- // });
70
- // }
68
+ if (available.includes('delete') && id > 0) {
69
+ options.push({
70
+ label: t('table.actions.delete', { ns: 'common' }),
71
+ icon: <BiTrash />,
72
+ subtype: 'delete',
73
+ handler: onAskDelete
74
+ });
75
+ }
71
76
 
72
- // if (actions.includes('search')) {
73
- // options.push({
74
- // label: t('general:table.action.search'),
75
- // icon: <RiSearchLine />
76
- // });
77
- // }
77
+ if (available.includes('search')) {
78
+ options.push({
79
+ label: t('table.actions.search', { ns: 'common' }),
80
+ icon: <RiSearchLine />,
81
+ type: 'submit'
82
+ });
83
+ }
78
84
 
79
85
  const items = options.map((item, index) => (
80
86
  <Button
81
87
  key={ index }
82
88
  type={ item.type === 'submit' ? 'submit' : 'button' }
89
+ subtype={ item.subtype }
83
90
  text={
84
91
  <>{ item.icon } { item.label }</>
85
92
  }
86
93
  loading={ loading }
87
94
  noMargin
95
+ onClick={ item.handler }
88
96
  />
89
97
  ));
90
98
 
package/Viewer/Data.tsx CHANGED
@@ -1,30 +1,63 @@
1
+ import { TFunction } from 'i18next';
1
2
  import { UseFormRegister, UseFormSetValue } from 'react-hook-form';
3
+ import CheckboxList from './Items/CheckboxList';
4
+ import Linked from './Items/Linked';
5
+ import TextareaHtml from './Items/TextareaHtml';
6
+ import Password from '../Password/Password';
2
7
  import Dropdown from './Items/Dropdown';
8
+ import DatePicker from './Items/DatePicker';
3
9
  import { ViewData } from './types';
4
10
  import Calendar from '../Calendar/Calendar';
5
11
  import File from '../File/File';
6
12
  import { validate } from '@autobusal/utilities';
7
- import { TFunction } from 'i18next';
13
+ import { Display } from './styles';
8
14
 
9
15
  interface Props {
16
+ id: number
10
17
  item: ViewData
11
18
  refs: UseFormRegister<any>
12
19
  t: TFunction<'common'>
13
20
  onUpdate: UseFormSetValue<any>
14
21
  }
15
22
 
16
- const Data = ({ item, refs, t, onUpdate }: Props): (JSX.Element | null) => {
23
+ const Data = ({ id, item, refs, t, onUpdate }: Props): (JSX.Element | null) => {
17
24
  if (item.name === undefined) {
18
25
  return null;
19
26
  }
20
27
 
21
28
  switch (item.type) {
29
+ case 'checkbox':
30
+ return <input type="checkbox" value={ 1 } defaultChecked={ Number(item.value) == 1 } { ...refs(item.name, validate(String(item.rules), t)) } />;
31
+
32
+ case 'checkbox-list':
33
+ case 'checkbox-list-all':
34
+ return (
35
+ <CheckboxList
36
+ name={ item.name }
37
+ values={ item.values }
38
+ selected={ item.selected }
39
+ withAll={ item.type !== 'checkbox-list' }
40
+ t={ t }
41
+ refs={ refs }
42
+ />
43
+ );
44
+
45
+ case 'component':
46
+ return <div className="row-data">{ item.value }</div>;
47
+
48
+ case 'display':
49
+ return <Display className="row-data">{ item.value }</Display>;
50
+
51
+ case 'date':
22
52
  case 'dob':
53
+ case 'picker':
54
+ const value = item.value !== null && item.value !== undefined ? String(item.value) : undefined;
55
+
23
56
  return (
24
57
  <Calendar
25
58
  type={ item.type }
26
59
  name={ item.name }
27
- defaultValue={ item.value !== null ? String(item.value) : undefined }
60
+ defaultValue={ value }
28
61
  t={ t }
29
62
  validation={ item.rules }
30
63
  refs={ refs }
@@ -32,25 +65,57 @@ const Data = ({ item, refs, t, onUpdate }: Props): (JSX.Element | null) => {
32
65
  />
33
66
  );
34
67
 
68
+ case 'date-picker':
69
+ return <DatePicker item={ item } t={ t } refs={ refs } onUpdate={ onUpdate } />;
70
+
71
+ case 'email':
72
+ return <input type="email" defaultValue={ item.value ? String(item.value) : undefined } { ...refs(item.name, validate(String(item.rules), t)) } />;
73
+
35
74
  case 'file':
75
+ case 'files':
36
76
  return (
37
77
  <File
38
78
  name={ item.name }
39
- value={ item.value !== undefined ? String(item.value) : undefined }
79
+ value={ item.value ? String(item.value) : undefined }
40
80
  validation={ item.rules }
81
+ multiple={ item.type === 'files' }
41
82
  t={ t }
42
83
  refs={ refs }
43
84
  />
44
85
  );
45
86
 
87
+ case 'float':
88
+ return <input type="number" defaultValue={ item.value ? Number(item.value) : undefined } { ...refs(item.name, validate(String(item.rules), t)) } step="0.01" />;
89
+
90
+ case 'link':
91
+ return <Linked id={ id } value={ item.value } url={ item.url } />;
92
+
93
+ case 'number':
94
+ return <input type="number" defaultValue={ item.value ? Number(item?.value) : undefined } { ...refs(item.name, validate(String(item.rules), t)) } />
95
+
96
+ case 'password':
97
+ return <Password name={ item.name } validation={ item.rules } t={ t } refs={ refs } />;
98
+
46
99
  case 'select':
47
100
  return <Dropdown item={ item } refs={ refs } t={ t } />;
48
101
 
49
102
  case 'text':
50
- return <input type="text" defaultValue={ item.value } { ...refs(item.name, validate(String(item.rules), t)) } />;
103
+ return <input type="text" defaultValue={ item.value ? String(item.value) : undefined } { ...refs(item.name, validate(String(item.rules), t)) } />;
51
104
 
52
105
  case 'textarea':
53
- return <textarea defaultValue={ item.value } { ...refs(item.name, validate(String(item.rules), t)) }></textarea>;
106
+ return <textarea defaultValue={ item.value ? String(item.value) : undefined } { ...refs(item.name, validate(String(item.rules), t)) }></textarea>;
107
+
108
+ case 'textarea-html':
109
+ return (
110
+ <TextareaHtml
111
+ name={ item.name }
112
+ value={ item.value ? String(item.value) : undefined }
113
+ validation={ item.rules }
114
+ t={ t }
115
+ refs={ refs }
116
+ onUpdate={ onUpdate }
117
+ />
118
+ );
54
119
  }
55
120
 
56
121
  return null;