@dhis2-ui/alert 10.19.3 → 10.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/alert-bar/action.js +6 -5
- package/build/cjs/alert-bar/alert-bar.e2e.stories.js +5 -1
- package/build/cjs/alert-bar/alert-bar.js +4 -1
- package/build/cjs/alert-bar/dismiss.js +8 -5
- package/build/cjs/alert-bar/features/accessibility/index.js +15 -0
- package/build/cjs/alert-bar/features/accessibility.feature +17 -0
- package/build/cjs/alert-bar/features/common/index.js +4 -0
- package/build/cjs/alert-bar/icon.js +1 -0
- package/build/cjs/alert-bar/message.js +35 -8
- package/build/cjs/locales/en/translations.json +3 -0
- package/build/cjs/locales/index.js +26 -0
- package/build/es/alert-bar/action.js +7 -6
- package/build/es/alert-bar/alert-bar.e2e.stories.js +3 -0
- package/build/es/alert-bar/alert-bar.js +4 -1
- package/build/es/alert-bar/dismiss.js +9 -6
- package/build/es/alert-bar/features/accessibility/index.js +13 -0
- package/build/es/alert-bar/features/accessibility.feature +17 -0
- package/build/es/alert-bar/features/common/index.js +4 -0
- package/build/es/alert-bar/icon.js +1 -0
- package/build/es/alert-bar/message.js +35 -8
- package/build/es/locales/en/translations.json +3 -0
- package/build/es/locales/index.js +18 -0
- package/package.json +6 -4
- package/src/alert-bar/action.js +20 -5
- package/src/alert-bar/alert-bar.e2e.stories.js +1 -0
- package/src/alert-bar/alert-bar.js +3 -1
- package/src/alert-bar/dismiss.js +23 -7
- package/src/alert-bar/features/accessibility/index.js +27 -0
- package/src/alert-bar/features/accessibility.feature +17 -0
- package/src/alert-bar/features/common/index.js +5 -0
- package/src/alert-bar/icon.js +1 -1
- package/src/alert-bar/message.js +49 -12
- package/src/locales/en/translations.json +3 -0
- package/src/locales/index.js +21 -0
- package/types/index.d.ts +1 -1
|
@@ -22,14 +22,15 @@ class Action extends _react.Component {
|
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
render() {
|
|
25
|
-
return /*#__PURE__*/_react.default.createElement("
|
|
25
|
+
return /*#__PURE__*/_react.default.createElement("button", {
|
|
26
|
+
type: "button",
|
|
26
27
|
onClick: this.onClick,
|
|
27
28
|
"data-test": this.props.dataTest,
|
|
28
|
-
className: _style.default.dynamic([["
|
|
29
|
+
className: _style.default.dynamic([["2865572695", [_uiConstants.spacers.dp12, _uiConstants.theme.focus]]])
|
|
29
30
|
}, this.props.label, /*#__PURE__*/_react.default.createElement(_style.default, {
|
|
30
|
-
id: "
|
|
31
|
-
dynamic: [_uiConstants.spacers.dp12]
|
|
32
|
-
}, [`
|
|
31
|
+
id: "2865572695",
|
|
32
|
+
dynamic: [_uiConstants.spacers.dp12, _uiConstants.theme.focus]
|
|
33
|
+
}, [`button.__jsx-style-dynamic-selector{margin-inline-end:${_uiConstants.spacers.dp12};padding:0;border:none;background:transparent;color:inherit;font:inherit;-webkit-text-decoration:underline;text-decoration:underline;white-space:nowrap;}`, "button.__jsx-style-dynamic-selector:hover{cursor:pointer;}", `button.__jsx-style-dynamic-selector:focus{outline:3px solid ${_uiConstants.theme.focus};}`, "button.__jsx-style-dynamic-selector:focus.__jsx-style-dynamic-selector:not(:focus-visible){outline:none;}"]));
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
exports.Action = Action;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.default = exports.WithOnHidden = exports.WithMessage = exports.PermanentWithActions = exports.Permanent = exports.HiddenProp = exports.DisabledIcon = exports.Default = exports.CustomIcon = exports.CustomDuration = void 0;
|
|
6
|
+
exports.default = exports.WithOnHidden = exports.WithMessage = exports.PermanentWithActions = exports.Permanent = exports.HiddenProp = exports.DisabledIcon = exports.Default = exports.CustomIcon = exports.CustomDuration = exports.Critical = void 0;
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _index = require("./index.js");
|
|
9
9
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
@@ -13,6 +13,10 @@ var _default = exports.default = {
|
|
|
13
13
|
};
|
|
14
14
|
const Default = () => /*#__PURE__*/_react.default.createElement(_index.AlertBar, null, "Default");
|
|
15
15
|
exports.Default = Default;
|
|
16
|
+
const Critical = () => /*#__PURE__*/_react.default.createElement(_index.AlertBar, {
|
|
17
|
+
critical: true
|
|
18
|
+
}, "Critical");
|
|
19
|
+
exports.Critical = Critical;
|
|
16
20
|
const CustomDuration = () => /*#__PURE__*/_react.default.createElement(_index.AlertBar, {
|
|
17
21
|
duration: 2000
|
|
18
22
|
}, "Custom duration");
|
|
@@ -122,7 +122,10 @@ const AlertBar = ({
|
|
|
122
122
|
success: success,
|
|
123
123
|
warning: warning,
|
|
124
124
|
info: info
|
|
125
|
-
}), /*#__PURE__*/_react.default.createElement(_message.Message,
|
|
125
|
+
}), /*#__PURE__*/_react.default.createElement(_message.Message, {
|
|
126
|
+
critical: critical,
|
|
127
|
+
dataTest: `${dataTest}-message`
|
|
128
|
+
}, children), /*#__PURE__*/_react.default.createElement(_actions.Actions, {
|
|
126
129
|
actions: actions,
|
|
127
130
|
hide: runHideAnimation,
|
|
128
131
|
dataTest: dataTest
|
|
@@ -9,18 +9,21 @@ var _uiConstants = require("@dhis2/ui-constants");
|
|
|
9
9
|
var _uiIcons = require("@dhis2/ui-icons");
|
|
10
10
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
11
|
var _react = _interopRequireDefault(require("react"));
|
|
12
|
+
var _index = _interopRequireDefault(require("../locales/index.js"));
|
|
12
13
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
14
|
const Dismiss = ({
|
|
14
15
|
onClick,
|
|
15
16
|
dataTest
|
|
16
|
-
}) => /*#__PURE__*/_react.default.createElement("
|
|
17
|
+
}) => /*#__PURE__*/_react.default.createElement("button", {
|
|
18
|
+
type: "button",
|
|
17
19
|
onClick: onClick,
|
|
18
20
|
"data-test": dataTest,
|
|
19
|
-
|
|
21
|
+
"aria-label": _index.default.t('Dismiss'),
|
|
22
|
+
className: _style.default.dynamic([["503636260", [_uiConstants.spacers.dp16, _uiConstants.theme.focus]]])
|
|
20
23
|
}, /*#__PURE__*/_react.default.createElement(_uiIcons.IconCross24, null), /*#__PURE__*/_react.default.createElement(_style.default, {
|
|
21
|
-
id: "
|
|
22
|
-
dynamic: [_uiConstants.spacers.dp16]
|
|
23
|
-
}, [`
|
|
24
|
+
id: "503636260",
|
|
25
|
+
dynamic: [_uiConstants.spacers.dp16, _uiConstants.theme.focus]
|
|
26
|
+
}, [`button.__jsx-style-dynamic-selector{margin-inline-start:${_uiConstants.spacers.dp16};min-height:32px;min-width:32px;padding:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;border:none;border-radius:5px;background:transparent;color:inherit;}`, "button.__jsx-style-dynamic-selector:hover{cursor:pointer;background:rgba(0,0,0,0.15);}", "button.__jsx-style-dynamic-selector:active{background:rgba(0,0,0,0.25);}", `button.__jsx-style-dynamic-selector:focus{outline:3px solid ${_uiConstants.theme.focus};}`, "button.__jsx-style-dynamic-selector:focus.__jsx-style-dynamic-selector:not(:focus-visible){outline:none;}", "button.__jsx-style-dynamic-selector svg{width:18px;height:18px;}"]));
|
|
24
27
|
exports.Dismiss = Dismiss;
|
|
25
28
|
Dismiss.propTypes = {
|
|
26
29
|
dataTest: _propTypes.default.string.isRequired,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _cypressCucumberPreprocessor = require("@badeball/cypress-cucumber-preprocessor");
|
|
4
|
+
(0, _cypressCucumberPreprocessor.Then)('the AlertBar message has the status role', () => {
|
|
5
|
+
cy.get('[data-test="dhis2-uicore-alertbar-message"]').find('[role="status"]').should('exist');
|
|
6
|
+
});
|
|
7
|
+
(0, _cypressCucumberPreprocessor.Then)('the AlertBar message has the alert role', () => {
|
|
8
|
+
cy.get('[data-test="dhis2-uicore-alertbar-message"]').find('[role="alert"]').should('exist');
|
|
9
|
+
});
|
|
10
|
+
(0, _cypressCucumberPreprocessor.Then)('the icon is hidden from assistive technologies', () => {
|
|
11
|
+
cy.get('[data-test="dhis2-uicore-alertbar-icon"]').should('have.attr', 'aria-hidden', 'true');
|
|
12
|
+
});
|
|
13
|
+
(0, _cypressCucumberPreprocessor.Then)('the dismiss control is a button labelled "Dismiss"', () => {
|
|
14
|
+
cy.get('[data-test="dhis2-uicore-alertbar-dismiss"]').should('match', 'button').and('have.attr', 'aria-label', 'Dismiss');
|
|
15
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Feature: AlertBar accessibility
|
|
2
|
+
|
|
3
|
+
Scenario: A default AlertBar message is a polite live region
|
|
4
|
+
Given a default AlertBar is rendered
|
|
5
|
+
Then the AlertBar message has the status role
|
|
6
|
+
|
|
7
|
+
Scenario: A critical AlertBar message is an assertive live region
|
|
8
|
+
Given a critical AlertBar is rendered
|
|
9
|
+
Then the AlertBar message has the alert role
|
|
10
|
+
|
|
11
|
+
Scenario: The icon is hidden from assistive technologies
|
|
12
|
+
Given a default AlertBar is rendered
|
|
13
|
+
Then the icon is hidden from assistive technologies
|
|
14
|
+
|
|
15
|
+
Scenario: The dismiss control is a labelled button
|
|
16
|
+
Given a default AlertBar is rendered
|
|
17
|
+
Then the dismiss control is a button labelled "Dismiss"
|
|
@@ -5,6 +5,10 @@ var _cypressCucumberPreprocessor = require("@badeball/cypress-cucumber-preproces
|
|
|
5
5
|
cy.visitStory('AlertBar', 'Default');
|
|
6
6
|
cy.get('[data-test="dhis2-uicore-alertbar"]').should('be.visible');
|
|
7
7
|
});
|
|
8
|
+
(0, _cypressCucumberPreprocessor.Given)('a critical AlertBar is rendered', () => {
|
|
9
|
+
cy.visitStory('AlertBar', 'Critical');
|
|
10
|
+
cy.get('[data-test="dhis2-uicore-alertbar"]').should('be.visible');
|
|
11
|
+
});
|
|
8
12
|
(0, _cypressCucumberPreprocessor.Given)('the AlertBar is rendered', () => {
|
|
9
13
|
cy.get('[data-test="dhis2-uicore-alertbar"]').should('exist');
|
|
10
14
|
cy.get('[data-test="dhis2-uicore-alertbar"]').should('be.visible');
|
|
@@ -60,6 +60,7 @@ const Icon = ({
|
|
|
60
60
|
}
|
|
61
61
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
62
62
|
"data-test": dataTest,
|
|
63
|
+
"aria-hidden": "true",
|
|
63
64
|
className: _style.default.dynamic([["4176481777", [_uiConstants.spacers.dp12]]])
|
|
64
65
|
}, /*#__PURE__*/_react.default.isValidElement(icon) ? icon : /*#__PURE__*/_react.default.createElement(StatusIcon, {
|
|
65
66
|
valid: success,
|
|
@@ -6,16 +6,43 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.Message = void 0;
|
|
7
7
|
var _style = _interopRequireDefault(require("styled-jsx/style"));
|
|
8
8
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
9
|
-
var _react =
|
|
9
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
10
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
10
11
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
// Screen readers don't announce a role="status" region that has text on
|
|
13
|
+
// mount, so the text is added after a delay. role="alert" is announced on
|
|
14
|
+
// insertion and needs no delay. The visible copy is rendered separately so
|
|
15
|
+
// the delay doesn't shift the layout.
|
|
16
|
+
const ANNOUNCE_DELAY = 100;
|
|
11
17
|
const Message = ({
|
|
12
|
-
children
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
children,
|
|
19
|
+
critical,
|
|
20
|
+
dataTest
|
|
21
|
+
}) => {
|
|
22
|
+
const [announceable, setAnnounceable] = (0, _react.useState)(false);
|
|
23
|
+
(0, _react.useEffect)(() => {
|
|
24
|
+
if (critical) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const timeout = setTimeout(() => setAnnounceable(true), ANNOUNCE_DELAY);
|
|
28
|
+
return () => clearTimeout(timeout);
|
|
29
|
+
}, [critical]);
|
|
30
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
31
|
+
"data-test": dataTest,
|
|
32
|
+
className: "jsx-2192918634"
|
|
33
|
+
}, /*#__PURE__*/_react.default.createElement("span", {
|
|
34
|
+
"aria-hidden": "true",
|
|
35
|
+
className: "jsx-2192918634"
|
|
36
|
+
}, children), /*#__PURE__*/_react.default.createElement("span", {
|
|
37
|
+
role: critical ? 'alert' : 'status',
|
|
38
|
+
className: "jsx-2192918634" + " " + "live-region"
|
|
39
|
+
}, critical || announceable ? children : null), /*#__PURE__*/_react.default.createElement(_style.default, {
|
|
40
|
+
id: "2192918634"
|
|
41
|
+
}, ["div.jsx-2192918634{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}", ".live-region.jsx-2192918634{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;-webkit-clip:rect(0,0,0,0);clip:rect(0,0,0,0);white-space:nowrap;border:0;}"]));
|
|
42
|
+
};
|
|
18
43
|
exports.Message = Message;
|
|
19
44
|
Message.propTypes = {
|
|
20
|
-
children: _propTypes.default.string.isRequired
|
|
45
|
+
children: _propTypes.default.string.isRequired,
|
|
46
|
+
dataTest: _propTypes.default.string.isRequired,
|
|
47
|
+
critical: _propTypes.default.bool
|
|
21
48
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _d2I18n = _interopRequireDefault(require("@dhis2/d2-i18n"));
|
|
8
|
+
var _translations = _interopRequireDefault(require("./en/translations.json"));
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
//------------------------------------------------------------------------------
|
|
11
|
+
// <auto-generated>
|
|
12
|
+
// This code was generated by d2-i18n-generate.
|
|
13
|
+
//
|
|
14
|
+
// Changes to this file may cause incorrect behavior and will be lost if
|
|
15
|
+
// the code is regenerated.
|
|
16
|
+
// </auto-generated>
|
|
17
|
+
//------------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
const namespace = 'default';
|
|
20
|
+
|
|
21
|
+
// Use 'deep' = true and 'overwrite' = false to add to, but not overwrite,
|
|
22
|
+
// custom translations from the datastore (added by the app adapter)
|
|
23
|
+
|
|
24
|
+
_d2I18n.default.addResourceBundle('en', namespace, _translations.default, true, false);
|
|
25
|
+
_d2I18n.default.addResourceBundle('en', namespace, _translations.default, true, false);
|
|
26
|
+
var _default = exports.default = _d2I18n.default;
|
|
@@ -2,7 +2,7 @@ import _JSXStyle from "styled-jsx/style";
|
|
|
2
2
|
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
3
3
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
4
4
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
5
|
-
import { spacers } from '@dhis2/ui-constants';
|
|
5
|
+
import { spacers, theme } from '@dhis2/ui-constants';
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
7
|
import React, { Component } from 'react';
|
|
8
8
|
class Action extends Component {
|
|
@@ -14,14 +14,15 @@ class Action extends Component {
|
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
16
|
render() {
|
|
17
|
-
return /*#__PURE__*/React.createElement("
|
|
17
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
18
|
+
type: "button",
|
|
18
19
|
onClick: this.onClick,
|
|
19
20
|
"data-test": this.props.dataTest,
|
|
20
|
-
className: _JSXStyle.dynamic([["
|
|
21
|
+
className: _JSXStyle.dynamic([["2865572695", [spacers.dp12, theme.focus]]])
|
|
21
22
|
}, this.props.label, /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
22
|
-
id: "
|
|
23
|
-
dynamic: [spacers.dp12]
|
|
24
|
-
}, [`
|
|
23
|
+
id: "2865572695",
|
|
24
|
+
dynamic: [spacers.dp12, theme.focus]
|
|
25
|
+
}, [`button.__jsx-style-dynamic-selector{margin-inline-end:${spacers.dp12};padding:0;border:none;background:transparent;color:inherit;font:inherit;-webkit-text-decoration:underline;text-decoration:underline;white-space:nowrap;}`, "button.__jsx-style-dynamic-selector:hover{cursor:pointer;}", `button.__jsx-style-dynamic-selector:focus{outline:3px solid ${theme.focus};}`, "button.__jsx-style-dynamic-selector:focus.__jsx-style-dynamic-selector:not(:focus-visible){outline:none;}"]));
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
Action.propTypes = {
|
|
@@ -5,6 +5,9 @@ export default {
|
|
|
5
5
|
title: 'AlertBar'
|
|
6
6
|
};
|
|
7
7
|
export const Default = () => /*#__PURE__*/React.createElement(AlertBar, null, "Default");
|
|
8
|
+
export const Critical = () => /*#__PURE__*/React.createElement(AlertBar, {
|
|
9
|
+
critical: true
|
|
10
|
+
}, "Critical");
|
|
8
11
|
export const CustomDuration = () => /*#__PURE__*/React.createElement(AlertBar, {
|
|
9
12
|
duration: 2000
|
|
10
13
|
}, "Custom duration");
|
|
@@ -114,7 +114,10 @@ const AlertBar = ({
|
|
|
114
114
|
success: success,
|
|
115
115
|
warning: warning,
|
|
116
116
|
info: info
|
|
117
|
-
}), /*#__PURE__*/React.createElement(Message,
|
|
117
|
+
}), /*#__PURE__*/React.createElement(Message, {
|
|
118
|
+
critical: critical,
|
|
119
|
+
dataTest: `${dataTest}-message`
|
|
120
|
+
}, children), /*#__PURE__*/React.createElement(Actions, {
|
|
118
121
|
actions: actions,
|
|
119
122
|
hide: runHideAnimation,
|
|
120
123
|
dataTest: dataTest
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import _JSXStyle from "styled-jsx/style";
|
|
2
|
-
import { spacers } from '@dhis2/ui-constants';
|
|
2
|
+
import { spacers, theme } from '@dhis2/ui-constants';
|
|
3
3
|
import { IconCross24 } from '@dhis2/ui-icons';
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
5
|
import React from 'react';
|
|
6
|
+
import i18n from '../locales/index.js';
|
|
6
7
|
const Dismiss = ({
|
|
7
8
|
onClick,
|
|
8
9
|
dataTest
|
|
9
|
-
}) => /*#__PURE__*/React.createElement("
|
|
10
|
+
}) => /*#__PURE__*/React.createElement("button", {
|
|
11
|
+
type: "button",
|
|
10
12
|
onClick: onClick,
|
|
11
13
|
"data-test": dataTest,
|
|
12
|
-
|
|
14
|
+
"aria-label": i18n.t('Dismiss'),
|
|
15
|
+
className: _JSXStyle.dynamic([["503636260", [spacers.dp16, theme.focus]]])
|
|
13
16
|
}, /*#__PURE__*/React.createElement(IconCross24, null), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
14
|
-
id: "
|
|
15
|
-
dynamic: [spacers.dp16]
|
|
16
|
-
}, [`
|
|
17
|
+
id: "503636260",
|
|
18
|
+
dynamic: [spacers.dp16, theme.focus]
|
|
19
|
+
}, [`button.__jsx-style-dynamic-selector{margin-inline-start:${spacers.dp16};min-height:32px;min-width:32px;padding:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;border:none;border-radius:5px;background:transparent;color:inherit;}`, "button.__jsx-style-dynamic-selector:hover{cursor:pointer;background:rgba(0,0,0,0.15);}", "button.__jsx-style-dynamic-selector:active{background:rgba(0,0,0,0.25);}", `button.__jsx-style-dynamic-selector:focus{outline:3px solid ${theme.focus};}`, "button.__jsx-style-dynamic-selector:focus.__jsx-style-dynamic-selector:not(:focus-visible){outline:none;}", "button.__jsx-style-dynamic-selector svg{width:18px;height:18px;}"]));
|
|
17
20
|
Dismiss.propTypes = {
|
|
18
21
|
dataTest: PropTypes.string.isRequired,
|
|
19
22
|
onClick: PropTypes.func.isRequired
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Then } from '@badeball/cypress-cucumber-preprocessor';
|
|
2
|
+
Then('the AlertBar message has the status role', () => {
|
|
3
|
+
cy.get('[data-test="dhis2-uicore-alertbar-message"]').find('[role="status"]').should('exist');
|
|
4
|
+
});
|
|
5
|
+
Then('the AlertBar message has the alert role', () => {
|
|
6
|
+
cy.get('[data-test="dhis2-uicore-alertbar-message"]').find('[role="alert"]').should('exist');
|
|
7
|
+
});
|
|
8
|
+
Then('the icon is hidden from assistive technologies', () => {
|
|
9
|
+
cy.get('[data-test="dhis2-uicore-alertbar-icon"]').should('have.attr', 'aria-hidden', 'true');
|
|
10
|
+
});
|
|
11
|
+
Then('the dismiss control is a button labelled "Dismiss"', () => {
|
|
12
|
+
cy.get('[data-test="dhis2-uicore-alertbar-dismiss"]').should('match', 'button').and('have.attr', 'aria-label', 'Dismiss');
|
|
13
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Feature: AlertBar accessibility
|
|
2
|
+
|
|
3
|
+
Scenario: A default AlertBar message is a polite live region
|
|
4
|
+
Given a default AlertBar is rendered
|
|
5
|
+
Then the AlertBar message has the status role
|
|
6
|
+
|
|
7
|
+
Scenario: A critical AlertBar message is an assertive live region
|
|
8
|
+
Given a critical AlertBar is rendered
|
|
9
|
+
Then the AlertBar message has the alert role
|
|
10
|
+
|
|
11
|
+
Scenario: The icon is hidden from assistive technologies
|
|
12
|
+
Given a default AlertBar is rendered
|
|
13
|
+
Then the icon is hidden from assistive technologies
|
|
14
|
+
|
|
15
|
+
Scenario: The dismiss control is a labelled button
|
|
16
|
+
Given a default AlertBar is rendered
|
|
17
|
+
Then the dismiss control is a button labelled "Dismiss"
|
|
@@ -3,6 +3,10 @@ Given('a default AlertBar is rendered', () => {
|
|
|
3
3
|
cy.visitStory('AlertBar', 'Default');
|
|
4
4
|
cy.get('[data-test="dhis2-uicore-alertbar"]').should('be.visible');
|
|
5
5
|
});
|
|
6
|
+
Given('a critical AlertBar is rendered', () => {
|
|
7
|
+
cy.visitStory('AlertBar', 'Critical');
|
|
8
|
+
cy.get('[data-test="dhis2-uicore-alertbar"]').should('be.visible');
|
|
9
|
+
});
|
|
6
10
|
Given('the AlertBar is rendered', () => {
|
|
7
11
|
cy.get('[data-test="dhis2-uicore-alertbar"]').should('exist');
|
|
8
12
|
cy.get('[data-test="dhis2-uicore-alertbar"]').should('be.visible');
|
|
@@ -53,6 +53,7 @@ const Icon = ({
|
|
|
53
53
|
}
|
|
54
54
|
return /*#__PURE__*/React.createElement("div", {
|
|
55
55
|
"data-test": dataTest,
|
|
56
|
+
"aria-hidden": "true",
|
|
56
57
|
className: _JSXStyle.dynamic([["4176481777", [spacers.dp12]]])
|
|
57
58
|
}, /*#__PURE__*/React.isValidElement(icon) ? icon : /*#__PURE__*/React.createElement(StatusIcon, {
|
|
58
59
|
valid: success,
|
|
@@ -1,14 +1,41 @@
|
|
|
1
1
|
import _JSXStyle from "styled-jsx/style";
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import React from 'react';
|
|
3
|
+
import React, { useEffect, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
// Screen readers don't announce a role="status" region that has text on
|
|
6
|
+
// mount, so the text is added after a delay. role="alert" is announced on
|
|
7
|
+
// insertion and needs no delay. The visible copy is rendered separately so
|
|
8
|
+
// the delay doesn't shift the layout.
|
|
9
|
+
const ANNOUNCE_DELAY = 100;
|
|
4
10
|
const Message = ({
|
|
5
|
-
children
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
children,
|
|
12
|
+
critical,
|
|
13
|
+
dataTest
|
|
14
|
+
}) => {
|
|
15
|
+
const [announceable, setAnnounceable] = useState(false);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (critical) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const timeout = setTimeout(() => setAnnounceable(true), ANNOUNCE_DELAY);
|
|
21
|
+
return () => clearTimeout(timeout);
|
|
22
|
+
}, [critical]);
|
|
23
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
24
|
+
"data-test": dataTest,
|
|
25
|
+
className: "jsx-2192918634"
|
|
26
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
27
|
+
"aria-hidden": "true",
|
|
28
|
+
className: "jsx-2192918634"
|
|
29
|
+
}, children), /*#__PURE__*/React.createElement("span", {
|
|
30
|
+
role: critical ? 'alert' : 'status',
|
|
31
|
+
className: "jsx-2192918634" + " " + "live-region"
|
|
32
|
+
}, critical || announceable ? children : null), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
33
|
+
id: "2192918634"
|
|
34
|
+
}, ["div.jsx-2192918634{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}", ".live-region.jsx-2192918634{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;-webkit-clip:rect(0,0,0,0);clip:rect(0,0,0,0);white-space:nowrap;border:0;}"]));
|
|
35
|
+
};
|
|
11
36
|
Message.propTypes = {
|
|
12
|
-
children: PropTypes.string.isRequired
|
|
37
|
+
children: PropTypes.string.isRequired,
|
|
38
|
+
dataTest: PropTypes.string.isRequired,
|
|
39
|
+
critical: PropTypes.bool
|
|
13
40
|
};
|
|
14
41
|
export { Message };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//------------------------------------------------------------------------------
|
|
2
|
+
// <auto-generated>
|
|
3
|
+
// This code was generated by d2-i18n-generate.
|
|
4
|
+
//
|
|
5
|
+
// Changes to this file may cause incorrect behavior and will be lost if
|
|
6
|
+
// the code is regenerated.
|
|
7
|
+
// </auto-generated>
|
|
8
|
+
//------------------------------------------------------------------------------
|
|
9
|
+
import i18n from '@dhis2/d2-i18n';
|
|
10
|
+
import enTranslations from './en/translations.json';
|
|
11
|
+
const namespace = 'default';
|
|
12
|
+
|
|
13
|
+
// Use 'deep' = true and 'overwrite' = false to add to, but not overwrite,
|
|
14
|
+
// custom translations from the datastore (added by the app adapter)
|
|
15
|
+
|
|
16
|
+
i18n.addResourceBundle('en', namespace, enTranslations, true, false);
|
|
17
|
+
i18n.addResourceBundle('en', namespace, enTranslations, true, false);
|
|
18
|
+
export default i18n;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhis2-ui/alert",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.20.0",
|
|
4
4
|
"description": "UI Alert",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,15 +27,16 @@
|
|
|
27
27
|
"test": "d2-app-scripts test --jestConfig ../../jest.config.shared.js"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
+
"@dhis2/d2-i18n": "^1",
|
|
30
31
|
"react": "^16.13 || ^18",
|
|
31
32
|
"react-dom": "^16.13 || ^18",
|
|
32
33
|
"styled-jsx": "^4"
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"@dhis2/prop-types": "^3.1.2",
|
|
36
|
-
"@dhis2-ui/portal": "10.
|
|
37
|
-
"@dhis2/ui-constants": "10.
|
|
38
|
-
"@dhis2/ui-icons": "10.
|
|
37
|
+
"@dhis2-ui/portal": "10.20.0",
|
|
38
|
+
"@dhis2/ui-constants": "10.20.0",
|
|
39
|
+
"@dhis2/ui-icons": "10.20.0",
|
|
39
40
|
"classnames": "^2.3.1",
|
|
40
41
|
"prop-types": "^15.7.2"
|
|
41
42
|
},
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
"src"
|
|
46
47
|
],
|
|
47
48
|
"devDependencies": {
|
|
49
|
+
"@dhis2/d2-i18n": "^1.1.0",
|
|
48
50
|
"react": "^18.3.1",
|
|
49
51
|
"react-dom": "^18.3.1",
|
|
50
52
|
"styled-jsx": "^4.0.1"
|
package/src/alert-bar/action.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spacers } from '@dhis2/ui-constants'
|
|
1
|
+
import { spacers, theme } from '@dhis2/ui-constants'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import React, { Component } from 'react'
|
|
4
4
|
|
|
@@ -10,19 +10,34 @@ class Action extends Component {
|
|
|
10
10
|
|
|
11
11
|
render() {
|
|
12
12
|
return (
|
|
13
|
-
<
|
|
13
|
+
<button
|
|
14
|
+
type="button"
|
|
15
|
+
onClick={this.onClick}
|
|
16
|
+
data-test={this.props.dataTest}
|
|
17
|
+
>
|
|
14
18
|
{this.props.label}
|
|
15
19
|
<style jsx>{`
|
|
16
|
-
|
|
20
|
+
button {
|
|
17
21
|
margin-inline-end: ${spacers.dp12};
|
|
22
|
+
padding: 0;
|
|
23
|
+
border: none;
|
|
24
|
+
background: transparent;
|
|
25
|
+
color: inherit;
|
|
26
|
+
font: inherit;
|
|
18
27
|
text-decoration: underline;
|
|
19
28
|
white-space: nowrap;
|
|
20
29
|
}
|
|
21
|
-
|
|
30
|
+
button:hover {
|
|
22
31
|
cursor: pointer;
|
|
23
32
|
}
|
|
33
|
+
button:focus {
|
|
34
|
+
outline: 3px solid ${theme.focus};
|
|
35
|
+
}
|
|
36
|
+
button:focus:not(:focus-visible) {
|
|
37
|
+
outline: none;
|
|
38
|
+
}
|
|
24
39
|
`}</style>
|
|
25
|
-
</
|
|
40
|
+
</button>
|
|
26
41
|
)
|
|
27
42
|
}
|
|
28
43
|
}
|
|
@@ -6,6 +6,7 @@ window.onHidden = window.Cypress && window.Cypress.cy.stub()
|
|
|
6
6
|
export default { title: 'AlertBar' }
|
|
7
7
|
|
|
8
8
|
export const Default = () => <AlertBar>Default</AlertBar>
|
|
9
|
+
export const Critical = () => <AlertBar critical>Critical</AlertBar>
|
|
9
10
|
export const CustomDuration = () => (
|
|
10
11
|
<AlertBar duration={2000}>Custom duration</AlertBar>
|
|
11
12
|
)
|
|
@@ -129,7 +129,9 @@ const AlertBar = ({
|
|
|
129
129
|
warning={warning}
|
|
130
130
|
info={info}
|
|
131
131
|
/>
|
|
132
|
-
<Message
|
|
132
|
+
<Message critical={critical} dataTest={`${dataTest}-message`}>
|
|
133
|
+
{children}
|
|
134
|
+
</Message>
|
|
133
135
|
<Actions
|
|
134
136
|
actions={actions}
|
|
135
137
|
hide={runHideAnimation}
|
package/src/alert-bar/dismiss.js
CHANGED
|
@@ -1,34 +1,50 @@
|
|
|
1
|
-
import { spacers } from '@dhis2/ui-constants'
|
|
1
|
+
import { spacers, theme } from '@dhis2/ui-constants'
|
|
2
2
|
import { IconCross24 } from '@dhis2/ui-icons'
|
|
3
3
|
import PropTypes from 'prop-types'
|
|
4
4
|
import React from 'react'
|
|
5
|
+
import i18n from '../locales/index.js'
|
|
5
6
|
|
|
6
7
|
const Dismiss = ({ onClick, dataTest }) => (
|
|
7
|
-
<
|
|
8
|
+
<button
|
|
9
|
+
type="button"
|
|
10
|
+
onClick={onClick}
|
|
11
|
+
data-test={dataTest}
|
|
12
|
+
aria-label={i18n.t('Dismiss')}
|
|
13
|
+
>
|
|
8
14
|
<IconCross24 />
|
|
9
15
|
<style jsx>{`
|
|
10
|
-
|
|
16
|
+
button {
|
|
11
17
|
margin-inline-start: ${spacers.dp16};
|
|
12
18
|
min-height: 32px;
|
|
13
19
|
min-width: 32px;
|
|
20
|
+
padding: 0;
|
|
14
21
|
display: flex;
|
|
15
22
|
align-items: center;
|
|
16
23
|
justify-content: center;
|
|
24
|
+
border: none;
|
|
17
25
|
border-radius: 5px;
|
|
26
|
+
background: transparent;
|
|
27
|
+
color: inherit;
|
|
18
28
|
}
|
|
19
|
-
|
|
29
|
+
button:hover {
|
|
20
30
|
cursor: pointer;
|
|
21
31
|
background: rgba(0, 0, 0, 0.15);
|
|
22
32
|
}
|
|
23
|
-
|
|
33
|
+
button:active {
|
|
24
34
|
background: rgba(0, 0, 0, 0.25);
|
|
25
35
|
}
|
|
26
|
-
|
|
36
|
+
button:focus {
|
|
37
|
+
outline: 3px solid ${theme.focus};
|
|
38
|
+
}
|
|
39
|
+
button:focus:not(:focus-visible) {
|
|
40
|
+
outline: none;
|
|
41
|
+
}
|
|
42
|
+
button :global(svg) {
|
|
27
43
|
width: 18px;
|
|
28
44
|
height: 18px;
|
|
29
45
|
}
|
|
30
46
|
`}</style>
|
|
31
|
-
</
|
|
47
|
+
</button>
|
|
32
48
|
)
|
|
33
49
|
|
|
34
50
|
Dismiss.propTypes = {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Then } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Then('the AlertBar message has the status role', () => {
|
|
4
|
+
cy.get('[data-test="dhis2-uicore-alertbar-message"]')
|
|
5
|
+
.find('[role="status"]')
|
|
6
|
+
.should('exist')
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
Then('the AlertBar message has the alert role', () => {
|
|
10
|
+
cy.get('[data-test="dhis2-uicore-alertbar-message"]')
|
|
11
|
+
.find('[role="alert"]')
|
|
12
|
+
.should('exist')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
Then('the icon is hidden from assistive technologies', () => {
|
|
16
|
+
cy.get('[data-test="dhis2-uicore-alertbar-icon"]').should(
|
|
17
|
+
'have.attr',
|
|
18
|
+
'aria-hidden',
|
|
19
|
+
'true'
|
|
20
|
+
)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
Then('the dismiss control is a button labelled "Dismiss"', () => {
|
|
24
|
+
cy.get('[data-test="dhis2-uicore-alertbar-dismiss"]')
|
|
25
|
+
.should('match', 'button')
|
|
26
|
+
.and('have.attr', 'aria-label', 'Dismiss')
|
|
27
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Feature: AlertBar accessibility
|
|
2
|
+
|
|
3
|
+
Scenario: A default AlertBar message is a polite live region
|
|
4
|
+
Given a default AlertBar is rendered
|
|
5
|
+
Then the AlertBar message has the status role
|
|
6
|
+
|
|
7
|
+
Scenario: A critical AlertBar message is an assertive live region
|
|
8
|
+
Given a critical AlertBar is rendered
|
|
9
|
+
Then the AlertBar message has the alert role
|
|
10
|
+
|
|
11
|
+
Scenario: The icon is hidden from assistive technologies
|
|
12
|
+
Given a default AlertBar is rendered
|
|
13
|
+
Then the icon is hidden from assistive technologies
|
|
14
|
+
|
|
15
|
+
Scenario: The dismiss control is a labelled button
|
|
16
|
+
Given a default AlertBar is rendered
|
|
17
|
+
Then the dismiss control is a button labelled "Dismiss"
|
|
@@ -5,6 +5,11 @@ Given('a default AlertBar is rendered', () => {
|
|
|
5
5
|
cy.get('[data-test="dhis2-uicore-alertbar"]').should('be.visible')
|
|
6
6
|
})
|
|
7
7
|
|
|
8
|
+
Given('a critical AlertBar is rendered', () => {
|
|
9
|
+
cy.visitStory('AlertBar', 'Critical')
|
|
10
|
+
cy.get('[data-test="dhis2-uicore-alertbar"]').should('be.visible')
|
|
11
|
+
})
|
|
12
|
+
|
|
8
13
|
Given('the AlertBar is rendered', () => {
|
|
9
14
|
cy.get('[data-test="dhis2-uicore-alertbar"]').should('exist')
|
|
10
15
|
cy.get('[data-test="dhis2-uicore-alertbar"]').should('be.visible')
|
package/src/alert-bar/icon.js
CHANGED
package/src/alert-bar/message.js
CHANGED
|
@@ -1,19 +1,56 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
)
|
|
2
|
+
import React, { useEffect, useState } from 'react'
|
|
3
|
+
|
|
4
|
+
// Screen readers don't announce a role="status" region that has text on
|
|
5
|
+
// mount, so the text is added after a delay. role="alert" is announced on
|
|
6
|
+
// insertion and needs no delay. The visible copy is rendered separately so
|
|
7
|
+
// the delay doesn't shift the layout.
|
|
8
|
+
const ANNOUNCE_DELAY = 100
|
|
9
|
+
|
|
10
|
+
const Message = ({ children, critical, dataTest }) => {
|
|
11
|
+
const [announceable, setAnnounceable] = useState(false)
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (critical) {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const timeout = setTimeout(() => setAnnounceable(true), ANNOUNCE_DELAY)
|
|
19
|
+
|
|
20
|
+
return () => clearTimeout(timeout)
|
|
21
|
+
}, [critical])
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div data-test={dataTest}>
|
|
25
|
+
<span aria-hidden="true">{children}</span>
|
|
26
|
+
<span role={critical ? 'alert' : 'status'} className="live-region">
|
|
27
|
+
{critical || announceable ? children : null}
|
|
28
|
+
</span>
|
|
29
|
+
<style jsx>{`
|
|
30
|
+
div {
|
|
31
|
+
flex-grow: 1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.live-region {
|
|
35
|
+
position: absolute;
|
|
36
|
+
width: 1px;
|
|
37
|
+
height: 1px;
|
|
38
|
+
margin: -1px;
|
|
39
|
+
padding: 0;
|
|
40
|
+
overflow: hidden;
|
|
41
|
+
clip: rect(0, 0, 0, 0);
|
|
42
|
+
white-space: nowrap;
|
|
43
|
+
border: 0;
|
|
44
|
+
}
|
|
45
|
+
`}</style>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
14
49
|
|
|
15
50
|
Message.propTypes = {
|
|
16
51
|
children: PropTypes.string.isRequired,
|
|
52
|
+
dataTest: PropTypes.string.isRequired,
|
|
53
|
+
critical: PropTypes.bool,
|
|
17
54
|
}
|
|
18
55
|
|
|
19
56
|
export { Message }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//------------------------------------------------------------------------------
|
|
2
|
+
// <auto-generated>
|
|
3
|
+
// This code was generated by d2-i18n-generate.
|
|
4
|
+
//
|
|
5
|
+
// Changes to this file may cause incorrect behavior and will be lost if
|
|
6
|
+
// the code is regenerated.
|
|
7
|
+
// </auto-generated>
|
|
8
|
+
//------------------------------------------------------------------------------
|
|
9
|
+
import i18n from '@dhis2/d2-i18n'
|
|
10
|
+
|
|
11
|
+
import enTranslations from './en/translations.json'
|
|
12
|
+
|
|
13
|
+
const namespace = 'default'
|
|
14
|
+
|
|
15
|
+
// Use 'deep' = true and 'overwrite' = false to add to, but not overwrite,
|
|
16
|
+
// custom translations from the datastore (added by the app adapter)
|
|
17
|
+
|
|
18
|
+
i18n.addResourceBundle('en', namespace, enTranslations, true, false)
|
|
19
|
+
i18n.addResourceBundle('en', namespace, enTranslations, true, false)
|
|
20
|
+
|
|
21
|
+
export default i18n
|
package/types/index.d.ts
CHANGED