design-react-kit 5.6.1 → 5.7.1

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 (109) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/Accordion/AccordionBody.cjs +1 -1
  3. package/dist/Accordion/AccordionBody.cjs.map +1 -1
  4. package/dist/Accordion/AccordionBody.js +31 -21
  5. package/dist/Accordion/AccordionBody.js.map +1 -1
  6. package/dist/Accordion/AccordionHeader.cjs +1 -1
  7. package/dist/Accordion/AccordionHeader.cjs.map +1 -1
  8. package/dist/Accordion/AccordionHeader.js +1 -1
  9. package/dist/Accordion/AccordionHeader.js.map +1 -1
  10. package/dist/Autocomplete/Autocomplete.cjs +1 -3
  11. package/dist/Autocomplete/Autocomplete.cjs.map +1 -1
  12. package/dist/Autocomplete/Autocomplete.js +27 -4
  13. package/dist/Autocomplete/Autocomplete.js.map +1 -1
  14. package/dist/Carousel/Carousel.cjs +2 -0
  15. package/dist/Carousel/Carousel.cjs.map +1 -0
  16. package/dist/Carousel/Carousel.js +193 -0
  17. package/dist/Carousel/Carousel.js.map +1 -0
  18. package/dist/Carousel/CarouselSlide.cjs +2 -0
  19. package/dist/Carousel/CarouselSlide.cjs.map +1 -0
  20. package/dist/Carousel/CarouselSlide.js +8 -0
  21. package/dist/Carousel/CarouselSlide.js.map +1 -0
  22. package/dist/Header/Headers.cjs +1 -1
  23. package/dist/Header/Headers.cjs.map +1 -1
  24. package/dist/Header/Headers.js +3 -8
  25. package/dist/Header/Headers.js.map +1 -1
  26. package/dist/Input/Input.cjs +1 -1
  27. package/dist/Input/Input.cjs.map +1 -1
  28. package/dist/Input/Input.js +1 -2
  29. package/dist/Input/Input.js.map +1 -1
  30. package/dist/Rating/Rating.cjs +1 -1
  31. package/dist/Rating/Rating.cjs.map +1 -1
  32. package/dist/Transfer/BacktransferButton.cjs +2 -0
  33. package/dist/Transfer/BacktransferButton.cjs.map +1 -0
  34. package/dist/Transfer/BacktransferButton.js +20 -0
  35. package/dist/Transfer/BacktransferButton.js.map +1 -0
  36. package/dist/Transfer/Item.cjs +2 -0
  37. package/dist/Transfer/Item.cjs.map +1 -0
  38. package/dist/Transfer/Item.js +15 -0
  39. package/dist/Transfer/Item.js.map +1 -0
  40. package/dist/Transfer/ResetButton.cjs +2 -0
  41. package/dist/Transfer/ResetButton.cjs.map +1 -0
  42. package/dist/Transfer/ResetButton.js +16 -0
  43. package/dist/Transfer/ResetButton.js.map +1 -0
  44. package/dist/Transfer/SelectAllCheckbox.cjs +2 -0
  45. package/dist/Transfer/SelectAllCheckbox.cjs.map +1 -0
  46. package/dist/Transfer/SelectAllCheckbox.js +11 -0
  47. package/dist/Transfer/SelectAllCheckbox.js.map +1 -0
  48. package/dist/Transfer/Source.cjs +2 -0
  49. package/dist/Transfer/Source.cjs.map +1 -0
  50. package/dist/Transfer/Source.js +61 -0
  51. package/dist/Transfer/Source.js.map +1 -0
  52. package/dist/Transfer/Target.cjs +2 -0
  53. package/dist/Transfer/Target.cjs.map +1 -0
  54. package/dist/Transfer/Target.js +60 -0
  55. package/dist/Transfer/Target.js.map +1 -0
  56. package/dist/Transfer/Transfer.cjs +2 -0
  57. package/dist/Transfer/Transfer.cjs.map +1 -0
  58. package/dist/Transfer/Transfer.js +21 -0
  59. package/dist/Transfer/Transfer.js.map +1 -0
  60. package/dist/Transfer/TransferButton.cjs +2 -0
  61. package/dist/Transfer/TransferButton.cjs.map +1 -0
  62. package/dist/Transfer/TransferButton.js +20 -0
  63. package/dist/Transfer/TransferButton.js.map +1 -0
  64. package/dist/Transfer/useTransferContext.cjs +2 -0
  65. package/dist/Transfer/useTransferContext.cjs.map +1 -0
  66. package/dist/Transfer/useTransferContext.js +63 -0
  67. package/dist/Transfer/useTransferContext.js.map +1 -0
  68. package/dist/Video/Video.cjs +2 -0
  69. package/dist/Video/Video.cjs.map +1 -0
  70. package/dist/Video/Video.js +99 -0
  71. package/dist/Video/Video.js.map +1 -0
  72. package/dist/index.cjs +1 -3
  73. package/dist/index.cjs.map +1 -1
  74. package/dist/index.js +4 -0
  75. package/dist/index.js.map +1 -1
  76. package/dist/types/Autocomplete/Autocomplete.d.ts +10 -5
  77. package/dist/types/Carousel/Carousel.d.ts +7 -0
  78. package/dist/types/Carousel/CarouselSlide.d.ts +2 -0
  79. package/dist/types/Input/Input.d.ts +1 -1
  80. package/dist/types/Transfer/BacktransferButton.d.ts +3 -0
  81. package/dist/types/Transfer/Item.d.ts +12 -0
  82. package/dist/types/Transfer/ResetButton.d.ts +3 -0
  83. package/dist/types/Transfer/SelectAllCheckbox.d.ts +10 -0
  84. package/dist/types/Transfer/Source.d.ts +9 -0
  85. package/dist/types/Transfer/Target.d.ts +9 -0
  86. package/dist/types/Transfer/Transfer.d.ts +40 -0
  87. package/dist/types/Transfer/TransferButton.d.ts +3 -0
  88. package/dist/types/Transfer/useTransferContext.d.ts +49 -0
  89. package/dist/types/Video/Video.d.ts +58 -0
  90. package/dist/types/index.d.ts +6 -0
  91. package/package.json +6 -4
  92. package/src/Accordion/AccordionBody.tsx +32 -22
  93. package/src/Accordion/AccordionHeader.tsx +0 -1
  94. package/src/Autocomplete/Autocomplete.tsx +69 -18
  95. package/src/Carousel/Carousel.tsx +210 -0
  96. package/src/Carousel/CarouselSlide.tsx +14 -0
  97. package/src/Header/Headers.tsx +4 -13
  98. package/src/Input/Input.tsx +9 -11
  99. package/src/Transfer/BacktransferButton.tsx +33 -0
  100. package/src/Transfer/Item.tsx +33 -0
  101. package/src/Transfer/ResetButton.tsx +28 -0
  102. package/src/Transfer/SelectAllCheckbox.tsx +30 -0
  103. package/src/Transfer/Source.tsx +89 -0
  104. package/src/Transfer/Target.tsx +87 -0
  105. package/src/Transfer/Transfer.tsx +31 -0
  106. package/src/Transfer/TransferButton.tsx +33 -0
  107. package/src/Transfer/useTransferContext.tsx +110 -0
  108. package/src/Video/Video.tsx +205 -0
  109. package/src/index.ts +6 -0
@@ -0,0 +1,210 @@
1
+ import React, { FC } from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ import {Splide, SplideProps} from '@splidejs/react-splide'
5
+
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ const CONFIG_DEFAULT: any = {
8
+ slideFocus: false,
9
+ rewind: true,
10
+ perMove: 1,
11
+ i18n: {
12
+ prev: 'Slide precedente',
13
+ next: 'Slide successiva',
14
+ first: 'Vai alla prima slide',
15
+ last: 'Vai all’ultima slide',
16
+ slideX: 'Vai alla slide %s',
17
+ pageX: 'Vai a pagina %s',
18
+ play: 'Attiva autoplay',
19
+ pause: 'Pausa autoplay',
20
+ carousel: 'Carosello',
21
+ select: 'Seleziona una slide da mostrare',
22
+ slide: 'slide',
23
+ slideLabel: '%s di %s',
24
+ },
25
+ }
26
+
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ const CONFIGS: any= {
29
+ 'landscape-three-cols': {
30
+ type: 'slide',
31
+ perPage: 3,
32
+ gap: 24,
33
+ padding: { left: 0, right: 0 },
34
+ arrows: false,
35
+ breakpoints: {
36
+ 768: {
37
+ perPage: 1,
38
+ gap: 24,
39
+ padding: { left: 0, right: 0 },
40
+ arrows: false,
41
+ },
42
+ 992: {
43
+ perPage: 2,
44
+ gap: 24,
45
+ padding: { left: 40, right: 40 },
46
+ arrows: false,
47
+ },
48
+ },
49
+ },
50
+ 'landscape-three-cols-arrows': {
51
+ type: 'slide',
52
+ perPage: 3,
53
+ gap: 24,
54
+ padding: { left: 0, right: 0 },
55
+ arrows: true,
56
+ breakpoints: {
57
+ 768: {
58
+ perPage: 1,
59
+ gap: 24,
60
+ padding: { left: 40, right: 40 },
61
+ arrows: true,
62
+ },
63
+ 992: {
64
+ perPage: 2,
65
+ gap: 24,
66
+ padding: { left: 40, right: 40 },
67
+ arrows: true,
68
+ },
69
+ },
70
+ },
71
+ 'big-image': {
72
+ type: 'loop',
73
+ perPage: 1,
74
+ gap: 48,
75
+ padding: { left: 320, right: 320 },
76
+ arrows: false,
77
+ breakpoints: {
78
+ 768: {
79
+ perPage: 1,
80
+ gap: 0,
81
+ padding: { left: 0, right: 0 },
82
+ arrows: false,
83
+ },
84
+ 992: {
85
+ perPage: 1,
86
+ gap: 24,
87
+ padding: { left: 160, right: 160 },
88
+ arrows: false,
89
+ },
90
+ },
91
+ },
92
+ 'standard-image': {
93
+ type: 'loop',
94
+ perPage: 3,
95
+ gap: 24,
96
+ padding: { left: 48, right: 48 },
97
+ arrows: false,
98
+ breakpoints: {
99
+ 768: {
100
+ perPage: 1,
101
+ gap: 24,
102
+ padding: { left: 40, right: 40 },
103
+ arrows: false,
104
+ },
105
+ 992: {
106
+ perPage: 2,
107
+ gap: 24,
108
+ padding: { left: 48, right: 48 },
109
+ arrows: false,
110
+ },
111
+ },
112
+ },
113
+ 'landscape': {
114
+ type: 'slide',
115
+ perPage: 1,
116
+ gap: 24,
117
+ padding: { left: 0, right: 0 },
118
+ arrows: false,
119
+ breakpoints: {
120
+ 768: {
121
+ perPage: 1,
122
+ gap: 24,
123
+ padding: { left: 0, right: 0 },
124
+ arrows: false,
125
+ },
126
+ 992: {
127
+ perPage: 1,
128
+ gap: 24,
129
+ padding: { left: 24, right: 24 },
130
+ arrows: false,
131
+ },
132
+ },
133
+ },
134
+ 'calendar-wrapper': {
135
+ type: 'slide',
136
+ perPage: 4,
137
+ gap: 0,
138
+ padding: { left: 0, right: 0 },
139
+ arrows: false,
140
+ breakpoints: {
141
+ 560: {
142
+ perPage: 1,
143
+ gap: 0,
144
+ padding: { left: 24, right: 24 },
145
+ arrows: false,
146
+ },
147
+ 768: {
148
+ perPage: 2,
149
+ gap: 0,
150
+ padding: { left: 0, right: 0 },
151
+ arrows: false,
152
+ },
153
+ 992: {
154
+ perPage: 3,
155
+ gap: 0,
156
+ padding: { left: 0, right: 0 },
157
+ arrows: false,
158
+ },
159
+ },
160
+ },
161
+ }
162
+
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ const EXTRA_CLASSES: any= {
165
+ 'landscape-three-cols': [
166
+ 'it-carousel-landscape-abstract-three-cols'
167
+ ],
168
+ 'landscape-three-cols-arrows': [
169
+ 'it-carousel-landscape-abstract-three-cols-arrow-visible'
170
+ ],
171
+ 'big-image': [
172
+ 'it-carousel-landscape-abstract-three-cols',
173
+ 'it-full-carousel',
174
+ 'it-big-img'
175
+ ],
176
+ 'standard-image': [
177
+ 'it-carousel-landscape-abstract-three-cols',
178
+ 'it-full-carousel',
179
+ 'it-standard-image'
180
+ ],
181
+ 'landscape': [
182
+ 'it-carousel-landscape-abstract'
183
+ ],
184
+ 'calendar-wrapper': [
185
+ 'it-calendar-wrapper'
186
+ ]
187
+ }
188
+
189
+ export interface CarouselProps extends SplideProps {
190
+ type: string;
191
+ children?: React.ReactNode;
192
+ }
193
+
194
+ // Splide wrapper
195
+ export const Carousel: FC<CarouselProps> = ({
196
+ className = '',
197
+ type,
198
+ children,
199
+ ...attributes
200
+ }) => {
201
+ let conf = Object.assign({}, CONFIG_DEFAULT)
202
+ if (['big-image', 'standard-image'].includes(type)){
203
+ conf = Object.assign({}, conf, CONFIGS['landscape-three-cols'])
204
+ }
205
+ conf = Object.assign({}, conf, CONFIGS[type])
206
+ return <Splide
207
+ {...attributes}
208
+ className={classNames('it-carousel-wrapper', className, ...EXTRA_CLASSES[type])}
209
+ options={conf}>{children}</Splide>;
210
+ };
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import {SplideSlide} from '@splidejs/react-splide'
3
+
4
+ // Splide wrapper
5
+ export const CarouselSlide: React.FC<JSX.IntrinsicElements['li']> = ({
6
+ children,
7
+ }) => {
8
+
9
+ return <SplideSlide>
10
+ <div className='it-single-slide-wrapper'>
11
+ {children}
12
+ </div>
13
+ </SplideSlide>;
14
+ };
@@ -1,7 +1,5 @@
1
1
  import React, { FC, HTMLAttributes } from 'react';
2
2
  import classNames from 'classnames';
3
- import { Sticky, StickyProvider } from 'react-stickup';
4
-
5
3
  export interface HeadersProps extends HTMLAttributes<HTMLElement> {
6
4
  /** Aggiunge un ombra per enfatizzare il componente rispetto alla pagina in cui è contenuto */
7
5
  shadow?: boolean;
@@ -17,18 +15,11 @@ export const Headers: FC<HeadersProps> = ({ className, shadow = false, sticky =
17
15
  'it-header-wrapper',
18
16
  {
19
17
  'it-shadow': shadow,
20
- 'it-header-sticky': sticky
18
+ 'it-header-sticky': sticky,
19
+ 'sticky-top': sticky
20
+
21
21
  },
22
22
  className
23
23
  );
24
- if (!sticky) {
25
- return <div className={classes} {...attributes} data-testid={testId}></div>;
26
- }
27
- return (
28
- <StickyProvider>
29
- <Sticky style={{ position: 'sticky', zIndex: 2 }} data-testid={testId}>
30
- <div className={classes} {...attributes}></div>
31
- </Sticky>
32
- </StickyProvider>
33
- );
24
+ return <div className={classes} {...attributes} data-testid={testId}></div>;
34
25
  };
@@ -62,7 +62,7 @@ export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
62
62
  decrementLabel?: string | ReactNode;
63
63
  /** Testo di esempio da utilizzare per il campo. */
64
64
  placeholder?: string;
65
- /** Testo di validazione per l'elemento del moduleo form. */
65
+ /** Testo di validazione per l'elemento del modulo form. */
66
66
  validationText?: string;
67
67
  /** Testo di aiuto per l'elemento del moduleo form. Richiede che il componente `Input` abbia la prop `id` impostata. */
68
68
  infoText?: string;
@@ -356,16 +356,14 @@ export const Input = ({
356
356
 
357
357
  if (indeterminateCheckboxInput) {
358
358
  return (
359
- <InputContainer {...containerProps}>
360
- <Tag
361
- {...rest}
362
- {...extraAttributes}
363
- {...sharedAttributes}
364
- className={inputClasses}
365
- data-testid={testId}
366
- indeterminate={'true'}
367
- />
368
- </InputContainer>
359
+ <Tag
360
+ {...rest}
361
+ {...extraAttributes}
362
+ {...sharedAttributes}
363
+ className={inputClasses}
364
+ data-testid={testId}
365
+ indeterminate={'true'}
366
+ />
369
367
  );
370
368
  }
371
369
 
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { Icon } from '../Icon/Icon';
3
+ import { useTransferContext } from './useTransferContext';
4
+
5
+ const BacktransferButton = () => {
6
+ const { targetCandidates, sourceItems, targetItems, setSourceItems, setTargetItems, setTargetCandidates } =
7
+ useTransferContext();
8
+ const handleTransfer: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
9
+ e.preventDefault();
10
+ const newTargetItems = targetItems.filter((item) => !targetCandidates.includes(item.id));
11
+ const newSourceItems = sourceItems.concat(targetItems.filter((item) => targetCandidates.includes(item.id)));
12
+ setSourceItems({ items: newSourceItems });
13
+ setTargetItems({ items: newTargetItems });
14
+ setTargetCandidates([]);
15
+ };
16
+ return (
17
+ <>
18
+ <a
19
+ className={`backtransfer ${targetCandidates.length > 0 ? 'active' : ''}`}
20
+ href='#'
21
+ role='button'
22
+ aria-label='Sposta indietro'
23
+ onClick={handleTransfer}
24
+ data-testid='backtransfer-button'
25
+ >
26
+ <Icon icon='it-arrow-left' />
27
+ </a>
28
+ <span className='visually-hidden'>Etichetta per freccia sinistra</span>
29
+ </>
30
+ );
31
+ };
32
+
33
+ export { BacktransferButton };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { FormGroup, Input, Label } from '..';
3
+
4
+ const Item = ({ id, children }: { id: string; children: React.ReactNode }) => {
5
+ return (
6
+ <>
7
+ {id} - {children}
8
+ </>
9
+ );
10
+ };
11
+
12
+ const InternalItem = ({
13
+ id,
14
+ checked,
15
+ children,
16
+ onChange
17
+ }: {
18
+ id: string;
19
+ checked?: boolean;
20
+ children: React.ReactNode;
21
+ onChange?: React.ChangeEventHandler<HTMLInputElement>;
22
+ }) => {
23
+ return (
24
+ <FormGroup check>
25
+ <Input checked={checked} onChange={onChange} id={id} type='checkbox' />
26
+ <Label for={id} check>
27
+ {children}
28
+ </Label>
29
+ </FormGroup>
30
+ );
31
+ };
32
+
33
+ export { InternalItem, Item };
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { Icon } from '../Icon/Icon';
3
+ import { useTransferContext } from './useTransferContext';
4
+
5
+ const ResetButton = () => {
6
+ const { reset, isChanged } = useTransferContext();
7
+ const handleReset: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
8
+ e.preventDefault();
9
+ reset();
10
+ };
11
+ return (
12
+ <>
13
+ <a
14
+ className={`reset ${isChanged ? 'active' : ''}`}
15
+ href='#'
16
+ role='button'
17
+ aria-label='Reset'
18
+ onClick={handleReset}
19
+ data-testid='reset-button'
20
+ >
21
+ <Icon icon='it-restore' />
22
+ </a>
23
+ <span className='visually-hidden'>Etichetta per icona di reset</span>
24
+ </>
25
+ );
26
+ };
27
+
28
+ export { ResetButton };
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { FormGroup, Input, Label } from '..';
3
+
4
+ const SelectAllCheckbox = ({
5
+ className,
6
+ description,
7
+ checked,
8
+ id,
9
+ onChange,
10
+ children
11
+ }: {
12
+ className?: string;
13
+ id: string;
14
+ checked?: boolean;
15
+ onChange: React.ChangeEventHandler<HTMLInputElement>;
16
+ children: React.ReactNode;
17
+ description?: string;
18
+ }) => {
19
+ return (
20
+ <FormGroup check>
21
+ <Input className={className} checked={checked} onChange={onChange} id={id} type='checkbox' />
22
+ <Label for={id} check>
23
+ {children}
24
+ {description && <span className='descr'>{description}</span>}
25
+ </Label>
26
+ </FormGroup>
27
+ );
28
+ };
29
+
30
+ export { SelectAllCheckbox };
@@ -0,0 +1,89 @@
1
+ import React, { useEffect } from 'react';
2
+ import { InternalItem, Item } from './Item';
3
+ import { SelectAllCheckbox } from './SelectAllCheckbox';
4
+ import { useTransferContext } from './useTransferContext';
5
+
6
+ const SourceItem = ({ id, children }: { id: string; children: React.ReactNode }) => {
7
+ const { sourceCandidates, setSourceCandidates } = useTransferContext();
8
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
9
+ if (e.target.checked) {
10
+ setSourceCandidates([...new Set([...sourceCandidates, e.target.id])]);
11
+ } else {
12
+ setSourceCandidates(sourceCandidates.filter((item) => item !== e.target.id));
13
+ }
14
+ };
15
+ const isChecked = sourceCandidates.includes(id);
16
+ return (
17
+ <InternalItem checked={isChecked} id={id} onChange={handleChange}>
18
+ {children}
19
+ </InternalItem>
20
+ );
21
+ };
22
+
23
+ const Source: React.FC<{ children?: React.ReactNode }> & {
24
+ Header: React.FC<{ children?: React.ReactNode }>;
25
+ } = ({ children }) => {
26
+ const { sourceItems, setSourceItems } = useTransferContext();
27
+ const otherComponents: React.ReactNode[] = [];
28
+ const childrenSource = React.Children.map(children, (child) => {
29
+ if (React.isValidElement(child) && child.type === Item) {
30
+ const { id, children } = child.props;
31
+ return { id, content: children };
32
+ }
33
+ otherComponents.push(child);
34
+ return null;
35
+ })?.filter((item) => item !== null);
36
+
37
+ useEffect(() => {
38
+ if (!childrenSource) return;
39
+ setSourceItems({ items: childrenSource, setOriginals: true });
40
+ }, []);
41
+
42
+ return (
43
+ <div className='it-transfer-wrapper source' data-testid='transfer-source'>
44
+ {otherComponents}
45
+ {sourceItems.map(({ id, content }) => (
46
+ <SourceItem key={id} id={id}>
47
+ {content}
48
+ </SourceItem>
49
+ ))}
50
+
51
+ <br />
52
+ </div>
53
+ );
54
+ };
55
+
56
+ Source.Header = ({ children }: { children?: React.ReactNode }) => {
57
+ const { sourceItems, sourceCandidates, setSourceCandidates } = useTransferContext();
58
+
59
+ const getStatus = () => {
60
+ if (sourceCandidates.length === 0) {
61
+ return { checked: false };
62
+ }
63
+ if (sourceItems.every((item) => sourceCandidates.includes(item.id))) {
64
+ return { checked: true };
65
+ }
66
+ return { checked: false, className: 'semi-checked' };
67
+ };
68
+
69
+ return (
70
+ <div className='transfer-header' data-testid='transfer-source-header'>
71
+ <SelectAllCheckbox
72
+ {...getStatus()}
73
+ onChange={(e) => {
74
+ if (e.target.checked) {
75
+ setSourceCandidates([...new Set(sourceItems.map((item) => item.id))]);
76
+ } else {
77
+ setSourceCandidates([]);
78
+ }
79
+ }}
80
+ id='transfer-source-header'
81
+ description={children ? 'Source' : undefined}
82
+ >
83
+ {children ? children : 'Source'}
84
+ </SelectAllCheckbox>
85
+ </div>
86
+ );
87
+ };
88
+
89
+ export { Source };
@@ -0,0 +1,87 @@
1
+ import React, { useEffect } from 'react';
2
+ import { InternalItem, Item } from './Item';
3
+ import { SelectAllCheckbox } from './SelectAllCheckbox';
4
+ import { useTransferContext } from './useTransferContext';
5
+
6
+ const TargetItem = ({ id, children }: { id: string; children: React.ReactNode }) => {
7
+ const { targetCandidates, setTargetCandidates } = useTransferContext();
8
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
9
+ if (e.target.checked) {
10
+ setTargetCandidates([...new Set([...targetCandidates, e.target.id])]);
11
+ } else {
12
+ setTargetCandidates(targetCandidates.filter((item) => item !== e.target.id));
13
+ }
14
+ };
15
+ const isChecked = targetCandidates.includes(id);
16
+ return (
17
+ <InternalItem checked={isChecked} id={id} onChange={handleChange}>
18
+ {children}
19
+ </InternalItem>
20
+ );
21
+ };
22
+
23
+ const Target: React.FC<{ children?: React.ReactNode }> & {
24
+ Header: React.FC<{ children?: React.ReactNode }>;
25
+ } = ({ children }) => {
26
+ const { targetItems, setTargetItems } = useTransferContext();
27
+ const otherComponents: React.ReactNode[] = [];
28
+ const childrenTarget = React.Children.map(children, (child) => {
29
+ if (React.isValidElement(child) && child.type === Item) {
30
+ const { id, children } = child.props;
31
+ return { id, content: children };
32
+ }
33
+ otherComponents.push(child);
34
+ return null;
35
+ })?.filter((item) => item !== null);
36
+
37
+ useEffect(() => {
38
+ if (!childrenTarget) return;
39
+ setTargetItems({ items: childrenTarget, setOriginals: true });
40
+ }, []);
41
+
42
+ return (
43
+ <div className='it-transfer-wrapper target' data-testid='transfer-target'>
44
+ {otherComponents}
45
+ {targetItems.map(({ id, content }) => (
46
+ <TargetItem key={id} id={id}>
47
+ {content}
48
+ </TargetItem>
49
+ ))}
50
+ </div>
51
+ );
52
+ };
53
+
54
+ Target.Header = ({ children }: { children?: React.ReactNode }) => {
55
+ const { targetItems, targetCandidates, setTargetCandidates } = useTransferContext();
56
+
57
+ const getStatus = () => {
58
+ if (targetCandidates.length === 0) {
59
+ return { checked: false };
60
+ }
61
+ if (targetItems.every((item) => targetCandidates.includes(item.id))) {
62
+ return { checked: true };
63
+ }
64
+ return { checked: false, className: 'semi-checked' };
65
+ };
66
+
67
+ return (
68
+ <div className='transfer-header' data-testid='transfer-target-header'>
69
+ <SelectAllCheckbox
70
+ {...getStatus()}
71
+ onChange={(e) => {
72
+ if (e.target.checked) {
73
+ setTargetCandidates([...new Set(targetItems.map((item) => item.id))]);
74
+ } else {
75
+ setTargetCandidates([]);
76
+ }
77
+ }}
78
+ id='transfer-target-header'
79
+ description={children ? 'Target' : undefined}
80
+ >
81
+ {children ? children : 'Target'}
82
+ </SelectAllCheckbox>
83
+ </div>
84
+ );
85
+ };
86
+
87
+ export { Target };
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { BacktransferButton } from './BacktransferButton';
3
+ import { Item } from './Item';
4
+ import { ResetButton } from './ResetButton';
5
+ import { Source } from './Source';
6
+ import { Target } from './Target';
7
+ import { TransferButton } from './TransferButton';
8
+ import { TransferContextProvider, useTransfer } from './useTransferContext';
9
+
10
+ const Transfer = ({ children }: { children: React.ReactNode }) => {
11
+ return (
12
+ <TransferContextProvider>
13
+ <div data-testid='test-id-transfer'>{children}</div>
14
+ </TransferContextProvider>
15
+ );
16
+ };
17
+
18
+ Transfer.Source = Source;
19
+ Transfer.Target = Target;
20
+
21
+ Transfer.Item = Item;
22
+
23
+ Transfer.TransferButton = TransferButton;
24
+
25
+ Transfer.BacktransferButton = BacktransferButton;
26
+
27
+ Transfer.ResetButton = ResetButton;
28
+
29
+ Transfer.useTransfer = useTransfer;
30
+
31
+ export { Transfer };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { Icon } from '../Icon/Icon';
3
+ import { useTransferContext } from './useTransferContext';
4
+
5
+ const TransferButton = () => {
6
+ const { sourceCandidates, sourceItems, targetItems, setSourceItems, setTargetItems, setSourceCandidates } =
7
+ useTransferContext();
8
+ const handleTransfer: React.MouseEventHandler<HTMLAnchorElement> = (e) => {
9
+ e.preventDefault();
10
+ const newSourceItems = sourceItems.filter((item) => !sourceCandidates.includes(item.id));
11
+ const newTargetItems = targetItems.concat(sourceItems.filter((item) => sourceCandidates.includes(item.id)));
12
+ setSourceItems({ items: newSourceItems });
13
+ setTargetItems({ items: newTargetItems });
14
+ setSourceCandidates([]);
15
+ };
16
+ return (
17
+ <>
18
+ <a
19
+ data-testid='transfer-button'
20
+ className={`transfer ${sourceCandidates.length > 0 ? 'active' : ''}`}
21
+ href='#'
22
+ role='button'
23
+ aria-label='Sposta avanti'
24
+ onClick={handleTransfer}
25
+ >
26
+ <Icon icon='it-arrow-right' />
27
+ </a>
28
+ <span className='visually-hidden'>Etichetta per freccia destra</span>
29
+ </>
30
+ );
31
+ };
32
+
33
+ export { TransferButton };