@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.
@@ -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 = _interopRequireDefault(require("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
- }) => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_MetaTitle.default, {
18
- title: title,
19
- pageName: pageName
20
- }), /*#__PURE__*/_react.default.createElement("div", {
21
- className: "page-header--wrapper"
22
- }, /*#__PURE__*/_react.default.createElement("div", {
23
- className: "page-header page-header--sticky"
24
- }, onViewUrl ? /*#__PURE__*/_react.default.createElement("div", {
25
- className: "page-header__heading page-header__heading--active",
26
- onClick: onViewUrl,
27
- role: "button"
28
- }, title) : /*#__PURE__*/_react.default.createElement("div", {
29
- className: "page-header__heading"
30
- }, title), /*#__PURE__*/_react.default.createElement("div", {
31
- className: "page-header__button"
32
- }, children)), /*#__PURE__*/_react.default.createElement("div", {
33
- className: "page-header page-header--base"
34
- }, /*#__PURE__*/_react.default.createElement("div", {
35
- className: "page-header__subheading"
36
- }, subtitle))));
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","_interopRequireDefault","require","_propTypes","_MetaTitle","PageHeader","title","subtitle","children","pageName","onViewUrl","default","createElement","Fragment","className","onClick","role","propTypes","PropTypes","string","isRequired","oneOfType","array","object","func","defaultProps","PageHeaderActions","React","Children","map","child","cloneElement","Actions","_default","exports"],"sources":["../../../src/components/PageHeader/PageHeader.js"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport MetaTitle from '../MetaTitle/MetaTitle';\n\nconst PageHeader = ({ title, subtitle, children, pageName, onViewUrl }) => (\n <>\n <MetaTitle title={title} pageName={pageName} />\n <div className=\"page-header--wrapper\">\n <div className=\"page-header page-header--sticky\">\n {onViewUrl ? (\n <div\n className=\"page-header__heading page-header__heading--active\"\n onClick={onViewUrl}\n role=\"button\">\n {title}\n </div>\n ) : (\n <div className=\"page-header__heading\">{title}</div>\n )}\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\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};\n\nPageHeader.defaultProps = {\n subtitle: '',\n children: '',\n pageName: '',\n onViewUrl: 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;\n\nexport default PageHeader;\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,UAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,UAAA,GAAAH,sBAAA,CAAAC,OAAA;AAEA,MAAMG,UAAU,GAAGA,CAAC;EAAEC,KAAK;EAAEC,QAAQ;EAAEC,QAAQ;EAAEC,QAAQ;EAAEC;AAAU,CAAC,kBACpEV,MAAA,CAAAW,OAAA,CAAAC,aAAA,CAAAZ,MAAA,CAAAW,OAAA,CAAAE,QAAA,qBACEb,MAAA,CAAAW,OAAA,CAAAC,aAAA,CAACR,UAAA,CAAAO,OAAS;EAACL,KAAK,EAAEA,KAAM;EAACG,QAAQ,EAAEA;AAAS,CAAE,CAAC,eAC/CT,MAAA,CAAAW,OAAA,CAAAC,aAAA;EAAKE,SAAS,EAAC;AAAsB,gBACnCd,MAAA,CAAAW,OAAA,CAAAC,aAAA;EAAKE,SAAS,EAAC;AAAiC,GAC7CJ,SAAS,gBACRV,MAAA,CAAAW,OAAA,CAAAC,aAAA;EACEE,SAAS,EAAC,mDAAmD;EAC7DC,OAAO,EAAEL,SAAU;EACnBM,IAAI,EAAC;AAAQ,GACZV,KACE,CAAC,gBAENN,MAAA,CAAAW,OAAA,CAAAC,aAAA;EAAKE,SAAS,EAAC;AAAsB,GAAER,KAAW,CACnD,eACDN,MAAA,CAAAW,OAAA,CAAAC,aAAA;EAAKE,SAAS,EAAC;AAAqB,GAAEN,QAAc,CACjD,CAAC,eACNR,MAAA,CAAAW,OAAA,CAAAC,aAAA;EAAKE,SAAS,EAAC;AAA+B,gBAC5Cd,MAAA,CAAAW,OAAA,CAAAC,aAAA;EAAKE,SAAS,EAAC;AAAyB,GAAEP,QAAc,CACrD,CACF,CACL,CACH;AAEDF,UAAU,CAACY,SAAS,GAAG;EACrBX,KAAK,EAAEY,kBAAS,CAACC,MAAM,CAACC,UAAU;EAClCb,QAAQ,EAAEW,kBAAS,CAACC,MAAM;EAC1BX,QAAQ,EAAEU,kBAAS,CAACG,SAAS,CAAC,CAACH,kBAAS,CAACI,KAAK,EAAEJ,kBAAS,CAACK,MAAM,EAAEL,kBAAS,CAACC,MAAM,CAAC,CAAC;EACpFV,QAAQ,EAAES,kBAAS,CAACC,MAAM;EAC1BT,SAAS,EAAEQ,kBAAS,CAACM;AACvB,CAAC;AAEDnB,UAAU,CAACoB,YAAY,GAAG;EACxBlB,QAAQ,EAAE,EAAE;EACZC,QAAQ,EAAE,EAAE;EACZC,QAAQ,EAAE,EAAE;EACZC,SAAS,EAAE;AACb,CAAC;AAED,MAAMgB,iBAAiB,GAAGA,CAAC;EAAElB;AAAS,CAAC,kBACrCR,MAAA,CAAAW,OAAA,CAAAC,aAAA,CAAAZ,MAAA,CAAAW,OAAA,CAAAE,QAAA,QAAGc,cAAK,CAACC,QAAQ,CAACC,GAAG,CAACrB,QAAQ,EAAEsB,KAAK,IAAIA,KAAK,iBAAIH,cAAK,CAACI,YAAY,CAACD,KAAK,CAAC,CAAI,CAChF;AAEDJ,iBAAiB,CAACT,SAAS,GAAG;EAC5BT,QAAQ,EAAEU,kBAAS,CAACG,SAAS,CAAC,CAACH,kBAAS,CAACI,KAAK,EAAEJ,kBAAS,CAACK,MAAM,CAAC,CAAC,CAACH;AACrE,CAAC;AAEDf,UAAU,CAAC2B,OAAO,GAAGN,iBAAiB;AAAC,IAAAO,QAAA,GAAAC,OAAA,CAAAvB,OAAA,GAExBN,UAAU","ignoreList":[]}
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
- }) => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MetaTitle, {
11
- title: title,
12
- pageName: pageName
13
- }), /*#__PURE__*/React.createElement("div", {
14
- className: "page-header--wrapper"
15
- }, /*#__PURE__*/React.createElement("div", {
16
- className: "page-header page-header--sticky"
17
- }, onViewUrl ? /*#__PURE__*/React.createElement("div", {
18
- className: "page-header__heading page-header__heading--active",
19
- onClick: onViewUrl,
20
- role: "button"
21
- }, title) : /*#__PURE__*/React.createElement("div", {
22
- className: "page-header__heading"
23
- }, title), /*#__PURE__*/React.createElement("div", {
24
- className: "page-header__button"
25
- }, children)), /*#__PURE__*/React.createElement("div", {
26
- className: "page-header page-header--base"
27
- }, /*#__PURE__*/React.createElement("div", {
28
- className: "page-header__subheading"
29
- }, subtitle))));
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 = ({ title, subtitle, children, pageName, onViewUrl }) => (\n <>\n <MetaTitle title={title} pageName={pageName} />\n <div className=\"page-header--wrapper\">\n <div className=\"page-header page-header--sticky\">\n {onViewUrl ? (\n <div\n className=\"page-header__heading page-header__heading--active\"\n onClick={onViewUrl}\n role=\"button\">\n {title}\n </div>\n ) : (\n <div className=\"page-header__heading\">{title}</div>\n )}\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\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};\n\nPageHeader.defaultProps = {\n subtitle: '',\n children: '',\n pageName: '',\n onViewUrl: 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;\n\nexport default PageHeader;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,OAAOC,SAAS,MAAM,YAAY;AAClC,OAAOC,SAAS,MAAM,wBAAwB;AAE9C,MAAMC,UAAU,GAAGA,CAAC;EAAEC,KAAK;EAAEC,QAAQ;EAAEC,QAAQ;EAAEC,QAAQ;EAAEC;AAAU,CAAC,kBACpER,KAAA,CAAAS,aAAA,CAAAT,KAAA,CAAAU,QAAA,qBACEV,KAAA,CAAAS,aAAA,CAACP,SAAS;EAACE,KAAK,EAAEA,KAAM;EAACG,QAAQ,EAAEA;AAAS,CAAE,CAAC,eAC/CP,KAAA,CAAAS,aAAA;EAAKE,SAAS,EAAC;AAAsB,gBACnCX,KAAA,CAAAS,aAAA;EAAKE,SAAS,EAAC;AAAiC,GAC7CH,SAAS,gBACRR,KAAA,CAAAS,aAAA;EACEE,SAAS,EAAC,mDAAmD;EAC7DC,OAAO,EAAEJ,SAAU;EACnBK,IAAI,EAAC;AAAQ,GACZT,KACE,CAAC,gBAENJ,KAAA,CAAAS,aAAA;EAAKE,SAAS,EAAC;AAAsB,GAAEP,KAAW,CACnD,eACDJ,KAAA,CAAAS,aAAA;EAAKE,SAAS,EAAC;AAAqB,GAAEL,QAAc,CACjD,CAAC,eACNN,KAAA,CAAAS,aAAA;EAAKE,SAAS,EAAC;AAA+B,gBAC5CX,KAAA,CAAAS,aAAA;EAAKE,SAAS,EAAC;AAAyB,GAAEN,QAAc,CACrD,CACF,CACL,CACH;AAEDF,UAAU,CAACW,SAAS,GAAG;EACrBV,KAAK,EAAEH,SAAS,CAACc,MAAM,CAACC,UAAU;EAClCX,QAAQ,EAAEJ,SAAS,CAACc,MAAM;EAC1BT,QAAQ,EAAEL,SAAS,CAACgB,SAAS,CAAC,CAAChB,SAAS,CAACiB,KAAK,EAAEjB,SAAS,CAACkB,MAAM,EAAElB,SAAS,CAACc,MAAM,CAAC,CAAC;EACpFR,QAAQ,EAAEN,SAAS,CAACc,MAAM;EAC1BP,SAAS,EAAEP,SAAS,CAACmB;AACvB,CAAC;AAEDjB,UAAU,CAACkB,YAAY,GAAG;EACxBhB,QAAQ,EAAE,EAAE;EACZC,QAAQ,EAAE,EAAE;EACZC,QAAQ,EAAE,EAAE;EACZC,SAAS,EAAE;AACb,CAAC;AAED,MAAMc,iBAAiB,GAAGA,CAAC;EAAEhB;AAAS,CAAC,kBACrCN,KAAA,CAAAS,aAAA,CAAAT,KAAA,CAAAU,QAAA,QAAGV,KAAK,CAACuB,QAAQ,CAACC,GAAG,CAAClB,QAAQ,EAAEmB,KAAK,IAAIA,KAAK,IAAIzB,KAAK,CAAC0B,YAAY,CAACD,KAAK,CAAC,CAAI,CAChF;AAEDH,iBAAiB,CAACR,SAAS,GAAG;EAC5BR,QAAQ,EAAEL,SAAS,CAACgB,SAAS,CAAC,CAAChB,SAAS,CAACiB,KAAK,EAAEjB,SAAS,CAACkB,MAAM,CAAC,CAAC,CAACH;AACrE,CAAC;AAEDb,UAAU,CAACwB,OAAO,GAAGL,iBAAiB;AAEtC,eAAenB,UAAU","ignoreList":[]}
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.10",
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.10",
40
- "@blaze-cms/plugin-auth-local-ui": "0.146.0-rc-eagle-3.10",
41
- "@blaze-cms/plugin-auth-ui": "0.146.0-rc-eagle-3.10",
42
- "@blaze-cms/plugin-data-ui": "0.146.0-rc-eagle-3.10",
43
- "@blaze-cms/plugin-google-maps-ui": "0.146.0-rc-eagle-3.10",
44
- "@blaze-cms/plugin-gtm-ui": "0.146.0-rc-eagle-3.10",
45
- "@blaze-cms/plugin-media-ui": "0.146.0-rc-eagle-3.10",
46
- "@blaze-cms/plugin-page-builder-ui": "0.146.0-rc-eagle-3.10",
47
- "@blaze-cms/react-form-builder": "0.146.0-rc-eagle-3.10",
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": "782e5e3c8df78fc8c873288a155958ff5b5c6705"
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 = ({ title, subtitle, children, pageName, onViewUrl }) => (
6
- <>
7
- <MetaTitle title={title} pageName={pageName} />
8
- <div className="page-header--wrapper">
9
- <div className="page-header page-header--sticky">
10
- {onViewUrl ? (
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--active"
13
- onClick={onViewUrl}
14
- role="button">
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
- <div className="page-header__button">{children}</div>
21
- </div>
22
- <div className="page-header page-header--base">
23
- <div className="page-header__subheading">{subtitle}</div>
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
- </div>
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;