@blaze-cms/admin 0.146.0-rc-eagle-3.10 → 0.146.0-rc-eagle-3.11
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/lib/components/PageHeader/HeaderIconButton.js +39 -0
- package/lib/components/PageHeader/HeaderIconButton.js.map +1 -0
- package/lib/components/PageHeader/PageHeader.js +81 -24
- package/lib/components/PageHeader/PageHeader.js.map +1 -1
- package/lib/components/PageHeader/TitleEditor.js +88 -0
- package/lib/components/PageHeader/TitleEditor.js.map +1 -0
- package/lib-es/components/PageHeader/HeaderIconButton.js +32 -0
- package/lib-es/components/PageHeader/HeaderIconButton.js.map +1 -0
- package/lib-es/components/PageHeader/PageHeader.js +80 -24
- package/lib-es/components/PageHeader/PageHeader.js.map +1 -1
- package/lib-es/components/PageHeader/TitleEditor.js +80 -0
- package/lib-es/components/PageHeader/TitleEditor.js.map +1 -0
- package/package.json +11 -11
- package/src/components/PageHeader/HeaderIconButton.js +27 -0
- package/src/components/PageHeader/PageHeader.js +90 -19
- package/src/components/PageHeader/TitleEditor.js +88 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
9
|
+
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
10
|
+
var _react = _interopRequireDefault(require("react"));
|
|
11
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
12
|
+
const _excluded = ["icon", "label", "className"];
|
|
13
|
+
const HeaderIconButton = _ref => {
|
|
14
|
+
let {
|
|
15
|
+
icon,
|
|
16
|
+
label,
|
|
17
|
+
className
|
|
18
|
+
} = _ref,
|
|
19
|
+
rest = (0, _objectWithoutProperties2.default)(_ref, _excluded);
|
|
20
|
+
return /*#__PURE__*/_react.default.createElement("button", (0, _extends2.default)({
|
|
21
|
+
type: "button",
|
|
22
|
+
className: `page-header__icon-button${className ? ` ${className}` : ''}`,
|
|
23
|
+
title: label,
|
|
24
|
+
"aria-label": label
|
|
25
|
+
}, rest), /*#__PURE__*/_react.default.createElement("span", {
|
|
26
|
+
className: "material-icons",
|
|
27
|
+
"aria-hidden": "true"
|
|
28
|
+
}, icon));
|
|
29
|
+
};
|
|
30
|
+
HeaderIconButton.propTypes = {
|
|
31
|
+
icon: _propTypes.default.string.isRequired,
|
|
32
|
+
label: _propTypes.default.string.isRequired,
|
|
33
|
+
className: _propTypes.default.string
|
|
34
|
+
};
|
|
35
|
+
HeaderIconButton.defaultProps = {
|
|
36
|
+
className: ''
|
|
37
|
+
};
|
|
38
|
+
var _default = exports.default = HeaderIconButton;
|
|
39
|
+
//# sourceMappingURL=HeaderIconButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeaderIconButton.js","names":["_react","_interopRequireDefault","require","_propTypes","_excluded","HeaderIconButton","_ref","icon","label","className","rest","_objectWithoutProperties2","default","createElement","_extends2","type","title","propTypes","PropTypes","string","isRequired","defaultProps","_default","exports"],"sources":["../../../src/components/PageHeader/HeaderIconButton.js"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst HeaderIconButton = ({ icon, label, className, ...rest }) => (\n <button\n type=\"button\"\n className={`page-header__icon-button${className ? ` ${className}` : ''}`}\n title={label}\n aria-label={label}\n {...rest}>\n <span className=\"material-icons\" aria-hidden=\"true\">\n {icon}\n </span>\n </button>\n);\n\nHeaderIconButton.propTypes = {\n icon: PropTypes.string.isRequired,\n label: PropTypes.string.isRequired,\n className: PropTypes.string\n};\n\nHeaderIconButton.defaultProps = {\n className: ''\n};\n\nexport default HeaderIconButton;\n"],"mappings":";;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,UAAA,GAAAF,sBAAA,CAAAC,OAAA;AAAmC,MAAAE,SAAA;AAEnC,MAAMC,gBAAgB,GAAGC,IAAA;EAAA,IAAC;MAAEC,IAAI;MAAEC,KAAK;MAAEC;IAAmB,CAAC,GAAAH,IAAA;IAANI,IAAI,OAAAC,yBAAA,CAAAC,OAAA,EAAAN,IAAA,EAAAF,SAAA;EAAA,oBACzDJ,MAAA,CAAAY,OAAA,CAAAC,aAAA,eAAAC,SAAA,CAAAF,OAAA;IACEG,IAAI,EAAC,QAAQ;IACbN,SAAS,EAAE,2BAA2BA,SAAS,GAAG,IAAIA,SAAS,EAAE,GAAG,EAAE,EAAG;IACzEO,KAAK,EAAER,KAAM;IACb,cAAYA;EAAM,GACdE,IAAI,gBACRV,MAAA,CAAAY,OAAA,CAAAC,aAAA;IAAMJ,SAAS,EAAC,gBAAgB;IAAC,eAAY;EAAM,GAChDF,IACG,CACA,CAAC;AAAA,CACV;AAEDF,gBAAgB,CAACY,SAAS,GAAG;EAC3BV,IAAI,EAAEW,kBAAS,CAACC,MAAM,CAACC,UAAU;EACjCZ,KAAK,EAAEU,kBAAS,CAACC,MAAM,CAACC,UAAU;EAClCX,SAAS,EAAES,kBAAS,CAACC;AACvB,CAAC;AAEDd,gBAAgB,CAACgB,YAAY,GAAG;EAC9BZ,SAAS,EAAE;AACb,CAAC;AAAC,IAAAa,QAAA,GAAAC,OAAA,CAAAX,OAAA,GAEaP,gBAAgB","ignoreList":[]}
|
|
@@ -5,47 +5,103 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.default = void 0;
|
|
8
|
-
var _react =
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
9
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
10
10
|
var _MetaTitle = _interopRequireDefault(require("../MetaTitle/MetaTitle"));
|
|
11
|
+
var _HeaderIconButton = _interopRequireDefault(require("./HeaderIconButton"));
|
|
12
|
+
var _TitleEditor = _interopRequireDefault(require("./TitleEditor"));
|
|
13
|
+
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); }
|
|
11
14
|
const PageHeader = ({
|
|
12
15
|
title,
|
|
13
16
|
subtitle,
|
|
14
17
|
children,
|
|
15
18
|
pageName,
|
|
16
|
-
onViewUrl
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
19
|
+
onViewUrl,
|
|
20
|
+
viewUrlDisabledReason,
|
|
21
|
+
onTitleChange,
|
|
22
|
+
titleActions
|
|
23
|
+
}) => {
|
|
24
|
+
const [isEditingTitle, setIsEditingTitle] = (0, _react.useState)(false);
|
|
25
|
+
const isTitleEditable = typeof onTitleChange === 'function';
|
|
26
|
+
// A reason renders the button disabled instead of dropping it.
|
|
27
|
+
const showViewButton = !!onViewUrl || !!viewUrlDisabledReason;
|
|
28
|
+
const hasTitleActions = isTitleEditable || !!titleActions || showViewButton;
|
|
29
|
+
const startEditing = () => setIsEditingTitle(true);
|
|
30
|
+
const stopEditing = () => setIsEditingTitle(false);
|
|
31
|
+
const saveTitle = nextTitle => {
|
|
32
|
+
stopEditing();
|
|
33
|
+
onTitleChange(nextTitle);
|
|
34
|
+
};
|
|
35
|
+
const renderTitle = () => {
|
|
36
|
+
if (isEditingTitle) {
|
|
37
|
+
return /*#__PURE__*/_react.default.createElement(_TitleEditor.default, {
|
|
38
|
+
title: title,
|
|
39
|
+
onSave: saveTitle,
|
|
40
|
+
onCancel: stopEditing
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, isTitleEditable ? /*#__PURE__*/_react.default.createElement("div", {
|
|
44
|
+
className: "page-header__heading page-header__heading--editable",
|
|
45
|
+
onClick: startEditing,
|
|
46
|
+
title: "Edit title",
|
|
47
|
+
role: "button",
|
|
48
|
+
tabIndex: 0,
|
|
49
|
+
onKeyDown: ({
|
|
50
|
+
key
|
|
51
|
+
}) => key === 'Enter' && startEditing()
|
|
52
|
+
}, title) : /*#__PURE__*/_react.default.createElement("div", {
|
|
53
|
+
className: "page-header__heading"
|
|
54
|
+
}, title), hasTitleActions && /*#__PURE__*/_react.default.createElement("div", {
|
|
55
|
+
className: "page-header__title-actions"
|
|
56
|
+
}, isTitleEditable && /*#__PURE__*/_react.default.createElement(_HeaderIconButton.default, {
|
|
57
|
+
icon: "edit",
|
|
58
|
+
label: "Edit title",
|
|
59
|
+
onClick: startEditing,
|
|
60
|
+
"data-testid": "page-header-title-edit"
|
|
61
|
+
}), titleActions, showViewButton && /*#__PURE__*/_react.default.createElement(_HeaderIconButton.default, {
|
|
62
|
+
icon: "open_in_new",
|
|
63
|
+
label: viewUrlDisabledReason || 'View',
|
|
64
|
+
className: viewUrlDisabledReason ? 'page-header__icon-button--disabled' : '',
|
|
65
|
+
"aria-disabled": viewUrlDisabledReason ? 'true' : undefined,
|
|
66
|
+
onClick: viewUrlDisabledReason ? undefined : onViewUrl,
|
|
67
|
+
"data-testid": "page-header-view"
|
|
68
|
+
})));
|
|
69
|
+
};
|
|
70
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_MetaTitle.default, {
|
|
71
|
+
title: title,
|
|
72
|
+
pageName: pageName
|
|
73
|
+
}), /*#__PURE__*/_react.default.createElement("div", {
|
|
74
|
+
className: "page-header--wrapper"
|
|
75
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
76
|
+
className: "page-header page-header--sticky"
|
|
77
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
78
|
+
className: "page-header__title"
|
|
79
|
+
}, renderTitle()), /*#__PURE__*/_react.default.createElement("div", {
|
|
80
|
+
className: "page-header__button"
|
|
81
|
+
}, children)), /*#__PURE__*/_react.default.createElement("div", {
|
|
82
|
+
className: "page-header page-header--base"
|
|
83
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
84
|
+
className: "page-header__subheading"
|
|
85
|
+
}, subtitle))));
|
|
86
|
+
};
|
|
37
87
|
PageHeader.propTypes = {
|
|
38
88
|
title: _propTypes.default.string.isRequired,
|
|
39
89
|
subtitle: _propTypes.default.string,
|
|
40
90
|
children: _propTypes.default.oneOfType([_propTypes.default.array, _propTypes.default.object, _propTypes.default.string]),
|
|
41
91
|
pageName: _propTypes.default.string,
|
|
42
|
-
onViewUrl: _propTypes.default.func
|
|
92
|
+
onViewUrl: _propTypes.default.func,
|
|
93
|
+
viewUrlDisabledReason: _propTypes.default.string,
|
|
94
|
+
onTitleChange: _propTypes.default.func,
|
|
95
|
+
titleActions: _propTypes.default.node
|
|
43
96
|
};
|
|
44
97
|
PageHeader.defaultProps = {
|
|
45
98
|
subtitle: '',
|
|
46
99
|
children: '',
|
|
47
100
|
pageName: '',
|
|
48
|
-
onViewUrl: null
|
|
101
|
+
onViewUrl: null,
|
|
102
|
+
viewUrlDisabledReason: null,
|
|
103
|
+
onTitleChange: null,
|
|
104
|
+
titleActions: null
|
|
49
105
|
};
|
|
50
106
|
const PageHeaderActions = ({
|
|
51
107
|
children
|
|
@@ -54,5 +110,6 @@ PageHeaderActions.propTypes = {
|
|
|
54
110
|
children: _propTypes.default.oneOfType([_propTypes.default.array, _propTypes.default.object]).isRequired
|
|
55
111
|
};
|
|
56
112
|
PageHeader.Actions = PageHeaderActions;
|
|
113
|
+
PageHeader.IconButton = _HeaderIconButton.default;
|
|
57
114
|
var _default = exports.default = PageHeader;
|
|
58
115
|
//# sourceMappingURL=PageHeader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeader.js","names":["_react","
|
|
1
|
+
{"version":3,"file":"PageHeader.js","names":["_react","_interopRequireWildcard","require","_propTypes","_interopRequireDefault","_MetaTitle","_HeaderIconButton","_TitleEditor","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","PageHeader","title","subtitle","children","pageName","onViewUrl","viewUrlDisabledReason","onTitleChange","titleActions","isEditingTitle","setIsEditingTitle","useState","isTitleEditable","showViewButton","hasTitleActions","startEditing","stopEditing","saveTitle","nextTitle","renderTitle","createElement","onSave","onCancel","Fragment","className","onClick","role","tabIndex","onKeyDown","key","icon","label","undefined","propTypes","PropTypes","string","isRequired","oneOfType","array","object","func","node","defaultProps","PageHeaderActions","React","Children","map","child","cloneElement","Actions","IconButton","HeaderIconButton","_default","exports"],"sources":["../../../src/components/PageHeader/PageHeader.js"],"sourcesContent":["import React, { useState } from 'react';\nimport PropTypes from 'prop-types';\nimport MetaTitle from '../MetaTitle/MetaTitle';\nimport HeaderIconButton from './HeaderIconButton';\nimport TitleEditor from './TitleEditor';\n\nconst PageHeader = ({\n title,\n subtitle,\n children,\n pageName,\n onViewUrl,\n viewUrlDisabledReason,\n onTitleChange,\n titleActions\n}) => {\n const [isEditingTitle, setIsEditingTitle] = useState(false);\n const isTitleEditable = typeof onTitleChange === 'function';\n // A reason renders the button disabled instead of dropping it.\n const showViewButton = !!onViewUrl || !!viewUrlDisabledReason;\n const hasTitleActions = isTitleEditable || !!titleActions || showViewButton;\n\n const startEditing = () => setIsEditingTitle(true);\n const stopEditing = () => setIsEditingTitle(false);\n const saveTitle = nextTitle => {\n stopEditing();\n onTitleChange(nextTitle);\n };\n\n const renderTitle = () => {\n if (isEditingTitle) {\n return <TitleEditor title={title} onSave={saveTitle} onCancel={stopEditing} />;\n }\n\n return (\n <>\n {isTitleEditable ? (\n <div\n className=\"page-header__heading page-header__heading--editable\"\n onClick={startEditing}\n title=\"Edit title\"\n role=\"button\"\n tabIndex={0}\n onKeyDown={({ key }) => key === 'Enter' && startEditing()}>\n {title}\n </div>\n ) : (\n <div className=\"page-header__heading\">{title}</div>\n )}\n {hasTitleActions && (\n <div className=\"page-header__title-actions\">\n {isTitleEditable && (\n <HeaderIconButton\n icon=\"edit\"\n label=\"Edit title\"\n onClick={startEditing}\n data-testid=\"page-header-title-edit\"\n />\n )}\n {titleActions}\n {showViewButton && (\n <HeaderIconButton\n icon=\"open_in_new\"\n label={viewUrlDisabledReason || 'View'}\n className={viewUrlDisabledReason ? 'page-header__icon-button--disabled' : ''}\n aria-disabled={viewUrlDisabledReason ? 'true' : undefined}\n onClick={viewUrlDisabledReason ? undefined : onViewUrl}\n data-testid=\"page-header-view\"\n />\n )}\n </div>\n )}\n </>\n );\n };\n\n return (\n <>\n <MetaTitle title={title} pageName={pageName} />\n <div className=\"page-header--wrapper\">\n <div className=\"page-header page-header--sticky\">\n <div className=\"page-header__title\">{renderTitle()}</div>\n <div className=\"page-header__button\">{children}</div>\n </div>\n <div className=\"page-header page-header--base\">\n <div className=\"page-header__subheading\">{subtitle}</div>\n </div>\n </div>\n </>\n );\n};\n\nPageHeader.propTypes = {\n title: PropTypes.string.isRequired,\n subtitle: PropTypes.string,\n children: PropTypes.oneOfType([PropTypes.array, PropTypes.object, PropTypes.string]),\n pageName: PropTypes.string,\n onViewUrl: PropTypes.func,\n viewUrlDisabledReason: PropTypes.string,\n onTitleChange: PropTypes.func,\n titleActions: PropTypes.node\n};\n\nPageHeader.defaultProps = {\n subtitle: '',\n children: '',\n pageName: '',\n onViewUrl: null,\n viewUrlDisabledReason: null,\n onTitleChange: null,\n titleActions: null\n};\n\nconst PageHeaderActions = ({ children }) => (\n <>{React.Children.map(children, child => child && React.cloneElement(child))}</>\n);\n\nPageHeaderActions.propTypes = {\n children: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired\n};\n\nPageHeader.Actions = PageHeaderActions;\nPageHeader.IconButton = HeaderIconButton;\n\nexport default PageHeader;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
10
|
+
var _HeaderIconButton = _interopRequireDefault(require("./HeaderIconButton"));
|
|
11
|
+
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); }
|
|
12
|
+
const TitleEditor = ({
|
|
13
|
+
title,
|
|
14
|
+
onSave,
|
|
15
|
+
onCancel
|
|
16
|
+
}) => {
|
|
17
|
+
const [value, setValue] = (0, _react.useState)(title);
|
|
18
|
+
const inputRef = (0, _react.useRef)(null);
|
|
19
|
+
// Blur and the tick/cross clicks can both fire for one edit; only the first wins.
|
|
20
|
+
// Blur discards: a change is only kept through Enter or the tick.
|
|
21
|
+
const isDone = (0, _react.useRef)(false);
|
|
22
|
+
(0, _react.useEffect)(() => {
|
|
23
|
+
if (inputRef.current) {
|
|
24
|
+
inputRef.current.focus();
|
|
25
|
+
inputRef.current.select();
|
|
26
|
+
}
|
|
27
|
+
}, []);
|
|
28
|
+
const finish = callback => {
|
|
29
|
+
if (isDone.current) return;
|
|
30
|
+
isDone.current = true;
|
|
31
|
+
callback();
|
|
32
|
+
};
|
|
33
|
+
const save = () => finish(() => {
|
|
34
|
+
const nextTitle = value.trim();
|
|
35
|
+
if (!nextTitle || nextTitle === title) {
|
|
36
|
+
onCancel();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
onSave(nextTitle);
|
|
40
|
+
});
|
|
41
|
+
const cancel = () => finish(onCancel);
|
|
42
|
+
const onKeyDown = event => {
|
|
43
|
+
if (event.key === 'Enter') {
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
save();
|
|
46
|
+
} else if (event.key === 'Escape') {
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
cancel();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const keepInputFocus = event => event.preventDefault();
|
|
52
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
53
|
+
className: "page-header__title-editor"
|
|
54
|
+
}, /*#__PURE__*/_react.default.createElement("input", {
|
|
55
|
+
ref: inputRef,
|
|
56
|
+
type: "text",
|
|
57
|
+
className: "page-header__title-input",
|
|
58
|
+
value: value,
|
|
59
|
+
onChange: ({
|
|
60
|
+
target
|
|
61
|
+
}) => setValue(target.value),
|
|
62
|
+
onKeyDown: onKeyDown,
|
|
63
|
+
onBlur: cancel,
|
|
64
|
+
"aria-label": "Title",
|
|
65
|
+
"data-testid": "page-header-title-input"
|
|
66
|
+
}), /*#__PURE__*/_react.default.createElement("div", {
|
|
67
|
+
className: "page-header__title-editor-actions"
|
|
68
|
+
}, /*#__PURE__*/_react.default.createElement(_HeaderIconButton.default, {
|
|
69
|
+
icon: "check",
|
|
70
|
+
label: "Save title",
|
|
71
|
+
onMouseDown: keepInputFocus,
|
|
72
|
+
onClick: save,
|
|
73
|
+
"data-testid": "page-header-title-save"
|
|
74
|
+
}), /*#__PURE__*/_react.default.createElement(_HeaderIconButton.default, {
|
|
75
|
+
icon: "close",
|
|
76
|
+
label: "Cancel",
|
|
77
|
+
onMouseDown: keepInputFocus,
|
|
78
|
+
onClick: cancel,
|
|
79
|
+
"data-testid": "page-header-title-cancel"
|
|
80
|
+
})));
|
|
81
|
+
};
|
|
82
|
+
TitleEditor.propTypes = {
|
|
83
|
+
title: _propTypes.default.string.isRequired,
|
|
84
|
+
onSave: _propTypes.default.func.isRequired,
|
|
85
|
+
onCancel: _propTypes.default.func.isRequired
|
|
86
|
+
};
|
|
87
|
+
var _default = exports.default = TitleEditor;
|
|
88
|
+
//# sourceMappingURL=TitleEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TitleEditor.js","names":["_react","_interopRequireWildcard","require","_propTypes","_interopRequireDefault","_HeaderIconButton","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","TitleEditor","title","onSave","onCancel","value","setValue","useState","inputRef","useRef","isDone","useEffect","current","focus","select","finish","callback","save","nextTitle","trim","cancel","onKeyDown","event","key","preventDefault","keepInputFocus","createElement","className","ref","type","onChange","target","onBlur","icon","label","onMouseDown","onClick","propTypes","PropTypes","string","isRequired","func","_default","exports"],"sources":["../../../src/components/PageHeader/TitleEditor.js"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport HeaderIconButton from './HeaderIconButton';\n\nconst TitleEditor = ({ title, onSave, onCancel }) => {\n const [value, setValue] = useState(title);\n const inputRef = useRef(null);\n // Blur and the tick/cross clicks can both fire for one edit; only the first wins.\n // Blur discards: a change is only kept through Enter or the tick.\n const isDone = useRef(false);\n\n useEffect(() => {\n if (inputRef.current) {\n inputRef.current.focus();\n inputRef.current.select();\n }\n }, []);\n\n const finish = callback => {\n if (isDone.current) return;\n isDone.current = true;\n callback();\n };\n\n const save = () =>\n finish(() => {\n const nextTitle = value.trim();\n if (!nextTitle || nextTitle === title) {\n onCancel();\n return;\n }\n onSave(nextTitle);\n });\n\n const cancel = () => finish(onCancel);\n\n const onKeyDown = event => {\n if (event.key === 'Enter') {\n event.preventDefault();\n save();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n cancel();\n }\n };\n\n const keepInputFocus = event => event.preventDefault();\n\n return (\n <div className=\"page-header__title-editor\">\n <input\n ref={inputRef}\n type=\"text\"\n className=\"page-header__title-input\"\n value={value}\n onChange={({ target }) => setValue(target.value)}\n onKeyDown={onKeyDown}\n onBlur={cancel}\n aria-label=\"Title\"\n data-testid=\"page-header-title-input\"\n />\n <div className=\"page-header__title-editor-actions\">\n <HeaderIconButton\n icon=\"check\"\n label=\"Save title\"\n onMouseDown={keepInputFocus}\n onClick={save}\n data-testid=\"page-header-title-save\"\n />\n <HeaderIconButton\n icon=\"close\"\n label=\"Cancel\"\n onMouseDown={keepInputFocus}\n onClick={cancel}\n data-testid=\"page-header-title-cancel\"\n />\n </div>\n </div>\n );\n};\n\nTitleEditor.propTypes = {\n title: PropTypes.string.isRequired,\n onSave: PropTypes.func.isRequired,\n onCancel: PropTypes.func.isRequired\n};\n\nexport default TitleEditor;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
3
|
+
const _excluded = ["icon", "label", "className"];
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
const HeaderIconButton = _ref => {
|
|
7
|
+
let {
|
|
8
|
+
icon,
|
|
9
|
+
label,
|
|
10
|
+
className
|
|
11
|
+
} = _ref,
|
|
12
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
13
|
+
return /*#__PURE__*/React.createElement("button", _extends({
|
|
14
|
+
type: "button",
|
|
15
|
+
className: `page-header__icon-button${className ? ` ${className}` : ''}`,
|
|
16
|
+
title: label,
|
|
17
|
+
"aria-label": label
|
|
18
|
+
}, rest), /*#__PURE__*/React.createElement("span", {
|
|
19
|
+
className: "material-icons",
|
|
20
|
+
"aria-hidden": "true"
|
|
21
|
+
}, icon));
|
|
22
|
+
};
|
|
23
|
+
HeaderIconButton.propTypes = {
|
|
24
|
+
icon: PropTypes.string.isRequired,
|
|
25
|
+
label: PropTypes.string.isRequired,
|
|
26
|
+
className: PropTypes.string
|
|
27
|
+
};
|
|
28
|
+
HeaderIconButton.defaultProps = {
|
|
29
|
+
className: ''
|
|
30
|
+
};
|
|
31
|
+
export default HeaderIconButton;
|
|
32
|
+
//# sourceMappingURL=HeaderIconButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeaderIconButton.js","names":["React","PropTypes","HeaderIconButton","_ref","icon","label","className","rest","_objectWithoutProperties","_excluded","createElement","_extends","type","title","propTypes","string","isRequired","defaultProps"],"sources":["../../../src/components/PageHeader/HeaderIconButton.js"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst HeaderIconButton = ({ icon, label, className, ...rest }) => (\n <button\n type=\"button\"\n className={`page-header__icon-button${className ? ` ${className}` : ''}`}\n title={label}\n aria-label={label}\n {...rest}>\n <span className=\"material-icons\" aria-hidden=\"true\">\n {icon}\n </span>\n </button>\n);\n\nHeaderIconButton.propTypes = {\n icon: PropTypes.string.isRequired,\n label: PropTypes.string.isRequired,\n className: PropTypes.string\n};\n\nHeaderIconButton.defaultProps = {\n className: ''\n};\n\nexport default HeaderIconButton;\n"],"mappings":";;;AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,OAAOC,SAAS,MAAM,YAAY;AAElC,MAAMC,gBAAgB,GAAGC,IAAA;EAAA,IAAC;MAAEC,IAAI;MAAEC,KAAK;MAAEC;IAAmB,CAAC,GAAAH,IAAA;IAANI,IAAI,GAAAC,wBAAA,CAAAL,IAAA,EAAAM,SAAA;EAAA,oBACzDT,KAAA,CAAAU,aAAA,WAAAC,QAAA;IACEC,IAAI,EAAC,QAAQ;IACbN,SAAS,EAAE,2BAA2BA,SAAS,GAAG,IAAIA,SAAS,EAAE,GAAG,EAAE,EAAG;IACzEO,KAAK,EAAER,KAAM;IACb,cAAYA;EAAM,GACdE,IAAI,gBACRP,KAAA,CAAAU,aAAA;IAAMJ,SAAS,EAAC,gBAAgB;IAAC,eAAY;EAAM,GAChDF,IACG,CACA,CAAC;AAAA,CACV;AAEDF,gBAAgB,CAACY,SAAS,GAAG;EAC3BV,IAAI,EAAEH,SAAS,CAACc,MAAM,CAACC,UAAU;EACjCX,KAAK,EAAEJ,SAAS,CAACc,MAAM,CAACC,UAAU;EAClCV,SAAS,EAAEL,SAAS,CAACc;AACvB,CAAC;AAEDb,gBAAgB,CAACe,YAAY,GAAG;EAC9BX,SAAS,EAAE;AACb,CAAC;AAED,eAAeJ,gBAAgB","ignoreList":[]}
|
|
@@ -1,44 +1,99 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import MetaTitle from '../MetaTitle/MetaTitle';
|
|
4
|
+
import HeaderIconButton from './HeaderIconButton';
|
|
5
|
+
import TitleEditor from './TitleEditor';
|
|
4
6
|
const PageHeader = ({
|
|
5
7
|
title,
|
|
6
8
|
subtitle,
|
|
7
9
|
children,
|
|
8
10
|
pageName,
|
|
9
|
-
onViewUrl
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
11
|
+
onViewUrl,
|
|
12
|
+
viewUrlDisabledReason,
|
|
13
|
+
onTitleChange,
|
|
14
|
+
titleActions
|
|
15
|
+
}) => {
|
|
16
|
+
const [isEditingTitle, setIsEditingTitle] = useState(false);
|
|
17
|
+
const isTitleEditable = typeof onTitleChange === 'function';
|
|
18
|
+
// A reason renders the button disabled instead of dropping it.
|
|
19
|
+
const showViewButton = !!onViewUrl || !!viewUrlDisabledReason;
|
|
20
|
+
const hasTitleActions = isTitleEditable || !!titleActions || showViewButton;
|
|
21
|
+
const startEditing = () => setIsEditingTitle(true);
|
|
22
|
+
const stopEditing = () => setIsEditingTitle(false);
|
|
23
|
+
const saveTitle = nextTitle => {
|
|
24
|
+
stopEditing();
|
|
25
|
+
onTitleChange(nextTitle);
|
|
26
|
+
};
|
|
27
|
+
const renderTitle = () => {
|
|
28
|
+
if (isEditingTitle) {
|
|
29
|
+
return /*#__PURE__*/React.createElement(TitleEditor, {
|
|
30
|
+
title: title,
|
|
31
|
+
onSave: saveTitle,
|
|
32
|
+
onCancel: stopEditing
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, isTitleEditable ? /*#__PURE__*/React.createElement("div", {
|
|
36
|
+
className: "page-header__heading page-header__heading--editable",
|
|
37
|
+
onClick: startEditing,
|
|
38
|
+
title: "Edit title",
|
|
39
|
+
role: "button",
|
|
40
|
+
tabIndex: 0,
|
|
41
|
+
onKeyDown: ({
|
|
42
|
+
key
|
|
43
|
+
}) => key === 'Enter' && startEditing()
|
|
44
|
+
}, title) : /*#__PURE__*/React.createElement("div", {
|
|
45
|
+
className: "page-header__heading"
|
|
46
|
+
}, title), hasTitleActions && /*#__PURE__*/React.createElement("div", {
|
|
47
|
+
className: "page-header__title-actions"
|
|
48
|
+
}, isTitleEditable && /*#__PURE__*/React.createElement(HeaderIconButton, {
|
|
49
|
+
icon: "edit",
|
|
50
|
+
label: "Edit title",
|
|
51
|
+
onClick: startEditing,
|
|
52
|
+
"data-testid": "page-header-title-edit"
|
|
53
|
+
}), titleActions, showViewButton && /*#__PURE__*/React.createElement(HeaderIconButton, {
|
|
54
|
+
icon: "open_in_new",
|
|
55
|
+
label: viewUrlDisabledReason || 'View',
|
|
56
|
+
className: viewUrlDisabledReason ? 'page-header__icon-button--disabled' : '',
|
|
57
|
+
"aria-disabled": viewUrlDisabledReason ? 'true' : undefined,
|
|
58
|
+
onClick: viewUrlDisabledReason ? undefined : onViewUrl,
|
|
59
|
+
"data-testid": "page-header-view"
|
|
60
|
+
})));
|
|
61
|
+
};
|
|
62
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MetaTitle, {
|
|
63
|
+
title: title,
|
|
64
|
+
pageName: pageName
|
|
65
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
66
|
+
className: "page-header--wrapper"
|
|
67
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
68
|
+
className: "page-header page-header--sticky"
|
|
69
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
70
|
+
className: "page-header__title"
|
|
71
|
+
}, renderTitle()), /*#__PURE__*/React.createElement("div", {
|
|
72
|
+
className: "page-header__button"
|
|
73
|
+
}, children)), /*#__PURE__*/React.createElement("div", {
|
|
74
|
+
className: "page-header page-header--base"
|
|
75
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
76
|
+
className: "page-header__subheading"
|
|
77
|
+
}, subtitle))));
|
|
78
|
+
};
|
|
30
79
|
PageHeader.propTypes = {
|
|
31
80
|
title: PropTypes.string.isRequired,
|
|
32
81
|
subtitle: PropTypes.string,
|
|
33
82
|
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object, PropTypes.string]),
|
|
34
83
|
pageName: PropTypes.string,
|
|
35
|
-
onViewUrl: PropTypes.func
|
|
84
|
+
onViewUrl: PropTypes.func,
|
|
85
|
+
viewUrlDisabledReason: PropTypes.string,
|
|
86
|
+
onTitleChange: PropTypes.func,
|
|
87
|
+
titleActions: PropTypes.node
|
|
36
88
|
};
|
|
37
89
|
PageHeader.defaultProps = {
|
|
38
90
|
subtitle: '',
|
|
39
91
|
children: '',
|
|
40
92
|
pageName: '',
|
|
41
|
-
onViewUrl: null
|
|
93
|
+
onViewUrl: null,
|
|
94
|
+
viewUrlDisabledReason: null,
|
|
95
|
+
onTitleChange: null,
|
|
96
|
+
titleActions: null
|
|
42
97
|
};
|
|
43
98
|
const PageHeaderActions = ({
|
|
44
99
|
children
|
|
@@ -47,5 +102,6 @@ PageHeaderActions.propTypes = {
|
|
|
47
102
|
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired
|
|
48
103
|
};
|
|
49
104
|
PageHeader.Actions = PageHeaderActions;
|
|
105
|
+
PageHeader.IconButton = HeaderIconButton;
|
|
50
106
|
export default PageHeader;
|
|
51
107
|
//# sourceMappingURL=PageHeader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeader.js","names":["React","PropTypes","MetaTitle","PageHeader","title","subtitle","children","pageName","onViewUrl","createElement","Fragment","className","onClick","role","propTypes","string","isRequired","oneOfType","array","object","func","defaultProps","PageHeaderActions","Children","map","child","cloneElement","Actions"],"sources":["../../../src/components/PageHeader/PageHeader.js"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport MetaTitle from '../MetaTitle/MetaTitle';\n\nconst PageHeader = ({
|
|
1
|
+
{"version":3,"file":"PageHeader.js","names":["React","useState","PropTypes","MetaTitle","HeaderIconButton","TitleEditor","PageHeader","title","subtitle","children","pageName","onViewUrl","viewUrlDisabledReason","onTitleChange","titleActions","isEditingTitle","setIsEditingTitle","isTitleEditable","showViewButton","hasTitleActions","startEditing","stopEditing","saveTitle","nextTitle","renderTitle","createElement","onSave","onCancel","Fragment","className","onClick","role","tabIndex","onKeyDown","key","icon","label","undefined","propTypes","string","isRequired","oneOfType","array","object","func","node","defaultProps","PageHeaderActions","Children","map","child","cloneElement","Actions","IconButton"],"sources":["../../../src/components/PageHeader/PageHeader.js"],"sourcesContent":["import React, { useState } from 'react';\nimport PropTypes from 'prop-types';\nimport MetaTitle from '../MetaTitle/MetaTitle';\nimport HeaderIconButton from './HeaderIconButton';\nimport TitleEditor from './TitleEditor';\n\nconst PageHeader = ({\n title,\n subtitle,\n children,\n pageName,\n onViewUrl,\n viewUrlDisabledReason,\n onTitleChange,\n titleActions\n}) => {\n const [isEditingTitle, setIsEditingTitle] = useState(false);\n const isTitleEditable = typeof onTitleChange === 'function';\n // A reason renders the button disabled instead of dropping it.\n const showViewButton = !!onViewUrl || !!viewUrlDisabledReason;\n const hasTitleActions = isTitleEditable || !!titleActions || showViewButton;\n\n const startEditing = () => setIsEditingTitle(true);\n const stopEditing = () => setIsEditingTitle(false);\n const saveTitle = nextTitle => {\n stopEditing();\n onTitleChange(nextTitle);\n };\n\n const renderTitle = () => {\n if (isEditingTitle) {\n return <TitleEditor title={title} onSave={saveTitle} onCancel={stopEditing} />;\n }\n\n return (\n <>\n {isTitleEditable ? (\n <div\n className=\"page-header__heading page-header__heading--editable\"\n onClick={startEditing}\n title=\"Edit title\"\n role=\"button\"\n tabIndex={0}\n onKeyDown={({ key }) => key === 'Enter' && startEditing()}>\n {title}\n </div>\n ) : (\n <div className=\"page-header__heading\">{title}</div>\n )}\n {hasTitleActions && (\n <div className=\"page-header__title-actions\">\n {isTitleEditable && (\n <HeaderIconButton\n icon=\"edit\"\n label=\"Edit title\"\n onClick={startEditing}\n data-testid=\"page-header-title-edit\"\n />\n )}\n {titleActions}\n {showViewButton && (\n <HeaderIconButton\n icon=\"open_in_new\"\n label={viewUrlDisabledReason || 'View'}\n className={viewUrlDisabledReason ? 'page-header__icon-button--disabled' : ''}\n aria-disabled={viewUrlDisabledReason ? 'true' : undefined}\n onClick={viewUrlDisabledReason ? undefined : onViewUrl}\n data-testid=\"page-header-view\"\n />\n )}\n </div>\n )}\n </>\n );\n };\n\n return (\n <>\n <MetaTitle title={title} pageName={pageName} />\n <div className=\"page-header--wrapper\">\n <div className=\"page-header page-header--sticky\">\n <div className=\"page-header__title\">{renderTitle()}</div>\n <div className=\"page-header__button\">{children}</div>\n </div>\n <div className=\"page-header page-header--base\">\n <div className=\"page-header__subheading\">{subtitle}</div>\n </div>\n </div>\n </>\n );\n};\n\nPageHeader.propTypes = {\n title: PropTypes.string.isRequired,\n subtitle: PropTypes.string,\n children: PropTypes.oneOfType([PropTypes.array, PropTypes.object, PropTypes.string]),\n pageName: PropTypes.string,\n onViewUrl: PropTypes.func,\n viewUrlDisabledReason: PropTypes.string,\n onTitleChange: PropTypes.func,\n titleActions: PropTypes.node\n};\n\nPageHeader.defaultProps = {\n subtitle: '',\n children: '',\n pageName: '',\n onViewUrl: null,\n viewUrlDisabledReason: null,\n onTitleChange: null,\n titleActions: null\n};\n\nconst PageHeaderActions = ({ children }) => (\n <>{React.Children.map(children, child => child && React.cloneElement(child))}</>\n);\n\nPageHeaderActions.propTypes = {\n children: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired\n};\n\nPageHeader.Actions = PageHeaderActions;\nPageHeader.IconButton = HeaderIconButton;\n\nexport default PageHeader;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import HeaderIconButton from './HeaderIconButton';
|
|
4
|
+
const TitleEditor = ({
|
|
5
|
+
title,
|
|
6
|
+
onSave,
|
|
7
|
+
onCancel
|
|
8
|
+
}) => {
|
|
9
|
+
const [value, setValue] = useState(title);
|
|
10
|
+
const inputRef = useRef(null);
|
|
11
|
+
// Blur and the tick/cross clicks can both fire for one edit; only the first wins.
|
|
12
|
+
// Blur discards: a change is only kept through Enter or the tick.
|
|
13
|
+
const isDone = useRef(false);
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (inputRef.current) {
|
|
16
|
+
inputRef.current.focus();
|
|
17
|
+
inputRef.current.select();
|
|
18
|
+
}
|
|
19
|
+
}, []);
|
|
20
|
+
const finish = callback => {
|
|
21
|
+
if (isDone.current) return;
|
|
22
|
+
isDone.current = true;
|
|
23
|
+
callback();
|
|
24
|
+
};
|
|
25
|
+
const save = () => finish(() => {
|
|
26
|
+
const nextTitle = value.trim();
|
|
27
|
+
if (!nextTitle || nextTitle === title) {
|
|
28
|
+
onCancel();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
onSave(nextTitle);
|
|
32
|
+
});
|
|
33
|
+
const cancel = () => finish(onCancel);
|
|
34
|
+
const onKeyDown = event => {
|
|
35
|
+
if (event.key === 'Enter') {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
save();
|
|
38
|
+
} else if (event.key === 'Escape') {
|
|
39
|
+
event.preventDefault();
|
|
40
|
+
cancel();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const keepInputFocus = event => event.preventDefault();
|
|
44
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
45
|
+
className: "page-header__title-editor"
|
|
46
|
+
}, /*#__PURE__*/React.createElement("input", {
|
|
47
|
+
ref: inputRef,
|
|
48
|
+
type: "text",
|
|
49
|
+
className: "page-header__title-input",
|
|
50
|
+
value: value,
|
|
51
|
+
onChange: ({
|
|
52
|
+
target
|
|
53
|
+
}) => setValue(target.value),
|
|
54
|
+
onKeyDown: onKeyDown,
|
|
55
|
+
onBlur: cancel,
|
|
56
|
+
"aria-label": "Title",
|
|
57
|
+
"data-testid": "page-header-title-input"
|
|
58
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
59
|
+
className: "page-header__title-editor-actions"
|
|
60
|
+
}, /*#__PURE__*/React.createElement(HeaderIconButton, {
|
|
61
|
+
icon: "check",
|
|
62
|
+
label: "Save title",
|
|
63
|
+
onMouseDown: keepInputFocus,
|
|
64
|
+
onClick: save,
|
|
65
|
+
"data-testid": "page-header-title-save"
|
|
66
|
+
}), /*#__PURE__*/React.createElement(HeaderIconButton, {
|
|
67
|
+
icon: "close",
|
|
68
|
+
label: "Cancel",
|
|
69
|
+
onMouseDown: keepInputFocus,
|
|
70
|
+
onClick: cancel,
|
|
71
|
+
"data-testid": "page-header-title-cancel"
|
|
72
|
+
})));
|
|
73
|
+
};
|
|
74
|
+
TitleEditor.propTypes = {
|
|
75
|
+
title: PropTypes.string.isRequired,
|
|
76
|
+
onSave: PropTypes.func.isRequired,
|
|
77
|
+
onCancel: PropTypes.func.isRequired
|
|
78
|
+
};
|
|
79
|
+
export default TitleEditor;
|
|
80
|
+
//# sourceMappingURL=TitleEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TitleEditor.js","names":["React","useEffect","useRef","useState","PropTypes","HeaderIconButton","TitleEditor","title","onSave","onCancel","value","setValue","inputRef","isDone","current","focus","select","finish","callback","save","nextTitle","trim","cancel","onKeyDown","event","key","preventDefault","keepInputFocus","createElement","className","ref","type","onChange","target","onBlur","icon","label","onMouseDown","onClick","propTypes","string","isRequired","func"],"sources":["../../../src/components/PageHeader/TitleEditor.js"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport HeaderIconButton from './HeaderIconButton';\n\nconst TitleEditor = ({ title, onSave, onCancel }) => {\n const [value, setValue] = useState(title);\n const inputRef = useRef(null);\n // Blur and the tick/cross clicks can both fire for one edit; only the first wins.\n // Blur discards: a change is only kept through Enter or the tick.\n const isDone = useRef(false);\n\n useEffect(() => {\n if (inputRef.current) {\n inputRef.current.focus();\n inputRef.current.select();\n }\n }, []);\n\n const finish = callback => {\n if (isDone.current) return;\n isDone.current = true;\n callback();\n };\n\n const save = () =>\n finish(() => {\n const nextTitle = value.trim();\n if (!nextTitle || nextTitle === title) {\n onCancel();\n return;\n }\n onSave(nextTitle);\n });\n\n const cancel = () => finish(onCancel);\n\n const onKeyDown = event => {\n if (event.key === 'Enter') {\n event.preventDefault();\n save();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n cancel();\n }\n };\n\n const keepInputFocus = event => event.preventDefault();\n\n return (\n <div className=\"page-header__title-editor\">\n <input\n ref={inputRef}\n type=\"text\"\n className=\"page-header__title-input\"\n value={value}\n onChange={({ target }) => setValue(target.value)}\n onKeyDown={onKeyDown}\n onBlur={cancel}\n aria-label=\"Title\"\n data-testid=\"page-header-title-input\"\n />\n <div className=\"page-header__title-editor-actions\">\n <HeaderIconButton\n icon=\"check\"\n label=\"Save title\"\n onMouseDown={keepInputFocus}\n onClick={save}\n data-testid=\"page-header-title-save\"\n />\n <HeaderIconButton\n icon=\"close\"\n label=\"Cancel\"\n onMouseDown={keepInputFocus}\n onClick={cancel}\n data-testid=\"page-header-title-cancel\"\n />\n </div>\n </div>\n );\n};\n\nTitleEditor.propTypes = {\n title: PropTypes.string.isRequired,\n onSave: PropTypes.func.isRequired,\n onCancel: PropTypes.func.isRequired\n};\n\nexport default TitleEditor;\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blaze-cms/admin",
|
|
3
|
-
"version": "0.146.0-rc-eagle-3.
|
|
3
|
+
"version": "0.146.0-rc-eagle-3.11",
|
|
4
4
|
"description": "Blaze example project",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib-es/index.js",
|
|
@@ -36,15 +36,15 @@
|
|
|
36
36
|
"@blaze-cms/admin-ui-utils": "0.146.0-rc-eagle-3.10",
|
|
37
37
|
"@blaze-cms/core-errors-ui": "0.146.0-rc-eagle-3.0",
|
|
38
38
|
"@blaze-cms/core-ui": "0.146.0-rc-eagle-3.6",
|
|
39
|
-
"@blaze-cms/plugin-admin-core-ui": "0.146.0-rc-eagle-3.
|
|
40
|
-
"@blaze-cms/plugin-auth-local-ui": "0.146.0-rc-eagle-3.
|
|
41
|
-
"@blaze-cms/plugin-auth-ui": "0.146.0-rc-eagle-3.
|
|
42
|
-
"@blaze-cms/plugin-data-ui": "0.146.0-rc-eagle-3.
|
|
43
|
-
"@blaze-cms/plugin-google-maps-ui": "0.146.0-rc-eagle-3.
|
|
44
|
-
"@blaze-cms/plugin-gtm-ui": "0.146.0-rc-eagle-3.
|
|
45
|
-
"@blaze-cms/plugin-media-ui": "0.146.0-rc-eagle-3.
|
|
46
|
-
"@blaze-cms/plugin-page-builder-ui": "0.146.0-rc-eagle-3.
|
|
47
|
-
"@blaze-cms/react-form-builder": "0.146.0-rc-eagle-3.
|
|
39
|
+
"@blaze-cms/plugin-admin-core-ui": "0.146.0-rc-eagle-3.11",
|
|
40
|
+
"@blaze-cms/plugin-auth-local-ui": "0.146.0-rc-eagle-3.11",
|
|
41
|
+
"@blaze-cms/plugin-auth-ui": "0.146.0-rc-eagle-3.11",
|
|
42
|
+
"@blaze-cms/plugin-data-ui": "0.146.0-rc-eagle-3.11",
|
|
43
|
+
"@blaze-cms/plugin-google-maps-ui": "0.146.0-rc-eagle-3.11",
|
|
44
|
+
"@blaze-cms/plugin-gtm-ui": "0.146.0-rc-eagle-3.11",
|
|
45
|
+
"@blaze-cms/plugin-media-ui": "0.146.0-rc-eagle-3.11",
|
|
46
|
+
"@blaze-cms/plugin-page-builder-ui": "0.146.0-rc-eagle-3.11",
|
|
47
|
+
"@blaze-cms/react-form-builder": "0.146.0-rc-eagle-3.11",
|
|
48
48
|
"@blaze-cms/setup-ui": "0.146.0-rc-eagle-3.0",
|
|
49
49
|
"@blaze-react/alert": "^0.7.0",
|
|
50
50
|
"@blaze-react/modal": "^0.7.0",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"lib/*",
|
|
66
66
|
"lib-es/*"
|
|
67
67
|
],
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "7608ce3003f6f888840e6dd27c2888a97a1be839"
|
|
69
69
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
const HeaderIconButton = ({ icon, label, className, ...rest }) => (
|
|
5
|
+
<button
|
|
6
|
+
type="button"
|
|
7
|
+
className={`page-header__icon-button${className ? ` ${className}` : ''}`}
|
|
8
|
+
title={label}
|
|
9
|
+
aria-label={label}
|
|
10
|
+
{...rest}>
|
|
11
|
+
<span className="material-icons" aria-hidden="true">
|
|
12
|
+
{icon}
|
|
13
|
+
</span>
|
|
14
|
+
</button>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
HeaderIconButton.propTypes = {
|
|
18
|
+
icon: PropTypes.string.isRequired,
|
|
19
|
+
label: PropTypes.string.isRequired,
|
|
20
|
+
className: PropTypes.string
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
HeaderIconButton.defaultProps = {
|
|
24
|
+
className: ''
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default HeaderIconButton;
|
|
@@ -1,44 +1,114 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import MetaTitle from '../MetaTitle/MetaTitle';
|
|
4
|
+
import HeaderIconButton from './HeaderIconButton';
|
|
5
|
+
import TitleEditor from './TitleEditor';
|
|
4
6
|
|
|
5
|
-
const PageHeader = ({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const PageHeader = ({
|
|
8
|
+
title,
|
|
9
|
+
subtitle,
|
|
10
|
+
children,
|
|
11
|
+
pageName,
|
|
12
|
+
onViewUrl,
|
|
13
|
+
viewUrlDisabledReason,
|
|
14
|
+
onTitleChange,
|
|
15
|
+
titleActions
|
|
16
|
+
}) => {
|
|
17
|
+
const [isEditingTitle, setIsEditingTitle] = useState(false);
|
|
18
|
+
const isTitleEditable = typeof onTitleChange === 'function';
|
|
19
|
+
// A reason renders the button disabled instead of dropping it.
|
|
20
|
+
const showViewButton = !!onViewUrl || !!viewUrlDisabledReason;
|
|
21
|
+
const hasTitleActions = isTitleEditable || !!titleActions || showViewButton;
|
|
22
|
+
|
|
23
|
+
const startEditing = () => setIsEditingTitle(true);
|
|
24
|
+
const stopEditing = () => setIsEditingTitle(false);
|
|
25
|
+
const saveTitle = nextTitle => {
|
|
26
|
+
stopEditing();
|
|
27
|
+
onTitleChange(nextTitle);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const renderTitle = () => {
|
|
31
|
+
if (isEditingTitle) {
|
|
32
|
+
return <TitleEditor title={title} onSave={saveTitle} onCancel={stopEditing} />;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
{isTitleEditable ? (
|
|
11
38
|
<div
|
|
12
|
-
className="page-header__heading page-header__heading--
|
|
13
|
-
onClick={
|
|
14
|
-
|
|
39
|
+
className="page-header__heading page-header__heading--editable"
|
|
40
|
+
onClick={startEditing}
|
|
41
|
+
title="Edit title"
|
|
42
|
+
role="button"
|
|
43
|
+
tabIndex={0}
|
|
44
|
+
onKeyDown={({ key }) => key === 'Enter' && startEditing()}>
|
|
15
45
|
{title}
|
|
16
46
|
</div>
|
|
17
47
|
) : (
|
|
18
48
|
<div className="page-header__heading">{title}</div>
|
|
19
49
|
)}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
50
|
+
{hasTitleActions && (
|
|
51
|
+
<div className="page-header__title-actions">
|
|
52
|
+
{isTitleEditable && (
|
|
53
|
+
<HeaderIconButton
|
|
54
|
+
icon="edit"
|
|
55
|
+
label="Edit title"
|
|
56
|
+
onClick={startEditing}
|
|
57
|
+
data-testid="page-header-title-edit"
|
|
58
|
+
/>
|
|
59
|
+
)}
|
|
60
|
+
{titleActions}
|
|
61
|
+
{showViewButton && (
|
|
62
|
+
<HeaderIconButton
|
|
63
|
+
icon="open_in_new"
|
|
64
|
+
label={viewUrlDisabledReason || 'View'}
|
|
65
|
+
className={viewUrlDisabledReason ? 'page-header__icon-button--disabled' : ''}
|
|
66
|
+
aria-disabled={viewUrlDisabledReason ? 'true' : undefined}
|
|
67
|
+
onClick={viewUrlDisabledReason ? undefined : onViewUrl}
|
|
68
|
+
data-testid="page-header-view"
|
|
69
|
+
/>
|
|
70
|
+
)}
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
73
|
+
</>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<>
|
|
79
|
+
<MetaTitle title={title} pageName={pageName} />
|
|
80
|
+
<div className="page-header--wrapper">
|
|
81
|
+
<div className="page-header page-header--sticky">
|
|
82
|
+
<div className="page-header__title">{renderTitle()}</div>
|
|
83
|
+
<div className="page-header__button">{children}</div>
|
|
84
|
+
</div>
|
|
85
|
+
<div className="page-header page-header--base">
|
|
86
|
+
<div className="page-header__subheading">{subtitle}</div>
|
|
87
|
+
</div>
|
|
24
88
|
</div>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
89
|
+
</>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
28
92
|
|
|
29
93
|
PageHeader.propTypes = {
|
|
30
94
|
title: PropTypes.string.isRequired,
|
|
31
95
|
subtitle: PropTypes.string,
|
|
32
96
|
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object, PropTypes.string]),
|
|
33
97
|
pageName: PropTypes.string,
|
|
34
|
-
onViewUrl: PropTypes.func
|
|
98
|
+
onViewUrl: PropTypes.func,
|
|
99
|
+
viewUrlDisabledReason: PropTypes.string,
|
|
100
|
+
onTitleChange: PropTypes.func,
|
|
101
|
+
titleActions: PropTypes.node
|
|
35
102
|
};
|
|
36
103
|
|
|
37
104
|
PageHeader.defaultProps = {
|
|
38
105
|
subtitle: '',
|
|
39
106
|
children: '',
|
|
40
107
|
pageName: '',
|
|
41
|
-
onViewUrl: null
|
|
108
|
+
onViewUrl: null,
|
|
109
|
+
viewUrlDisabledReason: null,
|
|
110
|
+
onTitleChange: null,
|
|
111
|
+
titleActions: null
|
|
42
112
|
};
|
|
43
113
|
|
|
44
114
|
const PageHeaderActions = ({ children }) => (
|
|
@@ -50,5 +120,6 @@ PageHeaderActions.propTypes = {
|
|
|
50
120
|
};
|
|
51
121
|
|
|
52
122
|
PageHeader.Actions = PageHeaderActions;
|
|
123
|
+
PageHeader.IconButton = HeaderIconButton;
|
|
53
124
|
|
|
54
125
|
export default PageHeader;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import HeaderIconButton from './HeaderIconButton';
|
|
4
|
+
|
|
5
|
+
const TitleEditor = ({ title, onSave, onCancel }) => {
|
|
6
|
+
const [value, setValue] = useState(title);
|
|
7
|
+
const inputRef = useRef(null);
|
|
8
|
+
// Blur and the tick/cross clicks can both fire for one edit; only the first wins.
|
|
9
|
+
// Blur discards: a change is only kept through Enter or the tick.
|
|
10
|
+
const isDone = useRef(false);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (inputRef.current) {
|
|
14
|
+
inputRef.current.focus();
|
|
15
|
+
inputRef.current.select();
|
|
16
|
+
}
|
|
17
|
+
}, []);
|
|
18
|
+
|
|
19
|
+
const finish = callback => {
|
|
20
|
+
if (isDone.current) return;
|
|
21
|
+
isDone.current = true;
|
|
22
|
+
callback();
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const save = () =>
|
|
26
|
+
finish(() => {
|
|
27
|
+
const nextTitle = value.trim();
|
|
28
|
+
if (!nextTitle || nextTitle === title) {
|
|
29
|
+
onCancel();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
onSave(nextTitle);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const cancel = () => finish(onCancel);
|
|
36
|
+
|
|
37
|
+
const onKeyDown = event => {
|
|
38
|
+
if (event.key === 'Enter') {
|
|
39
|
+
event.preventDefault();
|
|
40
|
+
save();
|
|
41
|
+
} else if (event.key === 'Escape') {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
cancel();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const keepInputFocus = event => event.preventDefault();
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div className="page-header__title-editor">
|
|
51
|
+
<input
|
|
52
|
+
ref={inputRef}
|
|
53
|
+
type="text"
|
|
54
|
+
className="page-header__title-input"
|
|
55
|
+
value={value}
|
|
56
|
+
onChange={({ target }) => setValue(target.value)}
|
|
57
|
+
onKeyDown={onKeyDown}
|
|
58
|
+
onBlur={cancel}
|
|
59
|
+
aria-label="Title"
|
|
60
|
+
data-testid="page-header-title-input"
|
|
61
|
+
/>
|
|
62
|
+
<div className="page-header__title-editor-actions">
|
|
63
|
+
<HeaderIconButton
|
|
64
|
+
icon="check"
|
|
65
|
+
label="Save title"
|
|
66
|
+
onMouseDown={keepInputFocus}
|
|
67
|
+
onClick={save}
|
|
68
|
+
data-testid="page-header-title-save"
|
|
69
|
+
/>
|
|
70
|
+
<HeaderIconButton
|
|
71
|
+
icon="close"
|
|
72
|
+
label="Cancel"
|
|
73
|
+
onMouseDown={keepInputFocus}
|
|
74
|
+
onClick={cancel}
|
|
75
|
+
data-testid="page-header-title-cancel"
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
TitleEditor.propTypes = {
|
|
83
|
+
title: PropTypes.string.isRequired,
|
|
84
|
+
onSave: PropTypes.func.isRequired,
|
|
85
|
+
onCancel: PropTypes.func.isRequired
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export default TitleEditor;
|