@hipay/hipay-material-ui 1.0.0-beta.19 → 1.0.0-beta.20
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/HiChip/HiChip.js +12 -2
- package/HiDatePicker/HiDateRangePicker.js +1 -1
- package/HiDatePicker/HiDateRangeSelector.js +5 -4
- package/HiDatePicker/stylesheet.js +4 -0
- package/HiForm/HiAddressField.js +32 -49
- package/HiForm/HiInput.js +11 -6
- package/HiForm/HiUpload.js +280 -0
- package/HiForm/HiUploadField.js +456 -0
- package/HiForm/index.js +18 -0
- package/HiMap/HiMap.js +367 -0
- package/HiMap/HiMapExpand.js +217 -0
- package/HiMap/index.js +25 -0
- package/HiSelect/HiSelect.js +1 -1
- package/HiTable/BodyCellBuilder.js +1 -1
- package/HiTable/BodyCells/CellCountry.js +1 -1
- package/HiTable/BodyCells/CellImage.js +6 -6
- package/HiTable/BodyCells/CellLayout.js +1 -1
- package/HiTable/HeaderCell.js +5 -4
- package/HiTable/HiTableFooter.js +2 -1
- package/HiTopBar/HiTopBar.js +6 -4
- package/es/HiChip/HiChip.js +11 -2
- package/es/HiDatePicker/HiDateRangePicker.js +1 -1
- package/es/HiDatePicker/HiDateRangeSelector.js +5 -4
- package/es/HiDatePicker/stylesheet.js +4 -0
- package/es/HiForm/HiAddressField.js +30 -45
- package/es/HiForm/HiInput.js +10 -5
- package/es/HiForm/HiUpload.js +194 -0
- package/es/HiForm/HiUploadField.js +368 -0
- package/es/HiForm/index.js +2 -0
- package/es/HiMap/HiMap.js +285 -0
- package/es/HiMap/HiMapExpand.js +145 -0
- package/es/HiMap/index.js +2 -0
- package/es/HiSelect/HiSelect.js +1 -1
- package/es/HiTable/BodyCellBuilder.js +1 -1
- package/es/HiTable/BodyCells/CellCountry.js +1 -1
- package/es/HiTable/BodyCells/CellImage.js +6 -6
- package/es/HiTable/BodyCells/CellLayout.js +1 -1
- package/es/HiTable/HeaderCell.js +5 -3
- package/es/HiTable/HiTableFooter.js +2 -1
- package/es/HiTopBar/HiTopBar.js +6 -4
- package/es/styles/createHiMuiTheme.js +2 -0
- package/hmu/images/map_marker.svg +8 -0
- package/index.es.js +1 -1
- package/index.js +1 -1
- package/package.json +44 -42
- package/styles/createHiMuiTheme.js +2 -0
- package/umd/hipay-material-ui.development.js +58049 -14511
- package/umd/hipay-material-ui.production.min.js +5 -5
@@ -0,0 +1,368 @@
|
|
1
|
+
import _extends from 'babel-runtime/helpers/extends';
|
2
|
+
import React from 'react';
|
3
|
+
import PropTypes from 'prop-types';
|
4
|
+
import classNames from 'classnames';
|
5
|
+
import withStyles from '../styles/withStyles';
|
6
|
+
import HiIconBuilder from '../utils/HiIconBuilder';
|
7
|
+
|
8
|
+
export const styles = theme => ({
|
9
|
+
root: _extends({
|
10
|
+
position: 'relative'
|
11
|
+
}, theme.typography.body1, {
|
12
|
+
borderBottom: `1px solid ${theme.palette.input.bottomLine}`,
|
13
|
+
paddingLeft: 8,
|
14
|
+
backgroundColor: theme.palette.local.background2,
|
15
|
+
height: 40,
|
16
|
+
display: 'inline-flex',
|
17
|
+
justifyContent: 'flex-start',
|
18
|
+
'&$focused, &$dragOver': {
|
19
|
+
backgroundColor: theme.palette.global.background1
|
20
|
+
},
|
21
|
+
width: '100%',
|
22
|
+
// Ajout d'1px pour ne pas avoir de décalage en mode error avec le border top
|
23
|
+
'&:not($error)': {
|
24
|
+
marginTop: 1
|
25
|
+
}
|
26
|
+
}),
|
27
|
+
underline: {
|
28
|
+
'&:before': {
|
29
|
+
left: 0,
|
30
|
+
bottom: 0,
|
31
|
+
// Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
|
32
|
+
content: '""',
|
33
|
+
height: 1,
|
34
|
+
position: 'absolute',
|
35
|
+
right: 0,
|
36
|
+
transition: theme.transitions.create('background-color', {
|
37
|
+
duration: theme.transitions.duration.shorter,
|
38
|
+
easing: theme.transitions.easing.ease
|
39
|
+
}),
|
40
|
+
pointerEvents: 'none' // Transparent to the hover style.
|
41
|
+
},
|
42
|
+
'&:hover:not($disabled):before': {
|
43
|
+
backgroundColor: theme.palette.input.bottomLine,
|
44
|
+
height: 2
|
45
|
+
},
|
46
|
+
'&$disabled:before': {
|
47
|
+
background: 'transparent',
|
48
|
+
backgroundImage: `linear-gradient(to right, ${theme.palette.input.bottomLine} 33%, transparent 0%)`,
|
49
|
+
backgroundPosition: 'left top',
|
50
|
+
backgroundRepeat: 'repeat-x',
|
51
|
+
backgroundSize: '5px 1px'
|
52
|
+
}
|
53
|
+
},
|
54
|
+
inkbar: {
|
55
|
+
'&:not($disabled)': {
|
56
|
+
'&:not($error):after': {
|
57
|
+
backgroundColor: theme.palette.business.primary.normal,
|
58
|
+
left: 0,
|
59
|
+
bottom: 0,
|
60
|
+
// Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242
|
61
|
+
content: '""',
|
62
|
+
height: 1,
|
63
|
+
position: 'absolute',
|
64
|
+
right: 0,
|
65
|
+
transform: 'scaleX(0)',
|
66
|
+
transition: theme.transitions.create('transform', {
|
67
|
+
duration: theme.transitions.duration.shorter,
|
68
|
+
easing: theme.transitions.easing.easeOut
|
69
|
+
}),
|
70
|
+
pointerEvents: 'none' // Transparent to the hover style.
|
71
|
+
},
|
72
|
+
'&:hover:after': {
|
73
|
+
transform: 'scaleX(1)'
|
74
|
+
},
|
75
|
+
'&$dragOver:after': {
|
76
|
+
transform: 'scaleX(1)'
|
77
|
+
},
|
78
|
+
'&$focused:after': {
|
79
|
+
transform: 'scaleX(1)'
|
80
|
+
},
|
81
|
+
'&$error': {
|
82
|
+
borderBottom: `1px solid ${theme.palette.negative.normal}`
|
83
|
+
}
|
84
|
+
}
|
85
|
+
},
|
86
|
+
disabled: {
|
87
|
+
color: `${theme.palette.action.disabled}`,
|
88
|
+
'&:before': {
|
89
|
+
display: 'none'
|
90
|
+
}
|
91
|
+
},
|
92
|
+
focused: {
|
93
|
+
backgroundColor: theme.palette.background3
|
94
|
+
},
|
95
|
+
error: {},
|
96
|
+
label: _extends({}, theme.typography.body1, {
|
97
|
+
fontWeight: theme.typography.fontWeightRegular,
|
98
|
+
caretColor: theme.palette.business.primary.normal,
|
99
|
+
alignItems: 'center',
|
100
|
+
whiteSpace: 'nowrap',
|
101
|
+
overflow: 'hidden',
|
102
|
+
textOverflow: 'ellipsis',
|
103
|
+
padding: `${theme.spacing.unit - 2}px 0 ${theme.spacing.unit - 1}px`,
|
104
|
+
height: 39,
|
105
|
+
display: 'inline-flex',
|
106
|
+
width: '100%',
|
107
|
+
'&$empty': {
|
108
|
+
opacity: 0.42
|
109
|
+
}
|
110
|
+
}),
|
111
|
+
empty: {},
|
112
|
+
dragOver: {},
|
113
|
+
droppable: {},
|
114
|
+
endAdornment: {
|
115
|
+
display: 'flex',
|
116
|
+
alignItems: 'center'
|
117
|
+
},
|
118
|
+
icon: {
|
119
|
+
display: 'inline-flex',
|
120
|
+
alignItems: 'center',
|
121
|
+
right: 0,
|
122
|
+
padding: '8px',
|
123
|
+
color: `${theme.palette.text.icon}`,
|
124
|
+
transition: theme.transitions.create(['opacity', 'transform'], {
|
125
|
+
duration: theme.transitions.duration.shorter
|
126
|
+
}),
|
127
|
+
'&:hover': {
|
128
|
+
color: 'inherit'
|
129
|
+
}
|
130
|
+
}
|
131
|
+
});
|
132
|
+
|
133
|
+
class HiUploadField extends React.PureComponent {
|
134
|
+
|
135
|
+
constructor(props) {
|
136
|
+
super(props);
|
137
|
+
this.state = {
|
138
|
+
errorMessage: '',
|
139
|
+
dragOver: false,
|
140
|
+
droppable: false
|
141
|
+
};
|
142
|
+
this.uploadFieldRef;
|
143
|
+
this.handleChange = this.handleChange.bind(this);
|
144
|
+
this.handleClear = this.handleClear.bind(this);
|
145
|
+
this.handleSeeFile = this.handleSeeFile.bind(this);
|
146
|
+
this.handleDrop = this.handleDrop.bind(this);
|
147
|
+
this.handleDragEnter = this.handleDragEnter.bind(this);
|
148
|
+
this.handleDragLeave = this.handleDragLeave.bind(this);
|
149
|
+
}
|
150
|
+
|
151
|
+
// When component mounts, we add eventListeners to handle the file drag and drop
|
152
|
+
componentDidMount() {
|
153
|
+
this.uploadFieldRef.addEventListener('dragenter', this.handleDragEnter, false);
|
154
|
+
this.uploadFieldRef.addEventListener('dragleave', this.handleDragLeave, false);
|
155
|
+
this.uploadFieldRef.addEventListener('dragover', event => {
|
156
|
+
event.preventDefault();
|
157
|
+
}, false);
|
158
|
+
this.uploadFieldRef.addEventListener('drop', this.handleDrop, false);
|
159
|
+
}
|
160
|
+
|
161
|
+
componentWillUnmount() {
|
162
|
+
this.uploadFieldRef.removeEventListener('dragenter', this.handleDragEnter, false);
|
163
|
+
this.uploadFieldRef.removeEventListener('dragleave', this.handleDragLeave, false);
|
164
|
+
this.uploadFieldRef.removeEventListener('dragover', event => {
|
165
|
+
event.preventDefault();
|
166
|
+
}, false);
|
167
|
+
this.uploadFieldRef.removeEventListener('drop', this.handleDrop, false);
|
168
|
+
}
|
169
|
+
|
170
|
+
// Action when files are dropped on the field
|
171
|
+
handleDrop(event) {
|
172
|
+
if (event.target === this.uploadFieldRef) {
|
173
|
+
event.preventDefault();
|
174
|
+
event.stopPropagation();
|
175
|
+
if (this.state.droppable) {
|
176
|
+
const param = this.handleFile(event.dataTransfer.files);
|
177
|
+
this.setState({ dragOver: false });
|
178
|
+
this.props.onChange(param, this.props.index);
|
179
|
+
} else {
|
180
|
+
this.setState({
|
181
|
+
errorMessage: this.props.translations.errorDropMultiple,
|
182
|
+
error: false,
|
183
|
+
dragOver: false
|
184
|
+
});
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
// Action when files are dragged over the field.
|
190
|
+
handleDragEnter(event) {
|
191
|
+
event.preventDefault();
|
192
|
+
event.stopPropagation();
|
193
|
+
if (event.target === this.uploadFieldRef) {
|
194
|
+
if (event.dataTransfer.items.length !== 1) {
|
195
|
+
event.dataTransfer.dropEffect = 'none';
|
196
|
+
this.props.onChange({
|
197
|
+
errorMessage: this.props.translations.errorDragEnter,
|
198
|
+
error: true,
|
199
|
+
value: null
|
200
|
+
}, this.props.index);
|
201
|
+
this.setState({ dragOver: true });
|
202
|
+
} else {
|
203
|
+
this.setState({ droppable: true, dragOver: true });
|
204
|
+
}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
|
208
|
+
// Action when files are not dragged over the field anymore.
|
209
|
+
handleDragLeave(event) {
|
210
|
+
event.preventDefault();
|
211
|
+
event.stopPropagation();
|
212
|
+
if (event.target === this.uploadFieldRef && event.relatedTarget.parentElement !== this.uploadFieldRef) {
|
213
|
+
this.props.onChange({ errorMessage: '', error: false, value: null }, this.props.index);
|
214
|
+
this.setState({ droppable: false, dragOver: false });
|
215
|
+
}
|
216
|
+
}
|
217
|
+
|
218
|
+
handleChange(event) {
|
219
|
+
const param = this.handleFile(event.target.files);
|
220
|
+
this.props.onChange(param, this.props.index);
|
221
|
+
}
|
222
|
+
|
223
|
+
handleClear() {
|
224
|
+
this.props.onClear(this.props.index);
|
225
|
+
}
|
226
|
+
|
227
|
+
handleSeeFile() {
|
228
|
+
this.props.onSeeFile(this.props.value);
|
229
|
+
}
|
230
|
+
|
231
|
+
// Handles the file wether it is selected via the input or dropped on it.
|
232
|
+
handleFile(files) {
|
233
|
+
let error = false;
|
234
|
+
let errorMessage = '';
|
235
|
+
let file = null;
|
236
|
+
if (files.length === 1) {
|
237
|
+
file = files[0];
|
238
|
+
errorMessage = '';
|
239
|
+
if (file.size > this.props.maxSize) {
|
240
|
+
errorMessage += this.props.translations.errorSize.replace('maxSize', this.props.maxSize / 1000000);
|
241
|
+
error = true;
|
242
|
+
}
|
243
|
+
if (this.props.acceptedTypes.length !== 0 && this.props.acceptedTypes.indexOf(file.type) === -1) {
|
244
|
+
errorMessage += this.props.translations.errorType;
|
245
|
+
error = true;
|
246
|
+
}
|
247
|
+
} else {
|
248
|
+
errorMessage = this.props.translations.errorDropMultiple;
|
249
|
+
}
|
250
|
+
return { errorMessage, error, value: file };
|
251
|
+
}
|
252
|
+
|
253
|
+
render() {
|
254
|
+
const { placeholder, classes, disabled, focused, value, error } = this.props;
|
255
|
+
|
256
|
+
const { dragOver, errorMessage, droppable } = this.state;
|
257
|
+
|
258
|
+
// On utilise classNames pour variabiliser les styles et merger les classes appliquées
|
259
|
+
const rootClass = classNames(classes.root, classes.inkbar, classes.underline, {
|
260
|
+
[classes.disabled]: disabled,
|
261
|
+
[classes.focused]: focused,
|
262
|
+
[classes.error]: error && !focused,
|
263
|
+
[classes.dragOver]: dragOver,
|
264
|
+
[classes.droppable]: droppable
|
265
|
+
});
|
266
|
+
|
267
|
+
return React.createElement(
|
268
|
+
'div',
|
269
|
+
{ className: rootClass },
|
270
|
+
React.createElement(
|
271
|
+
'label',
|
272
|
+
{
|
273
|
+
className: classNames(classes.label, { [classes.empty]: value === null }),
|
274
|
+
ref: label => this.uploadFieldRef = label
|
275
|
+
},
|
276
|
+
value ? value.name : error && errorMessage || placeholder,
|
277
|
+
React.createElement('input', { type: 'file', hidden: true, onChange: this.handleChange })
|
278
|
+
),
|
279
|
+
value === null || React.createElement(
|
280
|
+
'div',
|
281
|
+
{ className: classes.endAdornment },
|
282
|
+
React.createElement(HiIconBuilder, {
|
283
|
+
icon: 'eye',
|
284
|
+
size: 36,
|
285
|
+
className: classes.icon,
|
286
|
+
onClick: this.handleSeeFile
|
287
|
+
}),
|
288
|
+
React.createElement(HiIconBuilder, {
|
289
|
+
icon: 'delete',
|
290
|
+
size: 36,
|
291
|
+
className: classes.icon,
|
292
|
+
onClick: this.handleClear
|
293
|
+
})
|
294
|
+
)
|
295
|
+
);
|
296
|
+
}
|
297
|
+
}
|
298
|
+
|
299
|
+
HiUploadField.defaultProps = {
|
300
|
+
placeholder: 'Choose a file',
|
301
|
+
disabled: false,
|
302
|
+
focused: false,
|
303
|
+
acceptedTypes: [],
|
304
|
+
maxSize: 10000000,
|
305
|
+
error: false,
|
306
|
+
value: null,
|
307
|
+
translations: {
|
308
|
+
errorSize: "Votre fichier est trop lourd. Nous acceptons jusqu'à maxSizeMo",
|
309
|
+
errorDropMultiple: 'Veuillez insérer un et un seul fichier',
|
310
|
+
errorType: "Ce type de fichier n'est pas accepté",
|
311
|
+
errorDragEnter: 'Contenu non correct'
|
312
|
+
}
|
313
|
+
};
|
314
|
+
HiUploadField.propTypes = process.env.NODE_ENV !== "production" ? {
|
315
|
+
/**
|
316
|
+
* Defines what kind of file types the input accepts. If empty, no restrictions about the file type.
|
317
|
+
*/
|
318
|
+
acceptedTypes: PropTypes.array,
|
319
|
+
/**
|
320
|
+
* Useful to extend the style applied to components.
|
321
|
+
*/
|
322
|
+
classes: PropTypes.object,
|
323
|
+
/**
|
324
|
+
* Is the field disabled.
|
325
|
+
*/
|
326
|
+
disabled: PropTypes.bool,
|
327
|
+
/**
|
328
|
+
* Is there an error with the file selected.
|
329
|
+
*/
|
330
|
+
error: PropTypes.bool,
|
331
|
+
/**
|
332
|
+
* Is the field focused.
|
333
|
+
*/
|
334
|
+
focused: PropTypes.bool,
|
335
|
+
/**
|
336
|
+
* The index of the input.
|
337
|
+
*/
|
338
|
+
index: PropTypes.number,
|
339
|
+
/**
|
340
|
+
* Defines what size the file must not exceed (in bytes).
|
341
|
+
*/
|
342
|
+
maxSize: PropTypes.number,
|
343
|
+
/**
|
344
|
+
* The change handler.
|
345
|
+
*/
|
346
|
+
onChange: PropTypes.func,
|
347
|
+
/**
|
348
|
+
* The handler to clear the field.
|
349
|
+
*/
|
350
|
+
onClear: PropTypes.func,
|
351
|
+
/**
|
352
|
+
* The handler to see the file.
|
353
|
+
*/
|
354
|
+
onSeeFile: PropTypes.func,
|
355
|
+
/**
|
356
|
+
* The placeholder for the field.
|
357
|
+
*/
|
358
|
+
placeholder: PropTypes.string,
|
359
|
+
/**
|
360
|
+
* The translations of the error messages.
|
361
|
+
*/
|
362
|
+
translations: PropTypes.object,
|
363
|
+
/**
|
364
|
+
* The file value for the field.
|
365
|
+
*/
|
366
|
+
value: PropTypes.object
|
367
|
+
} : {};
|
368
|
+
export default withStyles(styles, { name: 'HmuiHiUploadField' })(HiUploadField);
|
package/es/HiForm/index.js
CHANGED
@@ -5,5 +5,7 @@ export { default as HiInput } from './HiInput';
|
|
5
5
|
export { default as HiPasswordField } from './HiPasswordField';
|
6
6
|
export { default as HiTextField } from './HiTextField';
|
7
7
|
export { default as HiSearchField } from './HiSearchField';
|
8
|
+
export { default as HiUpload } from './HiUpload';
|
9
|
+
export { default as HiUploadField } from './HiUploadField';
|
8
10
|
export { default as HiSlider } from './HiSlider';
|
9
11
|
export { default as HiAddressField } from './HiAddressField';
|
@@ -0,0 +1,285 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { withStyles } from '../styles';
|
4
|
+
import HiButton from '../HiButton';
|
5
|
+
import HiIconBuilder from '../utils/HiIconBuilder';
|
6
|
+
import HiLoader from '../HiLoader';
|
7
|
+
|
8
|
+
// The original CSS can be found here : https://unpkg.com/leaflet@1.3.1/dist/leaflet.css
|
9
|
+
export const styles = theme => ({
|
10
|
+
map: {
|
11
|
+
height: '100%',
|
12
|
+
overflow: 'hidden',
|
13
|
+
'& .leaflet-pane, & .leaflet-tile, & .leaflet-marker-icon, & .leaflet-marker-shadow, & .leaflet-tile-container, & .leaflet-pane > svg, & .leaflet-pane > canvas, & .leaflet-zoom-box, & .leaflet-image-layer, & .leaflet-layer': {
|
14
|
+
position: 'absolute',
|
15
|
+
left: 0,
|
16
|
+
top: 0
|
17
|
+
},
|
18
|
+
'& .leaflet-container': {
|
19
|
+
overflow: 'hidden',
|
20
|
+
height: '100%'
|
21
|
+
},
|
22
|
+
'& .leaflet-tile, & .leaflet-marker-icon, & .leaflet-marker-shadow': {
|
23
|
+
'-webkit-user-select': 'none',
|
24
|
+
'-moz-user-select': 'none',
|
25
|
+
userSelect: 'none',
|
26
|
+
'-webkit-user-drag': 'none'
|
27
|
+
},
|
28
|
+
'& .leaflet-control': {
|
29
|
+
display: 'none'
|
30
|
+
},
|
31
|
+
'& .map_marker': {
|
32
|
+
fill: theme.palette.business.primary.normal
|
33
|
+
}
|
34
|
+
},
|
35
|
+
controlButtons: {
|
36
|
+
position: 'absolute',
|
37
|
+
bottom: 16,
|
38
|
+
right: 16
|
39
|
+
},
|
40
|
+
centerIcon: {
|
41
|
+
fontSize: 14
|
42
|
+
},
|
43
|
+
centerButtonContainer: {
|
44
|
+
backgroundColor: theme.palette.business.primary.contrast,
|
45
|
+
borderRadius: 3,
|
46
|
+
padding: 3,
|
47
|
+
boxShadow: '1px 1px 5px rgba(0, 0, 0, .16)',
|
48
|
+
marginBottom: 4,
|
49
|
+
height: 32,
|
50
|
+
minHeight: 32,
|
51
|
+
width: 32,
|
52
|
+
minWidth: 32
|
53
|
+
},
|
54
|
+
centerButton: {
|
55
|
+
color: theme.palette.neutral.normal,
|
56
|
+
padding: '1px !important',
|
57
|
+
height: 26,
|
58
|
+
minHeight: 26,
|
59
|
+
width: 26,
|
60
|
+
minWidth: 26
|
61
|
+
},
|
62
|
+
zoomButtons: {
|
63
|
+
backgroundColor: theme.palette.global.background1,
|
64
|
+
borderRadius: 3,
|
65
|
+
padding: 3,
|
66
|
+
fontFamily: theme.typography.fontFamily,
|
67
|
+
boxShadow: '1px 1px 5px rgba(0, 0, 0, .16)',
|
68
|
+
color: theme.palette.neutral.normal,
|
69
|
+
'&>button:first-child': {
|
70
|
+
borderBottom: `1px solid ${theme.palette.neutral.normal}`
|
71
|
+
}
|
72
|
+
},
|
73
|
+
zoomButton: {
|
74
|
+
paddingTop: '0px !important',
|
75
|
+
paddingBottom: 0,
|
76
|
+
paddingRight: 6,
|
77
|
+
paddingLeft: 6,
|
78
|
+
minWidth: 0,
|
79
|
+
minHeight: 0,
|
80
|
+
borderRadius: 0,
|
81
|
+
display: 'block',
|
82
|
+
fontSize: 24,
|
83
|
+
fontWeight: 'bold',
|
84
|
+
lineHeight: '26px',
|
85
|
+
'&>span': {
|
86
|
+
width: 14
|
87
|
+
}
|
88
|
+
}
|
89
|
+
});
|
90
|
+
|
91
|
+
let L, Map, TileLayer, Marker, Popup;
|
92
|
+
|
93
|
+
var _ref = React.createElement(TileLayer, { url: 'https://{s}.tile.openstreetmap.se/hydda/full/{z}/{x}/{y}.png' });
|
94
|
+
|
95
|
+
var _ref2 = React.createElement(HiLoader, { loading: true });
|
96
|
+
|
97
|
+
class HiMap extends React.PureComponent {
|
98
|
+
|
99
|
+
constructor(props) {
|
100
|
+
super(props);
|
101
|
+
|
102
|
+
this.state = {
|
103
|
+
lat: 0,
|
104
|
+
lng: 0,
|
105
|
+
notFound: false,
|
106
|
+
loaded: false,
|
107
|
+
zoom: 16
|
108
|
+
};
|
109
|
+
|
110
|
+
this.xhr = null;
|
111
|
+
this.handleClickZoomIn = this.handleClickZoomIn.bind(this);
|
112
|
+
this.handleScrollZoom = this.handleScrollZoom.bind(this);
|
113
|
+
this.handleClickZoomOut = this.handleClickZoomOut.bind(this);
|
114
|
+
this.handleCenter = this.handleCenter.bind(this);
|
115
|
+
}
|
116
|
+
|
117
|
+
// Loads the libraries once the component mounted to avoid error caused by server-cli rendering.
|
118
|
+
componentDidMount() {
|
119
|
+
this.findCoords();
|
120
|
+
L = require('leaflet');
|
121
|
+
Map = require('react-leaflet').Map;
|
122
|
+
Popup = require('react-leaflet').Popup;
|
123
|
+
Marker = require('react-leaflet').Marker;
|
124
|
+
TileLayer = require('react-leaflet').TileLayer;
|
125
|
+
}
|
126
|
+
|
127
|
+
// Avoids a warning when cleanup() is called at the end of the test by stopping the async call.
|
128
|
+
componentWillUnmount() {
|
129
|
+
this.xhr.abort();
|
130
|
+
}
|
131
|
+
|
132
|
+
handleScrollZoom(event) {
|
133
|
+
this.setState({ zoom: event.zoom });
|
134
|
+
}
|
135
|
+
|
136
|
+
handleClickZoomIn() {
|
137
|
+
this.setState(prevState => {
|
138
|
+
return { zoom: prevState.zoom + 1 };
|
139
|
+
});
|
140
|
+
}
|
141
|
+
|
142
|
+
handleClickZoomOut() {
|
143
|
+
this.setState(prevState => {
|
144
|
+
return { zoom: prevState.zoom - 1 };
|
145
|
+
});
|
146
|
+
}
|
147
|
+
|
148
|
+
handleCenter() {
|
149
|
+
// trick to center the map.
|
150
|
+
this.setState(prevState => {
|
151
|
+
return { lat: prevState.lat + 0.0000000001 };
|
152
|
+
});
|
153
|
+
}
|
154
|
+
|
155
|
+
// Call to the geocoding API.
|
156
|
+
findCoords() {
|
157
|
+
this.xhr = new XMLHttpRequest();
|
158
|
+
this.xhr.onreadystatechange = () => {
|
159
|
+
if (this.xhr.readyState === XMLHttpRequest.DONE && this.xhr.status === 200) {
|
160
|
+
const response = JSON.parse(this.xhr.responseText);
|
161
|
+
if (response.length === 0) {
|
162
|
+
this.setState({ notFound: true });
|
163
|
+
this.props.onAddressNotFound();
|
164
|
+
} else {
|
165
|
+
this.setState({
|
166
|
+
lat: parseFloat(response[0].lat),
|
167
|
+
lng: parseFloat(response[0].lon),
|
168
|
+
notFound: false,
|
169
|
+
loaded: true
|
170
|
+
});
|
171
|
+
}
|
172
|
+
}
|
173
|
+
};
|
174
|
+
this.xhr.open('GET', `https://nominatim.openstreetmap.org/search?q=${this.props.address}&format=jsonv2&limit=5&bounded=1&dedupe=1&namedetails=1`, true);
|
175
|
+
this.xhr.setRequestHeader('Content-type', 'application/json');
|
176
|
+
this.xhr.send();
|
177
|
+
}
|
178
|
+
|
179
|
+
render() {
|
180
|
+
const { zoom, lng, lat, notFound, loaded } = this.state;
|
181
|
+
|
182
|
+
const { translations, classes } = this.props;
|
183
|
+
|
184
|
+
const position = [lat, lng];
|
185
|
+
|
186
|
+
let element;
|
187
|
+
|
188
|
+
let myIcon;
|
189
|
+
if (notFound) {
|
190
|
+
element = translations.notFound;
|
191
|
+
} else if (loaded) {
|
192
|
+
myIcon = L.divIcon({
|
193
|
+
html: '<svg x="0px" y="0px" viewBox="0 0 365 560" enable-background="new 0 0 365 560" xml:space="preserve">\n' + '<path class="map_marker" d="M182.9,551.7c0,0.1,0.2,0.3,0.2,0.3S358.3,283,358.3,194.6c0-130.1-88.8-186.7-175.4-186.9 C96.3,7.9,7.5,64.5,7.5,194.6c0,88.4,175.3,357.4,175.3,357.4S182.9,551.7,182.9,551.7z M122.2,187.2c0-33.6,27.2-60.8,60.8-60.8 c33.6,0,60.8,27.2,60.8,60.8S216.5,248,182.9,248C149.4,248,122.2,220.8,122.2,187.2z"/>\n' + '</svg>',
|
194
|
+
iconSize: [24, 36],
|
195
|
+
iconAnchor: [11, 36]
|
196
|
+
});
|
197
|
+
element = React.createElement(
|
198
|
+
Map,
|
199
|
+
{
|
200
|
+
zoom: zoom,
|
201
|
+
center: position,
|
202
|
+
className: classes.map,
|
203
|
+
onViewportChange: this.handleScrollZoom
|
204
|
+
},
|
205
|
+
_ref,
|
206
|
+
React.createElement(Marker, { position: position, icon: myIcon }),
|
207
|
+
React.createElement(
|
208
|
+
'div',
|
209
|
+
{ className: classes.controlButtons },
|
210
|
+
React.createElement(
|
211
|
+
'div',
|
212
|
+
{ className: classes.centerButtonContainer },
|
213
|
+
React.createElement(
|
214
|
+
HiButton,
|
215
|
+
{ className: classes.centerButton, onClick: this.handleCenter },
|
216
|
+
React.createElement(HiIconBuilder, {
|
217
|
+
className: classes.centerIcon,
|
218
|
+
icon: 'crosshairs_gps',
|
219
|
+
size: 24
|
220
|
+
})
|
221
|
+
)
|
222
|
+
),
|
223
|
+
React.createElement(
|
224
|
+
'div',
|
225
|
+
{ className: classes.zoomButtons },
|
226
|
+
React.createElement(
|
227
|
+
HiButton,
|
228
|
+
{
|
229
|
+
onClick: this.handleClickZoomIn,
|
230
|
+
className: classes.zoomButton
|
231
|
+
},
|
232
|
+
'+'
|
233
|
+
),
|
234
|
+
React.createElement(
|
235
|
+
HiButton,
|
236
|
+
{
|
237
|
+
onClick: this.handleClickZoomOut,
|
238
|
+
className: classes.zoomButton
|
239
|
+
},
|
240
|
+
'-'
|
241
|
+
)
|
242
|
+
)
|
243
|
+
)
|
244
|
+
);
|
245
|
+
} else {
|
246
|
+
element = React.createElement(
|
247
|
+
'div',
|
248
|
+
{ style: { top: '50%', left: '50%', position: 'absolute' } },
|
249
|
+
_ref2
|
250
|
+
);
|
251
|
+
}
|
252
|
+
|
253
|
+
return React.createElement(
|
254
|
+
'div',
|
255
|
+
{ style: { height: '352px', width: '100%', position: 'relative' } },
|
256
|
+
element
|
257
|
+
);
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
HiMap.defaultProps = {
|
262
|
+
translations: {
|
263
|
+
notFound: 'Address not found'
|
264
|
+
}
|
265
|
+
};
|
266
|
+
HiMap.propTypes = process.env.NODE_ENV !== "production" ? {
|
267
|
+
/**
|
268
|
+
* The address to see in the Map component.
|
269
|
+
*/
|
270
|
+
address: PropTypes.string.isRequired,
|
271
|
+
/**
|
272
|
+
* Useful to extend the style applied to components.
|
273
|
+
*/
|
274
|
+
classes: PropTypes.object.isRequired,
|
275
|
+
/**
|
276
|
+
* Function to tell the parent composant that the address was not found by the API.
|
277
|
+
*/
|
278
|
+
onAddressNotFound: PropTypes.func,
|
279
|
+
/**
|
280
|
+
* Traductions
|
281
|
+
*/
|
282
|
+
translations: PropTypes.object
|
283
|
+
} : {};
|
284
|
+
|
285
|
+
export default withStyles(styles, { name: 'HmuiHiMap' })(HiMap);
|