@luomus/laji-form 15.1.41 → 15.1.42
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/dist/laji-form.js +1 -1
- package/dist/styles.css +33 -0
- package/lib/components/components.d.ts +13 -1
- package/lib/components/components.js +53 -17
- package/lib/components/fields/SingleActiveArrayField.js +23 -13
- package/lib/components/templates/FieldTemplate.js +1 -1
- package/lib/components/templates/TitleField.js +12 -2
- package/lib/components/widgets/AutosuggestWidget.js +2 -8
- package/lib/components/widgets/CheckboxWidget.d.ts +3 -3
- package/lib/components/widgets/CheckboxWidget.js +30 -32
- package/lib/components/widgets/TextareaWidget.d.ts +0 -1
- package/lib/components/widgets/TextareaWidget.js +3 -21
- package/lib/utils.js +18 -8
- package/package.json +1 -1
package/dist/styles.css
CHANGED
|
@@ -2222,10 +2222,15 @@ body .laji-form {
|
|
|
2222
2222
|
font-weight: bold;
|
|
2223
2223
|
display: inline-block;
|
|
2224
2224
|
text-align: center;
|
|
2225
|
+
cursor: pointer;
|
|
2225
2226
|
}
|
|
2226
2227
|
.laji-form .laji-form-help-glyph:before {
|
|
2227
2228
|
content: "?";
|
|
2228
2229
|
}
|
|
2230
|
+
.laji-form .laji-form-help-glyph:focus {
|
|
2231
|
+
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,1);
|
|
2232
|
+
box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,1);
|
|
2233
|
+
}
|
|
2229
2234
|
|
|
2230
2235
|
.laji-form .laji-form-map-container {
|
|
2231
2236
|
z-index: 1;
|
|
@@ -2848,6 +2853,11 @@ body .laji-form {
|
|
|
2848
2853
|
.laji-form .laji-form-error-list .btn-link:focus {
|
|
2849
2854
|
outline: none;
|
|
2850
2855
|
}
|
|
2856
|
+
.laji-form .btn-group.laji-form-checkbox-widget-tab-target:focus {
|
|
2857
|
+
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,1);
|
|
2858
|
+
box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,1);
|
|
2859
|
+
outline: none;
|
|
2860
|
+
}
|
|
2851
2861
|
.laji-form-error-list .laji-form-error-list-expand {
|
|
2852
2862
|
font-size: 12px;
|
|
2853
2863
|
}
|
|
@@ -2869,6 +2879,22 @@ body .laji-form {
|
|
|
2869
2879
|
display: table;
|
|
2870
2880
|
}
|
|
2871
2881
|
|
|
2882
|
+
.laji-form-checkbox-selected-value-glyph, .laji-form-checkbox-unselected-value-glyph {
|
|
2883
|
+
pointer-events: none;
|
|
2884
|
+
}
|
|
2885
|
+
.laji-form-checkbox-selected-value-glyph:before, .laji-form-checkbox-unselected-value-glyph:before {
|
|
2886
|
+
content: "•";
|
|
2887
|
+
margin-right: 6px;
|
|
2888
|
+
height: 0;
|
|
2889
|
+
font-weight: 900;
|
|
2890
|
+
color: #9e9e9e;
|
|
2891
|
+
font-size: 18px;
|
|
2892
|
+
vertical-align: -2px;
|
|
2893
|
+
}
|
|
2894
|
+
.laji-form-checkbox-unselected-value-glyph:before {
|
|
2895
|
+
visibility: hidden;
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2872
2898
|
.laji-form.map-dialog .modal-content, .laji-form.map-dialog .modal-body {
|
|
2873
2899
|
width: auto;
|
|
2874
2900
|
height: inherit;
|
|
@@ -3869,4 +3895,11 @@ body .laji-form {
|
|
|
3869
3895
|
height: 25px;
|
|
3870
3896
|
}
|
|
3871
3897
|
|
|
3898
|
+
.laji-form-label-help-margin {
|
|
3899
|
+
padding-right: 25px;
|
|
3900
|
+
}
|
|
3901
|
+
|
|
3902
|
+
.laji-form-label-help-margin-clear {
|
|
3903
|
+
margin-left: -20px !important;
|
|
3904
|
+
}
|
|
3872
3905
|
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
export function AddButton({ onClick }: {
|
|
2
2
|
onClick: any;
|
|
3
3
|
}): JSX.Element;
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* @param standalone If provided, the help icon will handle **accessibility** itself.
|
|
6
|
+
* If not provided, the parent element must take care of showing the tooltip.
|
|
7
|
+
*
|
|
8
|
+
* **accessibility** means that it handles showing the tooltip on focus & hover, and
|
|
9
|
+
*/
|
|
10
|
+
export function Help({ help, id, focusable, onFocus, onBlur, className, onClick, standalone }: {
|
|
5
11
|
help: any;
|
|
6
12
|
id: any;
|
|
13
|
+
focusable?: boolean | undefined;
|
|
14
|
+
onFocus: any;
|
|
15
|
+
onBlur: any;
|
|
16
|
+
className: any;
|
|
17
|
+
onClick: any;
|
|
18
|
+
standalone: any;
|
|
7
19
|
}): JSX.Element;
|
|
8
20
|
export function Label({ label, children, id, required, registry, uiSchema }: {
|
|
9
21
|
label: any;
|
|
@@ -236,8 +236,9 @@ class Affix extends React.Component {
|
|
|
236
236
|
window.removeEventListener("resize", this.onResize);
|
|
237
237
|
}
|
|
238
238
|
componentDidUpdate(prevProps, prevState) {
|
|
239
|
-
if (!this.props.onAffixChange || !prevState || !this.state)
|
|
239
|
+
if (!this.props.onAffixChange || !prevState || !this.state) {
|
|
240
240
|
return;
|
|
241
|
+
}
|
|
241
242
|
if (prevState.affixState !== AFFIXED && this.state.affixState === AFFIXED) {
|
|
242
243
|
this.props.onAffixChange(true);
|
|
243
244
|
}
|
|
@@ -355,15 +356,32 @@ class Stretch extends React.Component {
|
|
|
355
356
|
}
|
|
356
357
|
}
|
|
357
358
|
exports.Stretch = Stretch;
|
|
358
|
-
|
|
359
|
-
|
|
359
|
+
/**
|
|
360
|
+
* @param standalone If provided, the help icon will handle **accessibility** itself.
|
|
361
|
+
* If not provided, the parent element must take care of showing the tooltip.
|
|
362
|
+
*
|
|
363
|
+
* **accessibility** means that it handles showing the tooltip on focus & hover, and
|
|
364
|
+
*/
|
|
365
|
+
function Help({ help, id, focusable = false, onFocus, onBlur, className, onClick, standalone }) {
|
|
360
366
|
const { Tooltip } = React.useContext(ReactContext_1.default).theme;
|
|
361
|
-
|
|
362
|
-
|
|
367
|
+
const [focused, setFocused] = React.useState(undefined);
|
|
368
|
+
const onHelpFocus = React.useCallback(() => {
|
|
369
|
+
setFocused(true);
|
|
370
|
+
}, []);
|
|
371
|
+
const onHelpBlur = React.useCallback(() => {
|
|
372
|
+
setFocused(false);
|
|
373
|
+
}, []);
|
|
374
|
+
const helpGlyph = React.createElement("span", { className: utils_1.classNames("laji-form-help-glyph", "text-muted", className), tabIndex: focusable ? 0 : -1, onFocus: standalone ? onHelpFocus : onFocus, onBlur: standalone ? onHelpBlur : onBlur, onClick: onClick });
|
|
375
|
+
const tooltip = React.createElement(Tooltip, { id: id },
|
|
376
|
+
React.createElement("span", { dangerouslySetInnerHTML: { __html: help } }));
|
|
377
|
+
return help ? (React.createElement(OverlayTrigger, { placement: "right", overlay: tooltip, show: standalone && focused || undefined },
|
|
378
|
+
React.createElement(React.Fragment, null,
|
|
379
|
+
helpGlyph,
|
|
380
|
+
standalone && React.createElement("div", { id: `${id}--help`, style: { display: "none" } }, help)))) : helpGlyph;
|
|
363
381
|
}
|
|
364
382
|
exports.Help = Help;
|
|
365
383
|
function Label({ label, children, id, required, registry = {}, uiSchema = {} }) {
|
|
366
|
-
const { "ui:help": help, "ui:helpHoverable": helpHoverable, "ui:helpPlacement": helpPlacement } = uiSchema;
|
|
384
|
+
const { "ui:help": help, "ui:helpHoverable": helpHoverable, "ui:helpPlacement": helpPlacement, labelComponent } = uiSchema;
|
|
367
385
|
const showHelp = label && help;
|
|
368
386
|
const { Tooltip } = React.useContext(ReactContext_1.default).theme;
|
|
369
387
|
const tooltipElem = (React.createElement(Tooltip, { id: id + "-tooltip" }, help ? (React.createElement("span", null,
|
|
@@ -371,12 +389,25 @@ function Label({ label, children, id, required, registry = {}, uiSchema = {} })
|
|
|
371
389
|
React.createElement("br", null),
|
|
372
390
|
React.createElement("span", { dangerouslySetInnerHTML: { __html: help } }))) : label));
|
|
373
391
|
const requiredHtml = required ? "<span class='text-danger'>*</span>" : "";
|
|
374
|
-
const
|
|
392
|
+
const [focused, setFocused] = React.useState(undefined);
|
|
393
|
+
const onHelpFocus = React.useCallback(() => {
|
|
394
|
+
setFocused(true);
|
|
395
|
+
}, []);
|
|
396
|
+
const onHelpBlur = React.useCallback(() => {
|
|
397
|
+
setFocused(false);
|
|
398
|
+
}, []);
|
|
399
|
+
const onHelpClick = React.useCallback((e) => {
|
|
400
|
+
e.preventDefault();
|
|
401
|
+
}, []);
|
|
402
|
+
const LabelComponent = labelComponent || "label";
|
|
403
|
+
const labelElem = (React.createElement(LabelComponent, { htmlFor: id, "aria-describedby": `${id}--help` },
|
|
375
404
|
React.createElement("div", null,
|
|
376
405
|
React.createElement("strong", { dangerouslySetInnerHTML: { __html: label + requiredHtml } }),
|
|
377
|
-
showHelp ? React.createElement(Help,
|
|
406
|
+
showHelp ? React.createElement(Help, { focusable: true, onFocus: onHelpFocus, onBlur: onHelpBlur, onClick: onHelpClick }) : null),
|
|
378
407
|
children));
|
|
379
|
-
return
|
|
408
|
+
return help ? React.createElement(React.Fragment, null,
|
|
409
|
+
React.createElement(OverlayTrigger, { placement: helpPlacement || "right", overlay: tooltipElem, hoverable: helpHoverable, formContext: registry.formContext, show: focused || undefined }, labelElem),
|
|
410
|
+
React.createElement("div", { id: `${id}--help`, style: { display: "none" } }, help)) : labelElem;
|
|
380
411
|
}
|
|
381
412
|
exports.Label = Label;
|
|
382
413
|
class ErrorPanel extends React.Component {
|
|
@@ -479,11 +510,16 @@ class OverlayTrigger extends React.Component {
|
|
|
479
510
|
if (this.overlayTimeout) {
|
|
480
511
|
clearTimeout(this.overlayTimeout);
|
|
481
512
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
this.
|
|
485
|
-
|
|
486
|
-
|
|
513
|
+
if (this.props.hoverable) {
|
|
514
|
+
this.overlayTimeout = this.props.formContext.setTimeout(() => {
|
|
515
|
+
if (!this.popoverMouseIn && !this.overlayTriggerMouseIn) {
|
|
516
|
+
this.setState({ hoveringElem: false });
|
|
517
|
+
}
|
|
518
|
+
}, 200);
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
this.setState({ hoveringElem: false });
|
|
522
|
+
}
|
|
487
523
|
};
|
|
488
524
|
this.overlayMouseOver = () => {
|
|
489
525
|
this.setState({ hoveringOverlay: true });
|
|
@@ -502,10 +538,10 @@ class OverlayTrigger extends React.Component {
|
|
|
502
538
|
const _a = this.props, { children, overlay, contextId } = _a, //eslint-disable-line @typescript-eslint/no-unused-vars
|
|
503
539
|
props = __rest(_a, ["children", "overlay", "contextId"]);
|
|
504
540
|
const { OverlayTrigger } = this.context.theme;
|
|
505
|
-
if (!this.props.hoverable)
|
|
506
|
-
return (React.createElement(OverlayTrigger, Object.assign({}, props, { overlay: overlay }), children));
|
|
507
541
|
let _overlay = React.cloneElement(overlay, { onMouseOver: this.overlayMouseOver, onMouseOut: this.overlayMouseOut });
|
|
508
|
-
const show = this.
|
|
542
|
+
const show = this.props.show !== undefined
|
|
543
|
+
? this.props.show
|
|
544
|
+
: this.state.hoveringElem || this.props.hoverable && this.state.hoveringOverlay;
|
|
509
545
|
return (React.createElement("div", { onMouseOver: this.overlayTriggerMouseOver, onMouseOut: this.overlayTriggerMouseOut },
|
|
510
546
|
React.createElement(OverlayTrigger, Object.assign({}, props, { delay: 1, trigger: [], placement: this.props.placement || "top", overlay: _overlay, show: show }), children)));
|
|
511
547
|
}
|
|
@@ -68,14 +68,7 @@ let SingleActiveArrayField = class SingleActiveArrayField extends React.Componen
|
|
|
68
68
|
});
|
|
69
69
|
};
|
|
70
70
|
this.onHeaderAffixChange = (elem, value) => {
|
|
71
|
-
|
|
72
|
-
this.setState({ scrollHeightFixed: elem.scrollHeight }, () => {
|
|
73
|
-
this.getLocalFormContext().utils.syncScroll(!!"force");
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
this.setState({ scrollHeightFixed: 0 });
|
|
78
|
-
}
|
|
71
|
+
this.setState({ scrollHeightFixed: value ? elem.scrollHeight : 0 });
|
|
79
72
|
};
|
|
80
73
|
this.getLocalFormContext = () => {
|
|
81
74
|
if (this.localContextKey === this.state.scrollHeightFixed) {
|
|
@@ -940,6 +933,15 @@ class AccordionHeader extends React.Component {
|
|
|
940
933
|
};
|
|
941
934
|
});
|
|
942
935
|
};
|
|
936
|
+
this.onHelpFocus = () => {
|
|
937
|
+
this.setState({ focused: true });
|
|
938
|
+
};
|
|
939
|
+
this.onHelpBlur = () => {
|
|
940
|
+
this.setState({ focused: false });
|
|
941
|
+
};
|
|
942
|
+
this.onHelpClick = (e) => {
|
|
943
|
+
e.preventDefault();
|
|
944
|
+
};
|
|
943
945
|
}
|
|
944
946
|
render() {
|
|
945
947
|
const { that, idx } = this.props;
|
|
@@ -947,7 +949,10 @@ class AccordionHeader extends React.Component {
|
|
|
947
949
|
const popupData = that.state.popups[idx];
|
|
948
950
|
const { uiSchema } = that.props;
|
|
949
951
|
const hasHelp = uiSchema && uiSchema["ui:help"];
|
|
950
|
-
const
|
|
952
|
+
const spanProps = hasHelp
|
|
953
|
+
? { "aria-describedby": `${that.props.idSchema.$id}_${idx}--help` }
|
|
954
|
+
: {};
|
|
955
|
+
const headerText = (React.createElement("span", Object.assign({}, spanProps),
|
|
951
956
|
title,
|
|
952
957
|
this.getFormatters().map((formatter, i) => {
|
|
953
958
|
const { component: Formatter } = formatter;
|
|
@@ -955,15 +960,20 @@ class AccordionHeader extends React.Component {
|
|
|
955
960
|
" ",
|
|
956
961
|
React.createElement(Formatter, { that: that, idx: idx }))) || null;
|
|
957
962
|
}),
|
|
958
|
-
hasHelp
|
|
959
|
-
|
|
963
|
+
hasHelp &&
|
|
964
|
+
React.createElement(React.Fragment, null,
|
|
965
|
+
React.createElement(components_1.Help, { focusable: true, onFocus: this.onHelpFocus, onBlur: this.onHelpBlur, onClick: this.onHelpClick }),
|
|
966
|
+
React.createElement("div", { id: `${that.props.idSchema.$id}_${idx}--help`, style: { display: "none" } }, uiSchema["ui:help"]))));
|
|
967
|
+
const { Tooltip } = this.context.theme;
|
|
968
|
+
const tooltip = React.createElement(Tooltip, null, uiSchema["ui:help"]);
|
|
969
|
+
const headerTextComponent = hasHelp ? React.createElement(components_1.OverlayTrigger, { placement: "right", overlay: tooltip, show: this.state && this.state.focused || undefined }, headerText) : headerText;
|
|
960
970
|
const header = (React.createElement("div", { className: this.props.className, role: "tab", id: `${that.props.idSchema.$id}_${utils_1.getFormDataIndex(idx, that.props.uiSchema)}-header`, onClick: this.onHeaderClick, onMouseEnter: this.onMouseEnter, onMouseLeave: this.onMouseLeave },
|
|
961
971
|
React.createElement("div", { className: this.props.wrapperClassName },
|
|
962
972
|
headerTextComponent,
|
|
963
973
|
this.props.children)));
|
|
964
|
-
|
|
965
|
-
return utils_1.hasData(popupData) ? (React.createElement(OverlayTrigger, { placement: "left", overlay: React.createElement(Tooltip, { id: "nav-tooltip-" + idx },
|
|
974
|
+
return utils_1.hasData(popupData) ? (React.createElement(components_1.OverlayTrigger, { placement: "left", overlay: React.createElement(Tooltip, { id: "nav-tooltip-" + idx },
|
|
966
975
|
React.createElement(Popup, { data: popupData })) }, header)) : (header);
|
|
967
976
|
}
|
|
968
977
|
}
|
|
969
978
|
AccordionHeader.contextType = ReactContext_1.default;
|
|
979
|
+
AccordionHeader.state = { focused: false };
|
|
@@ -91,7 +91,7 @@ class _FieldTemplate extends React.Component {
|
|
|
91
91
|
inlineHelp ? React.createElement("div", { className: "pull-left" }, children) : children,
|
|
92
92
|
inlineHelp
|
|
93
93
|
? (React.createElement("div", { className: "pull-left" },
|
|
94
|
-
React.createElement(components_1.Help, { help: inlineHelp, id: `${htmlId}-inline-help
|
|
94
|
+
React.createElement(components_1.Help, { help: inlineHelp, id: `${htmlId}-inline-help`, focusable: true, standalone: true }))) : null),
|
|
95
95
|
belowHelp ?
|
|
96
96
|
React.createElement("div", { className: "small text-muted", dangerouslySetInnerHTML: { __html: belowHelp } }) :
|
|
97
97
|
null,
|
|
@@ -13,10 +13,20 @@ const TitleField = ({ title, id, formData, style, uiSchema = {}, registry = {} }
|
|
|
13
13
|
return _titleFormatters[renderer](Object.assign(Object.assign({}, titleFormatter), { formData }));
|
|
14
14
|
}).filter(i => i);
|
|
15
15
|
const { Tooltip } = React.useContext(ReactContext_1.default).theme;
|
|
16
|
+
const [focused, setFocused] = React.useState(undefined);
|
|
17
|
+
const onHelpFocus = React.useCallback(() => {
|
|
18
|
+
setFocused(true);
|
|
19
|
+
}, []);
|
|
20
|
+
const onHelpBlur = React.useCallback(() => {
|
|
21
|
+
setFocused(false);
|
|
22
|
+
}, []);
|
|
23
|
+
const onHelpClick = React.useCallback((e) => {
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
}, []);
|
|
16
26
|
if (renderedFormatters.length === 0 && utils_1.isEmptyString(title)) {
|
|
17
27
|
return null;
|
|
18
28
|
}
|
|
19
|
-
const helpComponent = help ? React.createElement(components_1.Help,
|
|
29
|
+
const helpComponent = help ? React.createElement(components_1.Help, { focusable: true, onFocus: onHelpFocus, onBlur: onHelpBlur, onClick: onHelpClick }) : null;
|
|
20
30
|
let titleTextContent = React.createElement("span", null,
|
|
21
31
|
React.createElement("span", { dangerouslySetInnerHTML: { __html: title } }),
|
|
22
32
|
" ",
|
|
@@ -27,7 +37,7 @@ const TitleField = ({ title, id, formData, style, uiSchema = {}, registry = {} }
|
|
|
27
37
|
React.createElement("strong", { dangerouslySetInnerHTML: { __html: title } }),
|
|
28
38
|
React.createElement("br", null),
|
|
29
39
|
React.createElement("span", { dangerouslySetInnerHTML: { __html: help } }))));
|
|
30
|
-
titleTextContent = (React.createElement(components_1.OverlayTrigger, { placement: "right", overlay: tooltipElem, hoverable: helpHoverable, formContext: registry.formContext }, titleTextContent));
|
|
40
|
+
titleTextContent = (React.createElement(components_1.OverlayTrigger, { placement: "right", overlay: tooltipElem, hoverable: helpHoverable, formContext: registry.formContext, show: focused || undefined }, titleTextContent));
|
|
31
41
|
}
|
|
32
42
|
return (React.createElement("legend", { className: utils_1.classNames(className, help && "has-help"), style: style },
|
|
33
43
|
React.createElement("span", null,
|
|
@@ -1026,7 +1026,6 @@ class ReactAutosuggest extends React.Component {
|
|
|
1026
1026
|
};
|
|
1027
1027
|
this.onInputKeyDown = (e) => {
|
|
1028
1028
|
let state, suggestion;
|
|
1029
|
-
const { shortcuts } = this.props.formContext.services.keyHandler;
|
|
1030
1029
|
switch (e.key) {
|
|
1031
1030
|
case "ArrowDown":
|
|
1032
1031
|
e.preventDefault();
|
|
@@ -1057,13 +1056,8 @@ class ReactAutosuggest extends React.Component {
|
|
|
1057
1056
|
case "Enter":
|
|
1058
1057
|
e.preventDefault();
|
|
1059
1058
|
suggestion = (this.props.suggestions || [])[this.state.focusedIdx];
|
|
1060
|
-
if (
|
|
1061
|
-
this.
|
|
1062
|
-
suggestion && this.onSuggestionSelected(suggestion);
|
|
1063
|
-
}, 0);
|
|
1064
|
-
}
|
|
1065
|
-
else {
|
|
1066
|
-
this.inputElem.blur();
|
|
1059
|
+
if (suggestion) {
|
|
1060
|
+
this.onSuggestionSelected(suggestion);
|
|
1067
1061
|
}
|
|
1068
1062
|
break;
|
|
1069
1063
|
case "Control":
|
|
@@ -27,9 +27,9 @@ export default class CheckboxWidget extends React.Component<any, any, any> {
|
|
|
27
27
|
getOptions: (props: any) => any;
|
|
28
28
|
getToggleMode: (props: any) => boolean;
|
|
29
29
|
onGroupKeyDown: any;
|
|
30
|
-
onTrueKeyDown:
|
|
31
|
-
onFalseKeyDown:
|
|
32
|
-
onUndefinedKeyDown:
|
|
30
|
+
onTrueKeyDown: any;
|
|
31
|
+
onFalseKeyDown: any;
|
|
32
|
+
onUndefinedKeyDown: any;
|
|
33
33
|
toggle: (e: any) => void;
|
|
34
34
|
formatValue(value: any, options: any, props: any): any;
|
|
35
35
|
}
|
|
@@ -38,38 +38,28 @@ class CheckboxWidget extends React.Component {
|
|
|
38
38
|
return Object.assign({ allowUndefined: true, showUndefined: true, invert: false, trueLabel: Yes, falseLabel: No, unknownLabel: Unknown, required: this.props.required }, utils_1.getUiOptions(props));
|
|
39
39
|
};
|
|
40
40
|
this.getToggleMode = (props) => {
|
|
41
|
-
const { allowUndefined, showUndefined
|
|
41
|
+
const { allowUndefined, showUndefined } = this.getOptions(props);
|
|
42
42
|
const displayUndefined = (allowUndefined && showUndefined);
|
|
43
|
-
|
|
44
|
-
return !displayUndefined && (trueLabel === Yes && falseLabel === No);
|
|
43
|
+
return !displayUndefined;
|
|
45
44
|
};
|
|
46
45
|
this.onGroupKeyDown = this.props.formContext.utils.keyboardClick((e) => {
|
|
47
46
|
this.getToggleMode(this.props) && this.toggle(e);
|
|
48
|
-
}
|
|
49
|
-
this.onTrueKeyDown = (e) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
};
|
|
65
|
-
this.onUndefinedKeyDown = (e) => {
|
|
66
|
-
const { key } = e;
|
|
67
|
-
if (key === " ") {
|
|
68
|
-
this.onChange(undefined);
|
|
69
|
-
e.preventDefault();
|
|
70
|
-
e.stopPropagation();
|
|
71
|
-
}
|
|
72
|
-
};
|
|
47
|
+
});
|
|
48
|
+
this.onTrueKeyDown = this.props.formContext.utils.keyboardClick((e) => {
|
|
49
|
+
this.onChange(true);
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
e.stopPropagation();
|
|
52
|
+
});
|
|
53
|
+
this.onFalseKeyDown = this.props.formContext.utils.keyboardClick((e) => {
|
|
54
|
+
this.onChange(false);
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
e.stopPropagation();
|
|
57
|
+
});
|
|
58
|
+
this.onUndefinedKeyDown = this.props.formContext.utils.keyboardClick((e) => {
|
|
59
|
+
this.onChange(undefined);
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
e.stopPropagation();
|
|
62
|
+
});
|
|
73
63
|
this.toggle = (e) => {
|
|
74
64
|
if (this.props.disabled || this.props.readonly) {
|
|
75
65
|
return;
|
|
@@ -112,15 +102,23 @@ class CheckboxWidget extends React.Component {
|
|
|
112
102
|
tabIndex: (toggleMode || _disabled) ? undefined : 0
|
|
113
103
|
};
|
|
114
104
|
const tabTargetClass = "laji-form-checkbox-widget-tab-target";
|
|
105
|
+
const selectedValueGlyph = React.createElement("span", { className: "laji-form-checkbox-selected-value-glyph" });
|
|
106
|
+
const unselectedValueGlyph = React.createElement("span", { className: "laji-form-checkbox-unselected-value-glyph" });
|
|
115
107
|
const checkbox = (React.createElement(ButtonToolbar, { className: utils_1.classNames("laji-form-checkbox-buttons", toggleMode && "desktop-layout") },
|
|
116
108
|
React.createElement(ToggleButtonGroup, Object.assign({ ref: this.groupRef, type: "radio", value: [_value], name: this.props.id, onChange: this.onButtonGroupChange, onKeyDown: this.onGroupKeyDown, className: utils_1.classNames(toggleMode && tabTargetClass) }, commonProps, { tabIndex: (toggleMode && !_disabled) ? 0 : undefined }),
|
|
117
|
-
React.createElement(ToggleButton, Object.assign({ id: `${id}-true`, ref: this.trueRef, value: true, onClick: toggleMode ? this.toggle : undefined, className: utils_1.classNames(
|
|
118
|
-
|
|
109
|
+
React.createElement(ToggleButton, Object.assign({ id: `${id}-true`, ref: this.trueRef, value: true, onClick: toggleMode ? this.toggle : undefined, className: utils_1.classNames(_value === true && tabTargetClass), onKeyDown: this.onTrueKeyDown }, commonProps),
|
|
110
|
+
_value === true ? selectedValueGlyph : unselectedValueGlyph,
|
|
111
|
+
trueLabel),
|
|
112
|
+
React.createElement(ToggleButton, Object.assign({ id: `${id}-false`, ref: this.falseRef, value: false, onClick: toggleMode ? this.toggle : undefined, className: utils_1.classNames(_value === false && tabTargetClass), onKeyDown: this.onFalseKeyDown }, commonProps),
|
|
113
|
+
_value === false ? selectedValueGlyph : unselectedValueGlyph,
|
|
114
|
+
falseLabel),
|
|
119
115
|
(displayUndefined ?
|
|
120
|
-
React.createElement(ToggleButton, Object.assign({ id: `${id}-undefined`, ref: this.undefinedRef, value: "undefined", className: utils_1.classNames(value === undefined && tabTargetClass) }, commonProps, { onKeyDown: this.onUndefinedKeyDown }),
|
|
116
|
+
React.createElement(ToggleButton, Object.assign({ id: `${id}-undefined`, ref: this.undefinedRef, value: "undefined", className: utils_1.classNames(value === undefined && tabTargetClass) }, commonProps, { onKeyDown: this.onUndefinedKeyDown }),
|
|
117
|
+
_value === "undefined" ? selectedValueGlyph : unselectedValueGlyph,
|
|
118
|
+
unknownLabel) : null))));
|
|
121
119
|
const { Label } = this.props.formContext;
|
|
122
120
|
return !hasLabel ? checkbox : React.createElement(React.Fragment, null,
|
|
123
|
-
React.createElement(Label, { label: label, required: required, uiSchema: this.props.uiSchema,
|
|
121
|
+
React.createElement(Label, { label: label, required: required, uiSchema: this.props.uiSchema, registry: this.props.registry, id: this.props.id }),
|
|
124
122
|
checkbox);
|
|
125
123
|
}
|
|
126
124
|
formatValue(value, options, props) {
|
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const React = require("react");
|
|
4
4
|
const PropTypes = require("prop-types");
|
|
5
|
-
const utils_1 = require("../../utils");
|
|
6
|
-
const components_1 = require("../components");
|
|
7
5
|
const Context_1 = require("../../Context");
|
|
8
6
|
const ReactContext_1 = require("../../ReactContext");
|
|
9
|
-
const
|
|
7
|
+
const utils_1 = require("../../utils");
|
|
10
8
|
class TextareaWidget extends React.Component {
|
|
11
9
|
constructor(props) {
|
|
12
10
|
super(props);
|
|
@@ -35,7 +33,7 @@ class TextareaWidget extends React.Component {
|
|
|
35
33
|
if (this.timeout)
|
|
36
34
|
clearTimeout(this.timeout);
|
|
37
35
|
this.timeout = this.props.formContext.setTimeout(() => {
|
|
38
|
-
this.props.onChange(value === "" ?
|
|
36
|
+
this.props.onChange(value === "" ? utils_1.getUiOptions(this.props).emptyValue : value);
|
|
39
37
|
}, 1000);
|
|
40
38
|
}
|
|
41
39
|
});
|
|
@@ -43,24 +41,9 @@ class TextareaWidget extends React.Component {
|
|
|
43
41
|
this._onChange = ({ target: { value } }) => {
|
|
44
42
|
this.onChange(value);
|
|
45
43
|
};
|
|
46
|
-
this.onKeyDown = (e) => {
|
|
47
|
-
const inputAllowed = !this.props.disabled && !this.props.readonly;
|
|
48
|
-
const isCtrlEnter = e.ctrlKey && e.key === "Enter";
|
|
49
|
-
if (this.state.enterReserved && inputAllowed && isCtrlEnter) {
|
|
50
|
-
this.onChange(this.state.value + "\n");
|
|
51
|
-
e.preventDefault();
|
|
52
|
-
e.stopPropagation();
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
44
|
this.state = this.getStateFromProps(props);
|
|
56
45
|
this.textareaRef = React.createRef();
|
|
57
46
|
this._context = Context_1.default(props.formContext.contextId);
|
|
58
|
-
Object.keys(props.formContext.services.keyHandler.shortcuts).some(keyCombo => {
|
|
59
|
-
if (keyCombo === "Enter") {
|
|
60
|
-
// // Direct mutation should be ok in constructor.
|
|
61
|
-
this.state.enterReserved = true; // eslint-disable-line react/no-direct-mutation-state
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
47
|
}
|
|
65
48
|
UNSAFE_componentWillReceiveProps(props) {
|
|
66
49
|
this.setState(this.getStateFromProps(props));
|
|
@@ -69,8 +52,7 @@ class TextareaWidget extends React.Component {
|
|
|
69
52
|
const { id, options, placeholder, disabled, readonly, autofocus } = this.props;
|
|
70
53
|
const { value } = this.state;
|
|
71
54
|
const { required = this.props.required } = options;
|
|
72
|
-
|
|
73
|
-
return this.state.enterReserved ? (React.createElement(components_1.TooltipComponent, { tooltip: `${utils_1.stringifyKeyCombo("ctrl+Enter")} ${this.props.formContext.translations.textareaHint}`, placement: "bottom" }, textarea)) : textarea;
|
|
55
|
+
return React.createElement("textarea", { id: id, className: "form-control", value: typeof value === "undefined" ? "" : value, placeholder: placeholder, required: required, disabled: disabled, readOnly: readonly, autoFocus: autofocus, rows: options.rows, onFocus: this.onFocus, onBlur: this.onBlur, onChange: this._onChange, onKeyDown: this.onKeyDown });
|
|
74
56
|
}
|
|
75
57
|
}
|
|
76
58
|
exports.default = TextareaWidget;
|
package/lib/utils.js
CHANGED
|
@@ -204,9 +204,10 @@ function isSelect(schema) {
|
|
|
204
204
|
exports.isSelect = isSelect;
|
|
205
205
|
const SWITCH_CLASS = "laji-form-checkbox-widget-tab-target";
|
|
206
206
|
const IMG_ADD_CLASS = "laji-form-drop-zone";
|
|
207
|
-
const inputTypes = ["input", "select", "textarea"];
|
|
208
207
|
const tabbableSelectors = [
|
|
209
|
-
|
|
208
|
+
"input",
|
|
209
|
+
"select",
|
|
210
|
+
"textarea",
|
|
210
211
|
`.${SWITCH_CLASS}`,
|
|
211
212
|
`.${IMG_ADD_CLASS}`
|
|
212
213
|
].map(type => `${type}:not([type="hidden"]):not(:disabled):not([readonly]):not([type="file"]):not(.leaflet-control-layers-selector):not(.laji-map-input)`);
|
|
@@ -221,7 +222,7 @@ function getTabbableFields(elem, reverse) {
|
|
|
221
222
|
exports.getTabbableFields = getTabbableFields;
|
|
222
223
|
function isTabbableInput(elem) {
|
|
223
224
|
return elem.id.match(/^_laji-form_/)
|
|
224
|
-
||
|
|
225
|
+
|| ["input", "select", "textarea"].includes(elem.tagName.toLowerCase())
|
|
225
226
|
|| elem.className.includes(SWITCH_CLASS)
|
|
226
227
|
|| elem.className.includes(IMG_ADD_CLASS);
|
|
227
228
|
}
|
|
@@ -301,7 +302,18 @@ exports.getNextInputInInputs = getNextInputInInputs;
|
|
|
301
302
|
const getNextInput = (formContext) => (inputElem, reverseDirection = false) => {
|
|
302
303
|
const formElem = react_dom_1.findDOMNode(formContext.formRef.current);
|
|
303
304
|
const fields = getTabbableFields(formElem);
|
|
304
|
-
|
|
305
|
+
const input = formContext.utils.getNextInputInInputs(inputElem, reverseDirection, fields);
|
|
306
|
+
if (!input) {
|
|
307
|
+
// Try to find a "tabbable element" from inside the nearest parent schema element.
|
|
308
|
+
const nearestParentField = findNearestParentSchemaElem(inputElem);
|
|
309
|
+
if (nearestParentField) {
|
|
310
|
+
const nearestTabbableElem = nearestParentField.querySelector(tabbableSelectorsQuery);
|
|
311
|
+
if (nearestTabbableElem) {
|
|
312
|
+
return formContext.utils.getNextInputInInputs(nearestTabbableElem, reverseDirection, fields);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return input;
|
|
305
317
|
};
|
|
306
318
|
exports.getNextInput = getNextInput;
|
|
307
319
|
const focusNextInput = (formContext) => (reverseDirection = false) => {
|
|
@@ -313,12 +325,10 @@ const focusNextInput = (formContext) => (reverseDirection = false) => {
|
|
|
313
325
|
if (uiSchema.autoFocus === false) {
|
|
314
326
|
return false;
|
|
315
327
|
}
|
|
316
|
-
const width = pixelsToBsSize(window.outerWidth);
|
|
317
|
-
if (width === "xs")
|
|
318
|
-
return false;
|
|
319
328
|
const field = formContext.utils.getNextInput(document.activeElement, reverseDirection);
|
|
320
329
|
if (field) {
|
|
321
330
|
field.focus();
|
|
331
|
+
scrollIntoViewIfNeeded(field, formContext.topOffset, formContext.bottomOffset);
|
|
322
332
|
return true;
|
|
323
333
|
}
|
|
324
334
|
return false;
|
|
@@ -445,7 +455,7 @@ const _keyboardClick = ({ contextId }) => (fn, keys = [" ", "Enter"]) => {
|
|
|
445
455
|
const { shortcuts } = Context_1.default(contextId);
|
|
446
456
|
keys = keys.filter(k => !(shortcuts === null || shortcuts === void 0 ? void 0 : shortcuts[k]));
|
|
447
457
|
}
|
|
448
|
-
if (keys.every(k => e.key !== k)) {
|
|
458
|
+
if (e.altKey || e.ctrlKey || keys.every(k => e.key !== k)) {
|
|
449
459
|
return;
|
|
450
460
|
}
|
|
451
461
|
e.preventDefault();
|