studiokit-scaffolding-js 4.9.0-next.2.1 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/lib/components/ErrorMessage.d.ts +6 -0
  2. package/lib/components/ErrorMessage.js +18 -0
  3. package/lib/components/Icons/IconAlphaList.d.ts +3 -0
  4. package/lib/components/Icons/IconAlphaList.js +24 -0
  5. package/lib/components/Icons/IconTable.d.ts +5 -0
  6. package/lib/components/Icons/IconTable.js +24 -0
  7. package/lib/components/Icons/IconTableDeleteCol.d.ts +3 -0
  8. package/lib/components/Icons/IconTableDeleteCol.js +24 -0
  9. package/lib/components/Icons/IconTableDeleteRow.d.ts +3 -0
  10. package/lib/components/Icons/IconTableDeleteRow.js +24 -0
  11. package/lib/components/Icons/IconTableInsertCol.d.ts +3 -0
  12. package/lib/components/Icons/IconTableInsertCol.js +24 -0
  13. package/lib/components/Icons/IconTableInsertRow.d.ts +3 -0
  14. package/lib/components/Icons/IconTableInsertRow.js +24 -0
  15. package/lib/components/Quill/CustomToolbar.d.ts +42 -0
  16. package/lib/components/Quill/CustomToolbar.js +214 -0
  17. package/lib/components/Quill/ImageMissingAltTextWarning.d.ts +5 -0
  18. package/lib/components/Quill/ImageMissingAltTextWarning.js +15 -0
  19. package/lib/components/Quill/ImageWithAltTextModal.d.ts +15 -0
  20. package/lib/components/Quill/ImageWithAltTextModal.js +139 -0
  21. package/lib/components/Quill/TableModule/index.css +1 -1
  22. package/lib/components/Quill/index.d.ts +2 -0
  23. package/lib/components/Quill/index.js +10 -1
  24. package/lib/css/components/_buttons.css +32 -4
  25. package/lib/css/components/_quill.css +314 -0
  26. package/lib/css/utils/_color.css +38 -0
  27. package/lib/css/variables.css +8 -0
  28. package/lib/types/Quill.d.ts +9 -0
  29. package/lib/types/Quill.js +2 -0
  30. package/lib/types/index.d.ts +1 -0
  31. package/lib/types/index.js +1 -0
  32. package/lib/utils/quill.d.ts +9 -0
  33. package/lib/utils/quill.js +12 -0
  34. package/package.json +2 -2
@@ -0,0 +1,6 @@
1
+ import { FunctionComponent } from 'react';
2
+ export interface ErrorMessageProps {
3
+ message: string | JSX.Element | undefined;
4
+ hideIcon?: boolean;
5
+ }
6
+ export declare const ErrorMessage: FunctionComponent<ErrorMessageProps>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ErrorMessage = void 0;
7
+ var ErrorOutline_1 = __importDefault(require("@material-ui/icons/ErrorOutline"));
8
+ var react_1 = __importDefault(require("react"));
9
+ var ErrorMessage = function (_a) {
10
+ var message = _a.message, hideIcon = _a.hideIcon;
11
+ if (!message) {
12
+ return null;
13
+ }
14
+ return (react_1.default.createElement("span", { className: "color-red b" + (!hideIcon ? ' flex items-center' : '') },
15
+ !hideIcon && react_1.default.createElement(ErrorOutline_1.default, { className: "mr1" }),
16
+ message));
17
+ };
18
+ exports.ErrorMessage = ErrorMessage;
@@ -0,0 +1,3 @@
1
+ import { SvgIconProps } from '@material-ui/core/SvgIcon';
2
+ import { FunctionComponent } from 'react';
3
+ export declare const IconAlphaList: FunctionComponent<SvgIconProps>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.IconAlphaList = void 0;
18
+ var SvgIcon_1 = __importDefault(require("@material-ui/core/SvgIcon"));
19
+ var react_1 = __importDefault(require("react"));
20
+ /** Copied from `@mdi/js` */
21
+ var mdiOrderAlphabeticalAscending = 'M12 5H22V7H12M12 19V17H22V19M12 11H22V13H12M9 13V15L5.67 19H9V21H3V19L6.33 15H3V13M7 3H5C3.9 3 3 3.9 3 5V11H5V9H7V11H9V5C9 3.9 8.11 3 7 3M7 7H5V5H7Z';
22
+ var IconAlphaList = function (props) { return (react_1.default.createElement(SvgIcon_1.default, __assign({}, props),
23
+ react_1.default.createElement("path", { d: mdiOrderAlphabeticalAscending }))); };
24
+ exports.IconAlphaList = IconAlphaList;
@@ -0,0 +1,5 @@
1
+ import { SvgIconProps } from '@material-ui/core/SvgIcon';
2
+ import { FunctionComponent } from 'react';
3
+ /** Copied from `@mdi/js` */
4
+ export declare const mdiTable = "M5,4H19A2,2 0 0,1 21,6V18A2,2 0 0,1 19,20H5A2,2 0 0,1 3,18V6A2,2 0 0,1 5,4M5,8V12H11V8H5M13,8V12H19V8H13M5,14V18H11V14H5M13,14V18H19V14H13Z";
5
+ export declare const IconTable: FunctionComponent<SvgIconProps>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.IconTable = exports.mdiTable = void 0;
18
+ var SvgIcon_1 = __importDefault(require("@material-ui/core/SvgIcon"));
19
+ var react_1 = __importDefault(require("react"));
20
+ /** Copied from `@mdi/js` */
21
+ exports.mdiTable = 'M5,4H19A2,2 0 0,1 21,6V18A2,2 0 0,1 19,20H5A2,2 0 0,1 3,18V6A2,2 0 0,1 5,4M5,8V12H11V8H5M13,8V12H19V8H13M5,14V18H11V14H5M13,14V18H19V14H13Z';
22
+ var IconTable = function (props) { return (react_1.default.createElement(SvgIcon_1.default, __assign({}, props),
23
+ react_1.default.createElement("path", { d: exports.mdiTable }))); };
24
+ exports.IconTable = IconTable;
@@ -0,0 +1,3 @@
1
+ import { SvgIconProps } from '@material-ui/core/SvgIcon';
2
+ import { FunctionComponent } from 'react';
3
+ export declare const IconTableDeleteCol: FunctionComponent<SvgIconProps>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.IconTableDeleteCol = void 0;
18
+ var SvgIcon_1 = __importDefault(require("@material-ui/core/SvgIcon"));
19
+ var react_1 = __importDefault(require("react"));
20
+ /** Copied from `@mdi/js` */
21
+ var mdiTableColumnRemove = 'M4,2H11A2,2 0 0,1 13,4V20A2,2 0 0,1 11,22H4A2,2 0 0,1 2,20V4A2,2 0 0,1 4,2M4,10V14H11V10H4M4,16V20H11V16H4M4,4V8H11V4H4M17.59,12L15,9.41L16.41,8L19,10.59L21.59,8L23,9.41L20.41,12L23,14.59L21.59,16L19,13.41L16.41,16L15,14.59L17.59,12Z';
22
+ var IconTableDeleteCol = function (props) { return (react_1.default.createElement(SvgIcon_1.default, __assign({}, props),
23
+ react_1.default.createElement("path", { d: mdiTableColumnRemove }))); };
24
+ exports.IconTableDeleteCol = IconTableDeleteCol;
@@ -0,0 +1,3 @@
1
+ import { SvgIconProps } from '@material-ui/core/SvgIcon';
2
+ import { FunctionComponent } from 'react';
3
+ export declare const IconTableDeleteRow: FunctionComponent<SvgIconProps>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.IconTableDeleteRow = void 0;
18
+ var SvgIcon_1 = __importDefault(require("@material-ui/core/SvgIcon"));
19
+ var react_1 = __importDefault(require("react"));
20
+ /** Copied from `@mdi/js` */
21
+ var mdiTableRowRemove = 'M9.41,13L12,15.59L14.59,13L16,14.41L13.41,17L16,19.59L14.59,21L12,18.41L9.41,21L8,19.59L10.59,17L8,14.41L9.41,13M22,9A2,2 0 0,1 20,11H4A2,2 0 0,1 2,9V6A2,2 0 0,1 4,4H20A2,2 0 0,1 22,6V9M4,9H8V6H4V9M10,9H14V6H10V9M16,9H20V6H16V9Z';
22
+ var IconTableDeleteRow = function (props) { return (react_1.default.createElement(SvgIcon_1.default, __assign({}, props),
23
+ react_1.default.createElement("path", { d: mdiTableRowRemove }))); };
24
+ exports.IconTableDeleteRow = IconTableDeleteRow;
@@ -0,0 +1,3 @@
1
+ import { SvgIconProps } from '@material-ui/core/SvgIcon';
2
+ import { FunctionComponent } from 'react';
3
+ export declare const IconTableInsertCol: FunctionComponent<SvgIconProps>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.IconTableInsertCol = void 0;
18
+ var SvgIcon_1 = __importDefault(require("@material-ui/core/SvgIcon"));
19
+ var react_1 = __importDefault(require("react"));
20
+ /** Copied from `@mdi/js` */
21
+ var mdiTableColumnPlusAfter = 'M11,2A2,2 0 0,1 13,4V20A2,2 0 0,1 11,22H2V2H11M4,10V14H11V10H4M4,16V20H11V16H4M4,4V8H11V4H4M15,11H18V8H20V11H23V13H20V16H18V13H15V11Z';
22
+ var IconTableInsertCol = function (props) { return (react_1.default.createElement(SvgIcon_1.default, __assign({}, props),
23
+ react_1.default.createElement("path", { d: mdiTableColumnPlusAfter }))); };
24
+ exports.IconTableInsertCol = IconTableInsertCol;
@@ -0,0 +1,3 @@
1
+ import { SvgIconProps } from '@material-ui/core/SvgIcon';
2
+ import { FunctionComponent } from 'react';
3
+ export declare const IconTableInsertRow: FunctionComponent<SvgIconProps>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.IconTableInsertRow = void 0;
18
+ var SvgIcon_1 = __importDefault(require("@material-ui/core/SvgIcon"));
19
+ var react_1 = __importDefault(require("react"));
20
+ /** Copied from `@mdi/js` */
21
+ var mdiTableRowPlusAfter = 'M22,10A2,2 0 0,1 20,12H4A2,2 0 0,1 2,10V3H4V5H8V3H10V5H14V3H16V5H20V3H22V10M4,10H8V7H4V10M10,10H14V7H10V10M20,10V7H16V10H20M11,14H13V17H16V19H13V22H11V19H8V17H11V14Z';
22
+ var IconTableInsertRow = function (props) { return (react_1.default.createElement(SvgIcon_1.default, __assign({}, props),
23
+ react_1.default.createElement("path", { d: mdiTableRowPlusAfter }))); };
24
+ exports.IconTableInsertRow = IconTableInsertRow;
@@ -0,0 +1,42 @@
1
+ import { FunctionComponent } from 'react';
2
+ import ReactQuill from 'react-quill';
3
+ export declare enum TOOLBAR_OPTION {
4
+ HEADER = "header",
5
+ FONT = "font",
6
+ SIZE = "size",
7
+ BOLD = "bold",
8
+ ITALIC = "italic",
9
+ UNDERLINE = "underline",
10
+ SCRIPT_SUB = "sub",
11
+ SCRIPT_SUPER = "super",
12
+ STRIKE_THROUGH = "strike",
13
+ BLOCKQUOTE = "blockquote",
14
+ CODE_BLOCK = "code-block",
15
+ ALIGN = "align",
16
+ LIST_ORDERED = "ordered",
17
+ LIST_BULLET = "bullet",
18
+ LIST_ALPHA = "alpha",
19
+ INDENT = "indent",
20
+ LINK = "link",
21
+ IMAGE = "image",
22
+ VIDEO = "video",
23
+ FORMULA = "formula",
24
+ TABLE = "table",
25
+ /** NOTE: variable support is not currently in scaffolding, just the toolbar option */
26
+ VARIABLE = "variable",
27
+ CLEAN = "clean"
28
+ }
29
+ export declare const getFormatsForOptions: (sectionOptionsArray: TOOLBAR_OPTION[][]) => string[];
30
+ export declare type ToolbarSection = (disabled?: boolean) => JSX.Element;
31
+ export interface CustomToolbarProps {
32
+ guid: string;
33
+ /** An array of toolbar option arrays. Each top level array will equate to a toolbar section, with spacing between each section. */
34
+ sectionOptions: TOOLBAR_OPTION[][];
35
+ /** (Optional) An array of toolbar option arrays. When provided, a "more options" button is provided and a secondary toolbar can be expanded and collapsed. */
36
+ moreSectionOptions?: TOOLBAR_OPTION[][];
37
+ className?: string;
38
+ disabled?: boolean;
39
+ reactQuillRef: ReactQuill | null;
40
+ isVisibleWhenDisabled?: boolean;
41
+ }
42
+ export declare const CustomToolbar: FunctionComponent<CustomToolbarProps>;
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.CustomToolbar = exports.getFormatsForOptions = exports.TOOLBAR_OPTION = void 0;
26
+ var AddBox_1 = __importDefault(require("@material-ui/icons/AddBox"));
27
+ var MoreHoriz_1 = __importDefault(require("@material-ui/icons/MoreHoriz"));
28
+ var lodash_1 = require("lodash");
29
+ var react_1 = __importStar(require("react"));
30
+ var IconAlphaList_1 = require("../Icons/IconAlphaList");
31
+ var IconTable_1 = require("../Icons/IconTable");
32
+ var IconTableDeleteCol_1 = require("../Icons/IconTableDeleteCol");
33
+ var IconTableDeleteRow_1 = require("../Icons/IconTableDeleteRow");
34
+ var IconTableInsertCol_1 = require("../Icons/IconTableInsertCol");
35
+ var IconTableInsertRow_1 = require("../Icons/IconTableInsertRow");
36
+ var accessibilityFix_1 = require("./accessibilityFix");
37
+ var constants_1 = require("./TableModule/constants");
38
+ var TOOLBAR_OPTION;
39
+ (function (TOOLBAR_OPTION) {
40
+ TOOLBAR_OPTION["HEADER"] = "header";
41
+ TOOLBAR_OPTION["FONT"] = "font";
42
+ TOOLBAR_OPTION["SIZE"] = "size";
43
+ TOOLBAR_OPTION["BOLD"] = "bold";
44
+ TOOLBAR_OPTION["ITALIC"] = "italic";
45
+ TOOLBAR_OPTION["UNDERLINE"] = "underline";
46
+ TOOLBAR_OPTION["SCRIPT_SUB"] = "sub";
47
+ TOOLBAR_OPTION["SCRIPT_SUPER"] = "super";
48
+ TOOLBAR_OPTION["STRIKE_THROUGH"] = "strike";
49
+ TOOLBAR_OPTION["BLOCKQUOTE"] = "blockquote";
50
+ TOOLBAR_OPTION["CODE_BLOCK"] = "code-block";
51
+ TOOLBAR_OPTION["ALIGN"] = "align";
52
+ TOOLBAR_OPTION["LIST_ORDERED"] = "ordered";
53
+ TOOLBAR_OPTION["LIST_BULLET"] = "bullet";
54
+ TOOLBAR_OPTION["LIST_ALPHA"] = "alpha";
55
+ TOOLBAR_OPTION["INDENT"] = "indent";
56
+ TOOLBAR_OPTION["LINK"] = "link";
57
+ TOOLBAR_OPTION["IMAGE"] = "image";
58
+ TOOLBAR_OPTION["VIDEO"] = "video";
59
+ TOOLBAR_OPTION["FORMULA"] = "formula";
60
+ TOOLBAR_OPTION["TABLE"] = "table";
61
+ /** NOTE: variable support is not currently in scaffolding, just the toolbar option */
62
+ TOOLBAR_OPTION["VARIABLE"] = "variable";
63
+ TOOLBAR_OPTION["CLEAN"] = "clean";
64
+ })(TOOLBAR_OPTION = exports.TOOLBAR_OPTION || (exports.TOOLBAR_OPTION = {}));
65
+ var getFormatsForOption = function (option) {
66
+ switch (option) {
67
+ case TOOLBAR_OPTION.HEADER:
68
+ case TOOLBAR_OPTION.FONT:
69
+ case TOOLBAR_OPTION.SIZE:
70
+ case TOOLBAR_OPTION.BOLD:
71
+ case TOOLBAR_OPTION.ITALIC:
72
+ case TOOLBAR_OPTION.UNDERLINE:
73
+ case TOOLBAR_OPTION.STRIKE_THROUGH:
74
+ case TOOLBAR_OPTION.BLOCKQUOTE:
75
+ case TOOLBAR_OPTION.CODE_BLOCK:
76
+ case TOOLBAR_OPTION.ALIGN:
77
+ case TOOLBAR_OPTION.INDENT:
78
+ case TOOLBAR_OPTION.LINK:
79
+ case TOOLBAR_OPTION.IMAGE:
80
+ case TOOLBAR_OPTION.VIDEO:
81
+ case TOOLBAR_OPTION.FORMULA:
82
+ case TOOLBAR_OPTION.VARIABLE:
83
+ return [option];
84
+ case TOOLBAR_OPTION.LIST_ORDERED:
85
+ case TOOLBAR_OPTION.LIST_BULLET:
86
+ case TOOLBAR_OPTION.LIST_ALPHA:
87
+ return ['list'];
88
+ case TOOLBAR_OPTION.SCRIPT_SUB:
89
+ case TOOLBAR_OPTION.SCRIPT_SUPER:
90
+ return ['script'];
91
+ case TOOLBAR_OPTION.TABLE:
92
+ return ['table-container', 'table', 'tbody', 'tr', 'td'];
93
+ case TOOLBAR_OPTION.CLEAN:
94
+ return [];
95
+ default:
96
+ throw new Error("Unsupported option: " + option);
97
+ }
98
+ };
99
+ var getFormatsForOptions = function (sectionOptionsArray) {
100
+ // flatten section options to array of options
101
+ // map options to formats and flatten those formats
102
+ // get distinct values using Set, then convert back to Array
103
+ return Array.from(new Set(sectionOptionsArray.flat(2).flatMap(function (option) { return getFormatsForOption(option); })));
104
+ };
105
+ exports.getFormatsForOptions = getFormatsForOptions;
106
+ var getToolbarSectionForOption = function (option) {
107
+ switch (option) {
108
+ case TOOLBAR_OPTION.HEADER:
109
+ return function (disabled) { return (react_1.default.createElement(react_1.default.Fragment, null,
110
+ react_1.default.createElement("button", { className: "ql-header", value: "1", disabled: disabled }),
111
+ react_1.default.createElement("button", { className: "ql-header", value: "2", disabled: disabled }))); };
112
+ case TOOLBAR_OPTION.FONT:
113
+ case TOOLBAR_OPTION.SIZE:
114
+ case TOOLBAR_OPTION.ALIGN:
115
+ return function (disabled) { return react_1.default.createElement("select", { className: "ql-" + option, disabled: disabled }); };
116
+ case TOOLBAR_OPTION.BOLD:
117
+ case TOOLBAR_OPTION.ITALIC:
118
+ case TOOLBAR_OPTION.UNDERLINE:
119
+ case TOOLBAR_OPTION.STRIKE_THROUGH:
120
+ case TOOLBAR_OPTION.BLOCKQUOTE:
121
+ case TOOLBAR_OPTION.CODE_BLOCK:
122
+ case TOOLBAR_OPTION.LINK:
123
+ case TOOLBAR_OPTION.IMAGE:
124
+ case TOOLBAR_OPTION.VIDEO:
125
+ case TOOLBAR_OPTION.FORMULA:
126
+ case TOOLBAR_OPTION.CLEAN:
127
+ return function (disabled) { return react_1.default.createElement("button", { className: "ql-" + option, disabled: disabled }); };
128
+ case TOOLBAR_OPTION.SCRIPT_SUB:
129
+ return function (disabled) { return react_1.default.createElement("button", { className: "ql-script", value: "sub", disabled: disabled }); };
130
+ case TOOLBAR_OPTION.SCRIPT_SUPER:
131
+ return function (disabled) { return react_1.default.createElement("button", { className: "ql-script", value: "super", disabled: disabled }); };
132
+ case TOOLBAR_OPTION.LIST_ORDERED:
133
+ return function (disabled) { return react_1.default.createElement("button", { className: "ql-list", value: "ordered", disabled: disabled }); };
134
+ case TOOLBAR_OPTION.LIST_BULLET:
135
+ return function (disabled) { return react_1.default.createElement("button", { className: "ql-list", value: "bullet", disabled: disabled }); };
136
+ case TOOLBAR_OPTION.LIST_ALPHA:
137
+ return function (disabled) { return (react_1.default.createElement("button", { className: "ql-list", value: "alpha", disabled: disabled, title: "Toggle alpha list", "aria-label": "Toggle alpha list" },
138
+ react_1.default.createElement(IconAlphaList_1.IconAlphaList, { style: { width: 'auto' } }))); };
139
+ case TOOLBAR_OPTION.INDENT:
140
+ return function (disabled) { return (react_1.default.createElement(react_1.default.Fragment, null,
141
+ react_1.default.createElement("button", { className: "ql-indent", value: "-1", disabled: disabled }),
142
+ react_1.default.createElement("button", { className: "ql-indent", value: "+1", disabled: disabled }))); };
143
+ case TOOLBAR_OPTION.TABLE:
144
+ return function (disabled) { return (react_1.default.createElement(react_1.default.Fragment, null,
145
+ react_1.default.createElement("select", { className: "ql-table", disabled: disabled }, Array.from(Array(5).keys()).flatMap(function (row) {
146
+ return Array.from(Array(5).keys()).map(function (col) {
147
+ return (react_1.default.createElement("option", { key: row + "-" + col, value: "" + constants_1.TABLE_ACTION.NEW_TABLE + (row + 1) + "_" + (col + 1) }));
148
+ });
149
+ })),
150
+ react_1.default.createElement("button", { className: "ql-table", value: "insert-row", disabled: disabled },
151
+ react_1.default.createElement(IconTableInsertRow_1.IconTableInsertRow, { style: { width: 'auto' } })),
152
+ react_1.default.createElement("button", { className: "ql-table", value: "delete-row", disabled: disabled },
153
+ react_1.default.createElement(IconTableDeleteRow_1.IconTableDeleteRow, { style: { width: 'auto' } })),
154
+ react_1.default.createElement("button", { className: "ql-table", value: "insert-col", disabled: disabled },
155
+ react_1.default.createElement(IconTableInsertCol_1.IconTableInsertCol, { style: { width: 'auto' } })),
156
+ react_1.default.createElement("button", { className: "ql-table", value: "delete-col", disabled: disabled },
157
+ react_1.default.createElement(IconTableDeleteCol_1.IconTableDeleteCol, { style: { width: 'auto' } })))); };
158
+ case TOOLBAR_OPTION.VARIABLE:
159
+ return function (disabled) { return (react_1.default.createElement("button", { className: "ql-createVariable f6 fw5" + (disabled ? '' : ' color-primary'), style: { width: '100%' }, disabled: disabled, type: "button", "aria-label": "Insert variable", title: "Insert variable" },
160
+ react_1.default.createElement(AddBox_1.default, { className: "ma0" }),
161
+ "Variable")); };
162
+ default:
163
+ throw new Error("Unsupported option: " + option);
164
+ }
165
+ };
166
+ var getToolbarSectionsForOptions = function (sectionOptionsArray) {
167
+ return sectionOptionsArray.map(function (sectionOptions, sectionIndex) {
168
+ return function (disabled) { return (react_1.default.createElement(react_1.default.Fragment, null, sectionOptions.map(function (sectionOption, optionIndex) { return (react_1.default.createElement(react_1.Fragment, { key: sectionIndex + "-" + optionIndex }, getToolbarSectionForOption(sectionOption)(disabled))); }))); };
169
+ });
170
+ };
171
+ // Following this example: https://codepen.io/alexkrolick/pen/gmroPj?editors=0010
172
+ // All the options available here: https://github.com/quilljs/quill/blob/develop/docs/_includes/standalone/full.html
173
+ var CustomToolbar = function (props) {
174
+ var guid = props.guid, sectionOptions = props.sectionOptions, moreSectionOptions = props.moreSectionOptions, className = props.className, disabled = props.disabled, reactQuillRef = props.reactQuillRef, isVisibleWhenDisabled = props.isVisibleWhenDisabled;
175
+ var _a = react_1.useState(false), isInitialized = _a[0], setIsInitialized = _a[1];
176
+ var _b = react_1.useState(false), isShowingMoreOptions = _b[0], setIsShowingMoreOptions = _b[1];
177
+ var ref = react_1.default.createRef();
178
+ react_1.useEffect(function () {
179
+ var _a;
180
+ // initialize the toolbar after reactQuill exists and the buttons are displayed (not disabled)
181
+ if (!isInitialized && reactQuillRef && !disabled) {
182
+ accessibilityFix_1.applyAccessibilityHacks(ref, reactQuillRef.getEditor());
183
+ // manually modify the table picker select svg icon
184
+ var label = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.querySelector('.ql-table .ql-picker-label');
185
+ if (label) {
186
+ var svg = label.childNodes[0];
187
+ var polygons = svg.querySelectorAll('polygon');
188
+ polygons.forEach(function (polygon) {
189
+ polygon.remove();
190
+ });
191
+ svg.setAttribute('viewBox', '0 0 24 24');
192
+ svg.classList.add('ql-fill');
193
+ var path = svg.querySelector('path');
194
+ if (!path) {
195
+ var path_1 = document.createElementNS('http://www.w3.org/2000/svg', 'path');
196
+ path_1.setAttribute('d', IconTable_1.mdiTable);
197
+ svg.appendChild(path_1);
198
+ }
199
+ }
200
+ setIsInitialized(true);
201
+ }
202
+ }, [disabled, isInitialized, reactQuillRef, ref]);
203
+ var toolbarSections = react_1.useMemo(function () { return getToolbarSectionsForOptions(sectionOptions); }, [sectionOptions]);
204
+ var hasMoreOptions = !lodash_1.isUndefined(moreSectionOptions);
205
+ var moreToolbarSections = react_1.useMemo(function () { return (!lodash_1.isUndefined(moreSectionOptions) ? getToolbarSectionsForOptions(moreSectionOptions) : []); }, [moreSectionOptions]);
206
+ return (react_1.default.createElement("div", { id: "quill-toolbar-" + guid, className: "" + (className ? " " + className : '') + (disabled ? ' disabled' : '') + (!isVisibleWhenDisabled && disabled ? ' disabled-invisible' : ''), ref: ref }, (!disabled || (isVisibleWhenDisabled && isInitialized)) && (react_1.default.createElement(react_1.default.Fragment, null,
207
+ toolbarSections.map(function (section, i) { return (react_1.default.createElement("span", { className: "ql-formats", key: i }, section(disabled))); }),
208
+ hasMoreOptions && (react_1.default.createElement("button", { className: "more-options f6 fw5" + (isShowingMoreOptions ? ' expanded color-primary' : ''), type: "button", title: "More options", "aria-expanded": isShowingMoreOptions, onClick: function () { return setIsShowingMoreOptions(!isShowingMoreOptions); } },
209
+ react_1.default.createElement(MoreHoriz_1.default, { className: "ma0" }))),
210
+ // This is a sub-div so it's contained in the div with the id/guid for the forward ref.
211
+ // CSS handles appearance so it renders as if it were a sibling div.
212
+ hasMoreOptions && (react_1.default.createElement("div", { className: "more-options-toolbar ql-snow" + (isShowingMoreOptions ? ' expanded' : ' invisible'), "aria-hidden": !isShowingMoreOptions }, moreToolbarSections.map(function (section, i) { return (react_1.default.createElement("span", { className: "ql-formats", key: i }, section(disabled))); })))))));
213
+ };
214
+ exports.CustomToolbar = CustomToolbar;
@@ -0,0 +1,5 @@
1
+ import { FunctionComponent } from 'react';
2
+ export interface ImageMissingAltTextWarningProps {
3
+ className?: string;
4
+ }
5
+ export declare const ImageMissingAltTextWarning: FunctionComponent<ImageMissingAltTextWarningProps>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ImageMissingAltTextWarning = void 0;
7
+ var Warning_1 = __importDefault(require("@material-ui/icons/Warning"));
8
+ var react_1 = __importDefault(require("react"));
9
+ var ImageMissingAltTextWarning = function (_a) {
10
+ var className = _a.className;
11
+ return (react_1.default.createElement("p", { className: "small pv1 mv1" + (className ? " " + className : '') },
12
+ react_1.default.createElement(Warning_1.default, { className: "fill-orange nt1 mr1" }),
13
+ "One or more images are missing alt text. Use right-click to set alt text on images."));
14
+ };
15
+ exports.ImageMissingAltTextWarning = ImageMissingAltTextWarning;
@@ -0,0 +1,15 @@
1
+ import { RangeStatic } from 'quill';
2
+ import { FunctionComponent } from 'react';
3
+ import ReactQuill from 'react-quill';
4
+ import { ImageValue } from './Formats/Image';
5
+ interface ImageWithAltTextProps {
6
+ isOpen: boolean;
7
+ imageToEdit?: ImageValue;
8
+ supportedImageExtensions: string[];
9
+ onClose: () => void;
10
+ fileSelector: HTMLInputElement;
11
+ reactQuillRef: ReactQuill | null;
12
+ range: RangeStatic | undefined;
13
+ }
14
+ export declare const ImageWithAltTextModal: FunctionComponent<ImageWithAltTextProps>;
15
+ export {};
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.ImageWithAltTextModal = void 0;
26
+ var core_1 = require("@material-ui/core");
27
+ var Help_1 = __importDefault(require("@material-ui/icons/Help"));
28
+ var SwapVert_1 = __importDefault(require("@material-ui/icons/SwapVert"));
29
+ var lodash_1 = require("lodash");
30
+ var react_1 = __importStar(require("react"));
31
+ var react_bootstrap_1 = require("react-bootstrap");
32
+ var react_quill_1 = require("react-quill");
33
+ var ConnectedModal_1 = __importDefault(require("../ConnectedModal"));
34
+ var ErrorMessage_1 = require("../ErrorMessage");
35
+ var Delta = react_quill_1.Quill.import('delta');
36
+ var mdiUpload = 'M9,16V10H5L12,3L19,10H15V16H9M5,20V18H19V20H5Z';
37
+ var IconUpload = (react_1.default.createElement(core_1.SvgIcon, { role: "presentation" },
38
+ react_1.default.createElement("path", { d: mdiUpload })));
39
+ var ImageWithAltTextModal = function (_a) {
40
+ var isOpen = _a.isOpen, onClose = _a.onClose, imageToEdit = _a.imageToEdit, supportedImageExtensions = _a.supportedImageExtensions, fileSelector = _a.fileSelector, reactQuillRef = _a.reactQuillRef, range = _a.range;
41
+ // setup state that is editable in the modal, based on the targeted image, if any
42
+ var _b = react_1.useState(imageToEdit === null || imageToEdit === void 0 ? void 0 : imageToEdit.alt), alt = _b[0], setAlt = _b[1];
43
+ var _c = react_1.useState(imageToEdit === null || imageToEdit === void 0 ? void 0 : imageToEdit.src), src = _c[0], setSrc = _c[1];
44
+ var _d = react_1.useState(false), isSelectedFileInvalid = _d[0], setIsSelectedFileInvalid = _d[1];
45
+ // update local state based on the targeted image, if any
46
+ react_1.useEffect(function () {
47
+ if (imageToEdit) {
48
+ setAlt(imageToEdit.alt);
49
+ setSrc(imageToEdit.src);
50
+ }
51
+ }, [imageToEdit]);
52
+ var onTryClose = function () {
53
+ setAlt(undefined);
54
+ setSrc(undefined);
55
+ // programmatically reset file selector
56
+ fileSelector.value = '';
57
+ onClose();
58
+ };
59
+ /** Use file selector to get an image */
60
+ var onClickImageUpload = function () {
61
+ // programmatically click to open the file upload dialog
62
+ fileSelector.click();
63
+ // when a file is selected
64
+ fileSelector.onchange = function () {
65
+ var _a;
66
+ if (fileSelector.files && ((_a = fileSelector.files) === null || _a === void 0 ? void 0 : _a.length) > 0) {
67
+ var file_1 = fileSelector.files[0];
68
+ // convert filename to lowercase to make file extension check not case sensitive
69
+ setIsSelectedFileInvalid(!supportedImageExtensions.some(function (e) { return file_1.name.toLocaleLowerCase().endsWith(e); }));
70
+ var reader = new FileReader();
71
+ reader.onload = function (e) {
72
+ var _a;
73
+ if ((_a = e.target) === null || _a === void 0 ? void 0 : _a.DONE) {
74
+ // result is image in base64
75
+ setSrc(e.target.result);
76
+ if (!alt)
77
+ setAlt(file_1.name);
78
+ }
79
+ };
80
+ // get the file as a dataURI in base64
81
+ reader.readAsDataURL(file_1);
82
+ }
83
+ };
84
+ };
85
+ /** insert Image into quill */
86
+ var insertImage = function () {
87
+ if (reactQuillRef) {
88
+ var quill = reactQuillRef.getEditor();
89
+ var imageToInsert = { src: src, alt: alt };
90
+ if (imageToEdit) {
91
+ imageToInsert.height = imageToEdit.height;
92
+ imageToInsert.width = imageToEdit.width;
93
+ }
94
+ var index = range ? range.index : 0;
95
+ var diff = new Delta();
96
+ // retain up until the selected range
97
+ diff.retain(index);
98
+ // remove the existing image, if any
99
+ if (imageToEdit) {
100
+ diff.delete(1);
101
+ }
102
+ // insert the new image
103
+ diff.insert({ image: imageToInsert });
104
+ quill.updateContents(diff, 'user');
105
+ }
106
+ onTryClose();
107
+ };
108
+ return (react_1.default.createElement(ConnectedModal_1.default, { show: isOpen, onHide: onTryClose },
109
+ react_1.default.createElement(react_bootstrap_1.Modal.Header, { closeButton: true },
110
+ react_1.default.createElement(react_bootstrap_1.Modal.Title, { className: "f4" }, imageToEdit ? "Edit Alt Text" : "Image Upload")),
111
+ react_1.default.createElement(react_bootstrap_1.Modal.Body, null,
112
+ react_1.default.createElement("p", { className: "mb2 f7" }, "* Indicates required field"),
113
+ src && !isSelectedFileInvalid && (react_1.default.createElement(react_bootstrap_1.Row, null,
114
+ react_1.default.createElement("img", { className: "mb2 h5", src: src, alt: alt }))),
115
+ react_1.default.createElement("div", { "aria-live": "polite", className: "f7 mb2" }, isSelectedFileInvalid && (react_1.default.createElement(ErrorMessage_1.ErrorMessage, { message: "The chosen file type is not supported. Please use one of the image formats listed below." }))),
116
+ !imageToEdit && (react_1.default.createElement(react_1.default.Fragment, null,
117
+ react_1.default.createElement(core_1.Button, { className: "w-100-lt-xs pa2 mv1 btn-primary", onClick: onClickImageUpload },
118
+ src ? react_1.default.createElement(SwapVert_1.default, null) : IconUpload,
119
+ react_1.default.createElement("span", { className: "ml1" },
120
+ src ? 'Change' : 'Upload',
121
+ " Image")),
122
+ react_1.default.createElement("p", { className: "f7 mb3" }, "Supported formats: .jpg, .png, .gif, .bmp"))),
123
+ react_1.default.createElement(react_bootstrap_1.FormGroup, null,
124
+ react_1.default.createElement(react_bootstrap_1.Row, { className: "mb2" },
125
+ react_1.default.createElement("h3", { className: "mv0" },
126
+ react_1.default.createElement(react_bootstrap_1.FormLabel, { htmlFor: "img-alt-text", className: "mb0" },
127
+ "Alt Text *",
128
+ react_1.default.createElement(react_bootstrap_1.OverlayTrigger, { placement: "top", trigger: ['hover', 'focus'], overlay: react_1.default.createElement(react_bootstrap_1.Popover, { id: "alt-text-explanation" },
129
+ react_1.default.createElement("p", { className: "mb0" }, "Used by screen readers to describe the content of an image.")) },
130
+ react_1.default.createElement("button", { type: "button", className: "dib help-button bg-transparent" },
131
+ react_1.default.createElement(Help_1.default, { color: "primary", titleAccess: "Alt text explanation" })))))),
132
+ react_1.default.createElement(react_bootstrap_1.FormControl, { id: "img-alt-text", "aria-label": "Image Alt Text", as: "textarea", onChange: function (event) {
133
+ setAlt(event.target.value);
134
+ }, value: alt, spellCheck: false, autoComplete: "off", autoCorrect: "off" }))),
135
+ react_1.default.createElement(react_bootstrap_1.Modal.Footer, null,
136
+ react_1.default.createElement(core_1.Button, { className: "mr1 btn-text color-primary", onClick: onTryClose }, "Cancel"),
137
+ react_1.default.createElement(core_1.Button, { className: "btn-primary mb1", id: "save-image-button", onClick: insertImage, disabled: lodash_1.isEmpty(alt === null || alt === void 0 ? void 0 : alt.trim()) || lodash_1.isEmpty(src) || isSelectedFileInvalid }, "Save"))));
138
+ };
139
+ exports.ImageWithAltTextModal = ImageWithAltTextModal;
@@ -61,7 +61,7 @@
61
61
  }
62
62
 
63
63
  &:hover {
64
- background-color: var(--color-purple);
64
+ background-color: var(--color-primary);
65
65
 
66
66
  &::before {
67
67
  color: var(--color-white);
@@ -1 +1,3 @@
1
1
  export declare const registerQuill: () => void;
2
+ export declare const supportedFileExtensions: string[];
3
+ export declare const buildFileSelector: () => HTMLInputElement;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.registerQuill = void 0;
6
+ exports.buildFileSelector = exports.supportedFileExtensions = exports.registerQuill = void 0;
7
7
  var quill_blot_formatter_1 = __importDefault(require("quill-blot-formatter"));
8
8
  var react_quill_1 = require("react-quill");
9
9
  var accessibilityFix_1 = require("./accessibilityFix");
@@ -25,3 +25,12 @@ var registerQuill = function () {
25
25
  accessibilityFix_1.applyAccessibilityToIcons(react_quill_1.Quill.import('ui/icons'));
26
26
  };
27
27
  exports.registerQuill = registerQuill;
28
+ exports.supportedFileExtensions = ['.png', '.jpeg', '.jpg', '.gif', '.bmp'];
29
+ // Get the file dialog upload programmatically
30
+ var buildFileSelector = function () {
31
+ var fileSelector = document.createElement('input');
32
+ fileSelector.setAttribute('type', 'file');
33
+ fileSelector.setAttribute('accept', exports.supportedFileExtensions.join(', '));
34
+ return fileSelector;
35
+ };
36
+ exports.buildFileSelector = buildFileSelector;
@@ -104,6 +104,11 @@ a[class*="btn-"]:active:focus {
104
104
  .btn-primary {
105
105
  color: var(--color-white);
106
106
  white-space: normal;
107
+ background-color: var(--color-primary);
108
+
109
+ &:hover {
110
+ background-color: color-mod(var(--color-primary) l(+7%) s(+15%));
111
+ }
107
112
 
108
113
  &:active,
109
114
  &:focus,
@@ -114,6 +119,7 @@ a[class*="btn-"]:active:focus {
114
119
  outline-offset: -2px;
115
120
  box-shadow: none;
116
121
  color: var(--color-white);
122
+ background-color: var(--color-primary);
117
123
  }
118
124
  }
119
125
 
@@ -133,18 +139,18 @@ a[class*="btn-"]:active:focus {
133
139
 
134
140
  /* Bad */
135
141
  .btn-bad {
136
- background-color: var(--color-pink);
142
+ background-color: var(--color-error);
137
143
  white-space: normal;
138
144
 
139
145
  &:hover {
140
146
  color: var(--color-white);
141
- background-color: color-mod(var(--color-pink) l(+7%) s(+15%));
147
+ background-color: color-mod(var(--color-error) l(+7%) s(+15%));
142
148
  }
143
149
 
144
150
  &:active,
145
151
  &:focus,
146
152
  &:active:focus {
147
- background-color: var(--color-pink);
153
+ background-color: var(--color-error);
148
154
  color: var(--color-white);
149
155
  }
150
156
  }
@@ -161,6 +167,11 @@ a[class*="btn-"]:active:focus {
161
167
  margin-left: 0.5rem;
162
168
  }
163
169
 
170
+ &.color-primary:hover {
171
+ color: var(--color-primary);
172
+ background-color: color-mod(var(--color-primary) a(4%));
173
+ }
174
+
164
175
  &.color-purple:hover {
165
176
  color: var(--color-purple);
166
177
  background-color: color-mod(var(--color-purple) a(4%));
@@ -344,7 +355,7 @@ button.close > span {
344
355
  }
345
356
 
346
357
  .MuiSwitch-switchBase .MuiTouchRipple-root {
347
- color: var(--color-blue);
358
+ color: var(--color-primary);
348
359
  }
349
360
 
350
361
  .MuiSwitch-switchBase.MuiSwitch-checked .MuiTouchRipple-root {
@@ -367,3 +378,20 @@ button.close > span {
367
378
  }
368
379
  }
369
380
  }
381
+
382
+ .MuiToggleButton-root {
383
+ color: var(--color-primary);
384
+
385
+ &.Mui-selected {
386
+ background-color: var(--color-primary);
387
+ color: var(--color-white);
388
+
389
+ &:hover {
390
+ background-color: color-mod(var(--color-primary) l(+7%) s(+15%));
391
+ }
392
+
393
+ &:focus {
394
+ background-color: var(--color-primary);
395
+ }
396
+ }
397
+ }
@@ -0,0 +1,314 @@
1
+ @custom-selector :--quill-typography h1, h2, h3, h4, h5, h6, p, ol, ul, pre, blockquote;
2
+ @custom-selector :--quill-plaintext p, ol, ul;
3
+
4
+ :root {
5
+ --quill-min-height: 10rem;
6
+ --quill-max-height: 60vh;
7
+ --quill-toolbars-height: 111px;
8
+ }
9
+
10
+ .quill {
11
+ margin-bottom: 15px;
12
+ }
13
+
14
+ /* Loader */
15
+
16
+ .quill-loader {
17
+ min-height: calc(var(--quill-min-height) + var(--quill-toolbars-height));
18
+ max-height: calc(var(--quill-max-height) + var(--quill-toolbars-height));
19
+ position: relative;
20
+ border: 1px solid var(--color-light-grey);
21
+ }
22
+
23
+ .quill-loader-inner {
24
+ position: absolute;
25
+ top: calc(50% - 20px - 1.25rem);
26
+ left: calc(50% - 20px);
27
+ }
28
+
29
+ /* Editor */
30
+
31
+ .ql-editor {
32
+ background-color: var(--color-white);
33
+ min-height: var(--quill-min-height);
34
+ max-height: var(--quill-max-height);
35
+ overflow: auto;
36
+
37
+ & :--quill-typography {
38
+ margin-bottom: 1.1rem;
39
+ }
40
+
41
+ & :--quill-plaintext {
42
+ font-size: 1rem;
43
+ }
44
+ }
45
+
46
+ /* Expandable toolbar */
47
+
48
+ .more-options {
49
+ float: right !important;
50
+ padding: 0 0 0 2px !important;
51
+ height: 30px !important;
52
+
53
+ &.expanded {
54
+ background: var(--color-light-grey) !important;
55
+ }
56
+ }
57
+
58
+ .more-options-toolbar {
59
+ border-top: 0 solid var(--color-light-grey);
60
+ margin: 0;
61
+ padding: 0;
62
+ height: 0;
63
+ transition: border-top linear 0.05s, margin linear 0.3s, padding linear 0.3s, height linear 0.3s, visibility linear 0.5s;
64
+
65
+ & .ql-formats {
66
+ opacity: 0;
67
+ transition: opacity linear 0.3s;
68
+ }
69
+
70
+ &.expanded {
71
+ border-top: 1px solid var(--color-light-grey);
72
+ margin: 0.6rem -0.6rem 0;
73
+ padding: 0.6rem 0.6rem 0;
74
+ height: 36px;
75
+
76
+ & .ql-formats {
77
+ opacity: 1;
78
+ }
79
+ }
80
+ }
81
+
82
+ /* Toolbar */
83
+
84
+ .ql-toolbar.ql-snow {
85
+ padding: 0.6rem;
86
+
87
+ &.disabled-invisible {
88
+ padding: 0;
89
+ height: 0;
90
+ border-bottom: none;
91
+ }
92
+
93
+ &.read-only {
94
+ background-color: var(--color-off-white);
95
+ padding-top: 1rem;
96
+ }
97
+
98
+ &.Inline {
99
+ background-color: var(--color-white);
100
+ border-style: none;
101
+ padding-left: 2px;
102
+ padding-top: 1.2rem;
103
+ border-top-right-radius: 0.5rem;
104
+ border-bottom-right-radius: 0.5rem;
105
+
106
+ &.read-only {
107
+ background-color: var(--color-off-white);
108
+ }
109
+ }
110
+ }
111
+
112
+ .ql-container.ql-snow {
113
+ border-top: none;
114
+ overflow: visible;
115
+ }
116
+
117
+ .ql-toolbar.ql-snow .ql-formats {
118
+ margin-right: 10px;
119
+
120
+ &:last-child {
121
+ margin-right: 0;
122
+ }
123
+ }
124
+
125
+ /* Align */
126
+
127
+ .ql-align svg {
128
+ float: left;
129
+ }
130
+
131
+ /* Alpha Ordered List */
132
+
133
+ .ql-editor ol[data-value="alpha"] > li {
134
+ &::before {
135
+ content: counter(list-0, lower-alpha) '. ';
136
+ }
137
+
138
+ &.ql-indent-1::before {
139
+ content: counter(list-1, lower-roman) '. ';
140
+ }
141
+
142
+ &.ql-indent-2::before {
143
+ content: counter(list-2, decimal) '. ';
144
+ }
145
+
146
+ &.ql-indent-3::before {
147
+ content: counter(list-3, lower-alpha) '. ';
148
+ }
149
+
150
+ &.ql-indent-4::before {
151
+ content: counter(list-4, lower-roman) '. ';
152
+ }
153
+
154
+ &.ql-indent-5::before {
155
+ content: counter(list-5, decimal) '. ';
156
+ }
157
+
158
+ &.ql-indent-6::before {
159
+ content: counter(list-6, lower-alpha) '. ';
160
+ }
161
+
162
+ &.ql-indent-7::before {
163
+ content: counter(list-7, lower-roman) '. ';
164
+ }
165
+
166
+ &.ql-indent-8::before {
167
+ content: counter(list-8, decimal) '. ';
168
+ }
169
+ }
170
+
171
+ /* Images */
172
+
173
+ .ql-snow .ql-editor img {
174
+ max-width: 100%;
175
+ object-fit: contain;
176
+ }
177
+
178
+ /* Disabled and Read Only */
179
+
180
+ .ql-disabled {
181
+ & .ql-editor {
182
+ background-color: var(--color-off-white);
183
+ }
184
+ }
185
+
186
+ .blurred-editor {
187
+ overflow-y: auto;
188
+
189
+ & .ql-editor {
190
+ min-height: auto;
191
+ max-height: none;
192
+ padding: 0;
193
+ background-color: var(--color-white);
194
+ }
195
+
196
+ & .ql-toolbar {
197
+ display: none;
198
+ }
199
+
200
+ & .ql-container.ql-snow {
201
+ border: none;
202
+ }
203
+ }
204
+
205
+ /* stylelint-disable no-descending-specificity */
206
+ .ql-snow.ql-toolbar,
207
+ .ql-snow .ql-toolbar {
208
+ /* Hover/Focus/Active overrides */
209
+ & button:hover,
210
+ & button:focus,
211
+ & button.ql-active,
212
+ & .ql-picker-label:hover,
213
+ & .ql-picker-label:focus,
214
+ & .ql-picker-label.ql-active,
215
+ & .ql-picker-item:hover,
216
+ & .ql-picker-item:focus,
217
+ & .ql-picker-item.ql-selected {
218
+ color: var(--color-primary) !important;
219
+
220
+ & .ql-fill,
221
+ & .ql-stroke.ql-fill {
222
+ fill: var(--color-primary) !important;
223
+ }
224
+
225
+ & .ql-stroke {
226
+ stroke: var(--color-primary) !important;
227
+ }
228
+ }
229
+
230
+ /* Focus overrides */
231
+ & button:focus,
232
+ & button.ql-active,
233
+ & .ql-picker-label:focus,
234
+ & .ql-picker-label.ql-active,
235
+ & .ql-picker-item:focus,
236
+ & .ql-picker-item.ql-selected {
237
+ outline: 2px solid var(--color-primary) !important;
238
+ }
239
+
240
+ /* Disabled overrides */
241
+ & .ql-formula:disabled,
242
+ & button:disabled,
243
+ & button:hover:disabled,
244
+ & button:focus:disabled,
245
+ & button.ql-active:disabled {
246
+ color: #777 !important;
247
+ cursor: default;
248
+
249
+ & svg {
250
+ cursor: default;
251
+ }
252
+
253
+ & .ql-fill,
254
+ & .ql-stroke.ql-fill {
255
+ fill: #777 !important;
256
+ cursor: default;
257
+ }
258
+
259
+ & .ql-stroke {
260
+ stroke: #777 !important;
261
+ }
262
+ }
263
+ }
264
+
265
+ /* Inline - display with no background */
266
+
267
+ .quill.inline {
268
+ margin-bottom: 0;
269
+
270
+ & .ql-container {
271
+ background-color: transparent;
272
+ }
273
+
274
+ & .ql-editor {
275
+ background-color: transparent;
276
+ padding: 0.5rem 0;
277
+ }
278
+
279
+ & p:last-of-type {
280
+ margin-bottom: 0;
281
+ }
282
+ }
283
+
284
+ /* Hide line break in otherwise empty paragraph immediately preceded by a list */
285
+ .quill.blurred-editor {
286
+ & ol ~ p br:only-child,
287
+ & ul ~ p br:only-child {
288
+ display: none;
289
+ }
290
+ }
291
+
292
+ .quill:focus-within {
293
+ border-color: #80bdff;
294
+ box-shadow: 0 0 0 0.2rem rgb(0 123 255 / 25%);
295
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
296
+ position: relative;
297
+ z-index: 1;
298
+
299
+ & .ql-container.ql-snow {
300
+ border-color: #80bdff;
301
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
302
+ }
303
+ }
304
+
305
+ .error {
306
+ & .quill:focus-within {
307
+ border-color: var(--color-red);
308
+ box-shadow: 0 0 0 0.2rem rgb(220 53 69 / 25%);
309
+
310
+ & .ql-container.ql-snow {
311
+ border-color: var(--color-red);
312
+ }
313
+ }
314
+ }
@@ -90,6 +90,20 @@
90
90
  color: var(--color-green);
91
91
  }
92
92
 
93
+ /* Theme Colors */
94
+
95
+ .color-primary {
96
+ color: var(--color-primary);
97
+ }
98
+
99
+ .color-error {
100
+ color: var(--color-error);
101
+ }
102
+
103
+ .color-success {
104
+ color: var(--color-success);
105
+ }
106
+
93
107
  /* Background Colors */
94
108
 
95
109
  .bg-color-black {
@@ -180,6 +194,18 @@
180
194
  background-color: var(--color-green);
181
195
  }
182
196
 
197
+ .bg-color-primary {
198
+ background-color: var(--color-primary);
199
+ }
200
+
201
+ .bg-color-error {
202
+ background-color: var(--color-error);
203
+ }
204
+
205
+ .bg-color-success {
206
+ background-color: var(--color-success);
207
+ }
208
+
183
209
  /* Custom Fill Colors */
184
210
 
185
211
  .fill-black {
@@ -269,3 +295,15 @@
269
295
  .fill-green {
270
296
  fill: var(--color-green);
271
297
  }
298
+
299
+ .fill-primary {
300
+ fill: var(--color-primary);
301
+ }
302
+
303
+ .fill-error {
304
+ fill: var(--color-error);
305
+ }
306
+
307
+ .fill-success {
308
+ fill: var(--color-success);
309
+ }
@@ -47,6 +47,14 @@
47
47
  --color-red: #c93d44;
48
48
  --color-green: #7bcf64;
49
49
 
50
+ /**
51
+ * Themed Colors
52
+ * These will be customized per app
53
+ */
54
+ --color-primary: var(--color-blue);
55
+ --color-error: var(--color-red);
56
+ --color-success: var(--color-green);
57
+
50
58
  /* Border Radius */
51
59
  --border-radius: 3px;
52
60
  }
@@ -0,0 +1,9 @@
1
+ import { BoundsStatic, DeltaStatic, RangeStatic } from 'quill';
2
+ export interface UnprivilegedEditor {
3
+ getLength(): number;
4
+ getText(index?: number, length?: number): string;
5
+ getHTML(): string;
6
+ getBounds(index: number, length?: number): BoundsStatic;
7
+ getSelection(focus?: boolean): RangeStatic;
8
+ getContents(index?: number, length?: number): DeltaStatic;
9
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -13,6 +13,7 @@ export * from './Notification';
13
13
  export * from './OptionalRecord';
14
14
  export * from './OwnerSchedule';
15
15
  export * from './PropertyOfType';
16
+ export * from './Quill';
16
17
  export * from './RoleDescription';
17
18
  export * from './Search';
18
19
  export * from './SimpleLocation';
@@ -25,6 +25,7 @@ __exportStar(require("./Notification"), exports);
25
25
  __exportStar(require("./OptionalRecord"), exports);
26
26
  __exportStar(require("./OwnerSchedule"), exports);
27
27
  __exportStar(require("./PropertyOfType"), exports);
28
+ __exportStar(require("./Quill"), exports);
28
29
  __exportStar(require("./RoleDescription"), exports);
29
30
  __exportStar(require("./Search"), exports);
30
31
  __exportStar(require("./SimpleLocation"), exports);
@@ -0,0 +1,9 @@
1
+ import { DeltaStatic } from 'quill';
2
+ /**
3
+ * Find whether there are any image operations without alt text in the provided quill contents.
4
+ *
5
+ * @param contents The contents of quill.
6
+ *
7
+ * @returns True if there are any images without alt text
8
+ */
9
+ export declare const hasSomeMissingAltText: (contents: DeltaStatic) => boolean;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hasSomeMissingAltText = void 0;
4
+ /**
5
+ * Find whether there are any image operations without alt text in the provided quill contents.
6
+ *
7
+ * @param contents The contents of quill.
8
+ *
9
+ * @returns True if there are any images without alt text
10
+ */
11
+ var hasSomeMissingAltText = function (contents) { var _a; return ((_a = contents.ops) === null || _a === void 0 ? void 0 : _a.some(function (op) { var _a, _b, _c; return ((_a = op.insert) === null || _a === void 0 ? void 0 : _a.image) && !((_c = (_b = op.insert) === null || _b === void 0 ? void 0 : _b.image.alt) === null || _c === void 0 ? void 0 : _c.trim()); })) || false; };
12
+ exports.hasSomeMissingAltText = hasSomeMissingAltText;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "studiokit-scaffolding-js",
3
- "version": "4.9.0-next.2.1",
3
+ "version": "4.10.0",
4
4
  "description": "Common scaffolding for Studio apps at Purdue",
5
5
  "repository": "https://gitlab.com/purdue-informatics/studiokit/studiokit-scaffolding-js",
6
6
  "license": "MIT",
@@ -136,7 +136,7 @@
136
136
  "react-ga": "^3.3.0",
137
137
  "react-helmet": "^6.1.0",
138
138
  "react-modal": "^3.12.1",
139
- "react-quill": "^1.3.5",
139
+ "react-quill": "purdue-tlt/react-quill#fix/auto-focus",
140
140
  "react-redux": "^7.2.2",
141
141
  "react-router": "^5.2.0",
142
142
  "react-router-bootstrap": "^0.25.0",