@internetstiftelsen/styleguide 2.19.5 → 2.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atoms/textarea/rich-text.js +167 -0
- package/dist/focusTrap.js +5 -0
- package/dist/molecules/modal/modal.js +80 -4
- package/package.json +4 -1
- package/src/app.js +2 -1
- package/src/app.scss +1 -0
- package/src/atoms/textarea/_textarea.scss +21 -41
- package/src/atoms/textarea/rich-text.js +168 -0
- package/src/atoms/textarea/textarea.config.js +9 -1
- package/src/atoms/textarea/textarea.hbs +13 -10
- package/src/configurations/_extends.scss +1 -1
- package/src/configurations/colors/_colors-functions.scss +19 -0
- package/src/configurations/colors/_wordpress-colors.scss +12 -0
- package/src/focusTrap.js +1 -1
- package/src/molecules/modal/_modal.scss +11 -0
- package/src/molecules/modal/modal.js +73 -4
- package/src/organisms/footer/_footer.scss +96 -58
- package/src/organisms/footer/footer.config.js +4 -4
- package/src/organisms/footer/footer.hbs +110 -100
- package/src/theme/_theme.scss +15 -0
- package/src/.DS_Store +0 -0
- package/src/atoms/.DS_Store +0 -0
- package/src/atoms/icon/.DS_Store +0 -0
- package/src/molecules/.DS_Store +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _core = require('@tiptap/core');
|
|
4
|
+
|
|
5
|
+
var _starterKit = require('@tiptap/starter-kit');
|
|
6
|
+
|
|
7
|
+
var _starterKit2 = _interopRequireDefault(_starterKit);
|
|
8
|
+
|
|
9
|
+
var _extensionLink = require('@tiptap/extension-link');
|
|
10
|
+
|
|
11
|
+
var _className = require('../../assets/js/className');
|
|
12
|
+
|
|
13
|
+
var _className2 = _interopRequireDefault(_className);
|
|
14
|
+
|
|
15
|
+
var _modal = require('../../molecules/modal/modal');
|
|
16
|
+
|
|
17
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
|
+
|
|
19
|
+
function clearAndCapitalize(str) {
|
|
20
|
+
return str.replace(/-/, '').toUpperCase();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function kebabToCamel(str) {
|
|
24
|
+
return str.replace(/-\w/g, clearAndCapitalize);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function kebabToPascal(str) {
|
|
28
|
+
return str.replace(/(^\w|-\w)/g, clearAndCapitalize);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function insertLink(el, editor) {
|
|
32
|
+
var addLink = function addLink(e, modal, close) {
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
|
|
35
|
+
var value = modal.querySelector('input').value.trim();
|
|
36
|
+
|
|
37
|
+
if (!value.length) {
|
|
38
|
+
editor.commands.unsetLink();
|
|
39
|
+
} else {
|
|
40
|
+
var isAbsolute = new RegExp('(?:^[a-z][a-z0-9+.-]*:|//)', 'i');
|
|
41
|
+
|
|
42
|
+
if (!isAbsolute.test(value)) {
|
|
43
|
+
value = 'https://' + value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
editor.commands.toggleLink({ href: value });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
close();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
if (editor.view.state.selection.empty) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
var currentValue = editor.getAttributes('link').href ? editor.getAttributes('link').href : '';
|
|
57
|
+
|
|
58
|
+
(0, _modal.open)({
|
|
59
|
+
title: 'Lägg till länk',
|
|
60
|
+
content: '\n\t\t\t<p class="u-m-b-0 u-m-t-default"><input type="url" value="' + currentValue + '" class="' + (0, _className2.default)('a-input') + '"></p>\n\t\t',
|
|
61
|
+
actions: [{
|
|
62
|
+
text: 'Avbryt',
|
|
63
|
+
color: 'transparent',
|
|
64
|
+
attrs: {
|
|
65
|
+
'data-modal-close': null
|
|
66
|
+
}
|
|
67
|
+
}, {
|
|
68
|
+
text: 'Spara',
|
|
69
|
+
modifier: 'primary',
|
|
70
|
+
key: 'enter',
|
|
71
|
+
onClick: addLink
|
|
72
|
+
}]
|
|
73
|
+
}, {
|
|
74
|
+
onOpen: function onOpen(id, modal) {
|
|
75
|
+
modal.querySelector('input').focus();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function createToolbarButton(el, control, editor) {
|
|
81
|
+
var button = document.createElement('button');
|
|
82
|
+
var iconId = ['link'].includes(control) ? control : 'richtext-' + control;
|
|
83
|
+
|
|
84
|
+
button.setAttribute('data-rich-text-control', control);
|
|
85
|
+
button.value = kebabToCamel(control);
|
|
86
|
+
button.innerHTML = '\n\t\t<span class="u-visuallyhidden">' + control.replace('-', ' ') + '</span>\n\t\t<svg class="icon">\n\t\t\t<use xlink:href="#icon-' + iconId + '"></use>\n\t\t</svg>\n\t';
|
|
87
|
+
|
|
88
|
+
el.appendChild(button);
|
|
89
|
+
|
|
90
|
+
button.addEventListener('click', function (e) {
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
|
|
93
|
+
if (control === 'link') {
|
|
94
|
+
insertLink(el, editor);
|
|
95
|
+
} else {
|
|
96
|
+
var method = 'toggle' + kebabToPascal(control);
|
|
97
|
+
|
|
98
|
+
editor.chain().focus()[method]().run();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function toogleButtonState(editor, el) {
|
|
104
|
+
[].forEach.call(el.parentNode.querySelectorAll('[data-rich-text-control]'), function (control) {
|
|
105
|
+
if (editor.isActive(control.value)) {
|
|
106
|
+
control.classList.add('is-active');
|
|
107
|
+
} else {
|
|
108
|
+
control.classList.remove('is-active');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (control.value === 'link' && editor.view.state.selection.empty) {
|
|
112
|
+
control.disabled = true;
|
|
113
|
+
} else if (control.value === 'link') {
|
|
114
|
+
control.disabled = false;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function createToolbar(el, editor) {
|
|
120
|
+
var toolbar = document.createElement('div');
|
|
121
|
+
|
|
122
|
+
toolbar.className = (0, _className2.default)('a-textarea__toolbar');
|
|
123
|
+
|
|
124
|
+
el.parentNode.insertBefore(toolbar, el);
|
|
125
|
+
|
|
126
|
+
['bold', 'italic', 'link', 'bullet-list'].forEach(function (control) {
|
|
127
|
+
createToolbarButton(toolbar, control, editor);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function setupTextArea(el) {
|
|
132
|
+
var editorEl = document.createElement('div');
|
|
133
|
+
var editor = new _core.Editor({
|
|
134
|
+
element: editorEl,
|
|
135
|
+
extensions: [_starterKit2.default, _extensionLink.Link.configure({
|
|
136
|
+
openOnClick: false,
|
|
137
|
+
HTMLAttributes: {
|
|
138
|
+
class: 'u-link'
|
|
139
|
+
}
|
|
140
|
+
})],
|
|
141
|
+
content: el.value,
|
|
142
|
+
onTransaction: function onTransaction(props) {
|
|
143
|
+
toogleButtonState(props.editor, editorEl);
|
|
144
|
+
},
|
|
145
|
+
onUpdate: function onUpdate(props) {
|
|
146
|
+
el.value = props.editor.getHTML();
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
editorEl.className = el.className;
|
|
151
|
+
editorEl.classList.add((0, _className2.default)('a-textarea--rich-text'));
|
|
152
|
+
|
|
153
|
+
el.style.display = 'none';
|
|
154
|
+
el.editor = editor;
|
|
155
|
+
|
|
156
|
+
el.parentNode.insertBefore(editorEl, el);
|
|
157
|
+
|
|
158
|
+
createToolbar(editorEl, editor);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
var els = document.querySelectorAll('textarea[data-rich-text]');
|
|
162
|
+
|
|
163
|
+
if (els.length) {
|
|
164
|
+
[].forEach.call(els, function (el) {
|
|
165
|
+
return setupTextArea(el, _core.Editor, _starterKit2.default);
|
|
166
|
+
});
|
|
167
|
+
}
|
package/dist/focusTrap.js
CHANGED
|
@@ -9,6 +9,10 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
|
|
|
9
9
|
|
|
10
10
|
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
|
|
11
11
|
|
|
12
|
+
var _focusTrap = require('../../focusTrap');
|
|
13
|
+
|
|
14
|
+
var _focusTrap2 = _interopRequireDefault(_focusTrap);
|
|
15
|
+
|
|
12
16
|
var _className = require('../../assets/js/className');
|
|
13
17
|
|
|
14
18
|
var _className2 = _interopRequireDefault(_className);
|
|
@@ -24,6 +28,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
24
28
|
* @property {string} text - action content
|
|
25
29
|
* @property {string} url - action link url
|
|
26
30
|
* @property {string} target - action link target
|
|
31
|
+
* @property {string} key - action click handler key shortcut
|
|
27
32
|
* @property {function} onClick - action click handler
|
|
28
33
|
* @property {object} attrs – action element attributes
|
|
29
34
|
*/
|
|
@@ -52,6 +57,7 @@ var modal = null;
|
|
|
52
57
|
var modalContent = null;
|
|
53
58
|
var modalActions = null;
|
|
54
59
|
var modalClose = null;
|
|
60
|
+
var keyHandlers = {};
|
|
55
61
|
|
|
56
62
|
/**
|
|
57
63
|
* Increase increment ID and return the latest
|
|
@@ -75,7 +81,7 @@ function objectToAttributes(obj) {
|
|
|
75
81
|
key = _ref4[0],
|
|
76
82
|
value = _ref4[1];
|
|
77
83
|
|
|
78
|
-
return key + '=' + value;
|
|
84
|
+
return value !== null ? key + '=' + value : key;
|
|
79
85
|
}).join(' ');
|
|
80
86
|
}
|
|
81
87
|
|
|
@@ -87,7 +93,15 @@ function objectToAttributes(obj) {
|
|
|
87
93
|
function addAction(action) {
|
|
88
94
|
var icon = action.icon ? '\n\t\t<svg class="icon ' + (0, _className2.default)('a-button__icon') + '">\n\t\t\t<use xlink:href="#icon-' + action.icon + '"></use>\n\t\t</svg>\n\t' : '';
|
|
89
95
|
|
|
90
|
-
var cls = (0, _className2.default)('a-button
|
|
96
|
+
var cls = (0, _className2.default)('a-button') + ' u-m-l-2';
|
|
97
|
+
|
|
98
|
+
if (action.color) {
|
|
99
|
+
cls += ' ' + (0, _className2.default)('a-button--' + action.color);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (action.modifier) {
|
|
103
|
+
cls += ' ' + (0, _className2.default)('m-modal__button-' + action.modifier);
|
|
104
|
+
}
|
|
91
105
|
|
|
92
106
|
if (action.icon) {
|
|
93
107
|
cls += ' ' + (0, _className2.default)('a-button--icon');
|
|
@@ -96,7 +110,32 @@ function addAction(action) {
|
|
|
96
110
|
var tag = action.url ? 'a' : 'button';
|
|
97
111
|
var button = '\n\t\t<' + tag + ' ' + objectToAttributes(_extends({}, action.attrs, { href: action.url, target: action.target })) + ' class="' + cls + '">\n\t\t\t<span class="' + (0, _className2.default)('a-button__text') + '">' + action.text + '</span>\n\t\t\t' + icon + '\n\t\t</' + tag + '>\n\t';
|
|
98
112
|
|
|
99
|
-
|
|
113
|
+
var dummy = document.createElement('div');
|
|
114
|
+
|
|
115
|
+
dummy.innerHTML = button;
|
|
116
|
+
|
|
117
|
+
var el = dummy.firstElementChild;
|
|
118
|
+
modalActions.appendChild(el);
|
|
119
|
+
|
|
120
|
+
if (action.onClick) {
|
|
121
|
+
el.addEventListener('click', function (e) {
|
|
122
|
+
// eslint-disable-next-line no-use-before-define
|
|
123
|
+
action.onClick(e, modal, close);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function handleKeyUp(e) {
|
|
129
|
+
Object.entries(keyHandlers).forEach(function (_ref5) {
|
|
130
|
+
var _ref6 = _slicedToArray(_ref5, 2),
|
|
131
|
+
key = _ref6[0],
|
|
132
|
+
handler = _ref6[1];
|
|
133
|
+
|
|
134
|
+
if (e.key.toLowerCase() === key) {
|
|
135
|
+
// eslint-disable-next-line no-use-before-define
|
|
136
|
+
handler(e, modal, close);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
100
139
|
}
|
|
101
140
|
|
|
102
141
|
/**
|
|
@@ -120,11 +159,30 @@ function display() {
|
|
|
120
159
|
}
|
|
121
160
|
}
|
|
122
161
|
|
|
162
|
+
(0, _focusTrap2.default)(active.el);
|
|
163
|
+
|
|
123
164
|
active.el.setAttribute('aria-hidden', 'false');
|
|
124
165
|
|
|
125
166
|
if (active.settings.onOpen) {
|
|
126
|
-
active.settings.onOpen(active.id);
|
|
167
|
+
active.settings.onOpen(active.id, active.el);
|
|
127
168
|
}
|
|
169
|
+
|
|
170
|
+
setTimeout(function () {
|
|
171
|
+
if (active.el.focusTrap) {
|
|
172
|
+
active.el.focusTrap.activate();
|
|
173
|
+
}
|
|
174
|
+
}, 1);
|
|
175
|
+
|
|
176
|
+
// Just to make sure
|
|
177
|
+
keyHandlers = {};
|
|
178
|
+
|
|
179
|
+
active.content.actions.forEach(function (action) {
|
|
180
|
+
if (action.key && action.onClick) {
|
|
181
|
+
keyHandlers[action.key] = action.onClick;
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
document.addEventListener('keyup', handleKeyUp);
|
|
128
186
|
}
|
|
129
187
|
|
|
130
188
|
/**
|
|
@@ -152,6 +210,24 @@ function close() {
|
|
|
152
210
|
active.settings.onClose(active.id);
|
|
153
211
|
}
|
|
154
212
|
|
|
213
|
+
active.content.actions.forEach(function (action) {
|
|
214
|
+
if (action.key && action.onClick) {
|
|
215
|
+
document.addEventListener('keyup', function (e) {
|
|
216
|
+
if (e.key.toLowerCase() === action.key) {
|
|
217
|
+
// eslint-disable-next-line no-use-before-define
|
|
218
|
+
action.onClick(e, modal, close);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
document.removeEventListener('keyup', handleKeyUp);
|
|
225
|
+
|
|
226
|
+
if (active.el.focusTrap) {
|
|
227
|
+
active.el.focusTrap.deactivate();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
keyHandlers = {};
|
|
155
231
|
active = null;
|
|
156
232
|
}
|
|
157
233
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@internetstiftelsen/styleguide",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.1",
|
|
4
4
|
"main": "dist/components.js",
|
|
5
5
|
"ports": {
|
|
6
6
|
"fractal": "3000"
|
|
@@ -66,6 +66,9 @@
|
|
|
66
66
|
"uglify-es": "^3.3.9"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
+
"@tiptap/core": "^2.0.0-beta.131",
|
|
70
|
+
"@tiptap/extension-link": "^2.0.0-beta.25",
|
|
71
|
+
"@tiptap/starter-kit": "^2.0.0-beta.133",
|
|
69
72
|
"a11y-toggle": "^2.1.0",
|
|
70
73
|
"focus-trap": "^4.0.2",
|
|
71
74
|
"glider-js": "^1.7.7",
|
package/src/app.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import './molecules/form';
|
|
2
|
+
import './atoms/textarea/rich-text';
|
|
2
3
|
|
|
3
4
|
require('./atoms/grid-toggle/grid-toggle');
|
|
4
5
|
require('./components');
|
|
@@ -39,7 +40,7 @@ if (demoModal) {
|
|
|
39
40
|
color: 'peacock-light',
|
|
40
41
|
modifier: 'primary',
|
|
41
42
|
attrs: {
|
|
42
|
-
'data-modal-
|
|
43
|
+
'data-modal-close': null,
|
|
43
44
|
},
|
|
44
45
|
},
|
|
45
46
|
{
|
package/src/app.scss
CHANGED
|
@@ -8,6 +8,7 @@ $namespace: '';
|
|
|
8
8
|
// Configurations
|
|
9
9
|
@import 'configurations/grid/grid';
|
|
10
10
|
@import 'configurations/colors/colors';
|
|
11
|
+
@import 'configurations/colors/wordpress-colors';
|
|
11
12
|
@import 'configurations/colors/colors-functions';
|
|
12
13
|
@import 'configurations/colors/text-colors';
|
|
13
14
|
@import 'configurations/colors/background-colors';
|
|
@@ -18,50 +18,30 @@
|
|
|
18
18
|
@include m(discreet) {
|
|
19
19
|
@extend %discreet;
|
|
20
20
|
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.ql-editor {
|
|
24
|
-
@extend %input;
|
|
25
|
-
|
|
26
|
-
min-width: 100%;
|
|
27
|
-
max-width: 100%;
|
|
28
|
-
min-height: 100px;
|
|
29
21
|
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
@include m(rich-text) {
|
|
23
|
+
min-height: auto;
|
|
24
|
+
|
|
25
|
+
> div {
|
|
26
|
+
min-height: rhythm(12);
|
|
27
|
+
|
|
28
|
+
p,
|
|
29
|
+
ul,
|
|
30
|
+
ol {
|
|
31
|
+
@include plumber(
|
|
32
|
+
$font-size: 1.75,
|
|
33
|
+
$leading-bottom: 2
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
32
37
|
}
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
p {
|
|
39
|
-
font-size: rem(16px);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.ql-toolbar {
|
|
44
|
-
button {
|
|
45
|
-
@extend %button-toolbar;
|
|
39
|
+
@include e(toolbar) {
|
|
40
|
+
button {
|
|
41
|
+
@extend %button-toolbar;
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
margin-right: rhythm(0.5);
|
|
44
|
+
margin-bottom: rhythm(1);
|
|
45
|
+
}
|
|
49
46
|
}
|
|
50
47
|
}
|
|
51
|
-
|
|
52
|
-
.ql-clipboard {
|
|
53
|
-
position: absolute;
|
|
54
|
-
top: 50%;
|
|
55
|
-
left: -100000px;
|
|
56
|
-
height: 1px;
|
|
57
|
-
overflow-y: hidden;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.ql-editor p,
|
|
61
|
-
.ql-editor ul,
|
|
62
|
-
.ql-editor ol {
|
|
63
|
-
@include plumber(
|
|
64
|
-
$font-size: 1.75,
|
|
65
|
-
$leading-bottom: 2
|
|
66
|
-
);
|
|
67
|
-
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/core';
|
|
2
|
+
import StarterKit from '@tiptap/starter-kit';
|
|
3
|
+
import { Link } from '@tiptap/extension-link';
|
|
4
|
+
import className from '../../assets/js/className';
|
|
5
|
+
import { open } from '../../molecules/modal/modal';
|
|
6
|
+
|
|
7
|
+
function clearAndCapitalize(str) {
|
|
8
|
+
return str.replace(/-/, '').toUpperCase();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function kebabToCamel(str) {
|
|
12
|
+
return str.replace(/-\w/g, clearAndCapitalize);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function kebabToPascal(str) {
|
|
16
|
+
return str.replace(/(^\w|-\w)/g, clearAndCapitalize);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function insertLink(el, editor) {
|
|
20
|
+
const addLink = (e, modal, close) => {
|
|
21
|
+
e.preventDefault();
|
|
22
|
+
|
|
23
|
+
let value = modal.querySelector('input').value.trim();
|
|
24
|
+
|
|
25
|
+
if (!value.length) {
|
|
26
|
+
editor.commands.unsetLink();
|
|
27
|
+
} else {
|
|
28
|
+
const isAbsolute = new RegExp('(?:^[a-z][a-z0-9+.-]*:|//)', 'i');
|
|
29
|
+
|
|
30
|
+
if (!isAbsolute.test(value)) {
|
|
31
|
+
value = `https://${value}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
editor.commands.toggleLink({ href: value });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
close();
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (editor.view.state.selection.empty) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const currentValue = (editor.getAttributes('link').href) ? editor.getAttributes('link').href : '';
|
|
45
|
+
|
|
46
|
+
open({
|
|
47
|
+
title: 'Lägg till länk',
|
|
48
|
+
content: `
|
|
49
|
+
<p class="u-m-b-0 u-m-t-default"><input type="url" value="${currentValue}" class="${className('a-input')}"></p>
|
|
50
|
+
`,
|
|
51
|
+
actions: [
|
|
52
|
+
{
|
|
53
|
+
text: 'Avbryt',
|
|
54
|
+
color: 'transparent',
|
|
55
|
+
attrs: {
|
|
56
|
+
'data-modal-close': null,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
text: 'Spara',
|
|
61
|
+
modifier: 'primary',
|
|
62
|
+
key: 'enter',
|
|
63
|
+
onClick: addLink,
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
}, {
|
|
67
|
+
onOpen(id, modal) {
|
|
68
|
+
modal.querySelector('input').focus();
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function createToolbarButton(el, control, editor) {
|
|
74
|
+
const button = document.createElement('button');
|
|
75
|
+
const iconId = (['link'].includes(control)) ? control : `richtext-${control}`;
|
|
76
|
+
|
|
77
|
+
button.setAttribute('data-rich-text-control', control);
|
|
78
|
+
button.value = kebabToCamel(control);
|
|
79
|
+
button.innerHTML = `
|
|
80
|
+
<span class="u-visuallyhidden">${control.replace('-', ' ')}</span>
|
|
81
|
+
<svg class="icon">
|
|
82
|
+
<use xlink:href="#icon-${iconId}"></use>
|
|
83
|
+
</svg>
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
el.appendChild(button);
|
|
87
|
+
|
|
88
|
+
button.addEventListener('click', (e) => {
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
|
|
91
|
+
if (control === 'link') {
|
|
92
|
+
insertLink(el, editor);
|
|
93
|
+
} else {
|
|
94
|
+
const method = `toggle${kebabToPascal(control)}`;
|
|
95
|
+
|
|
96
|
+
editor.chain()
|
|
97
|
+
.focus()[method]()
|
|
98
|
+
.run();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function toogleButtonState(editor, el) {
|
|
104
|
+
[].forEach.call(el.parentNode.querySelectorAll('[data-rich-text-control]'), (control) => {
|
|
105
|
+
if (editor.isActive(control.value)) {
|
|
106
|
+
control.classList.add('is-active');
|
|
107
|
+
} else {
|
|
108
|
+
control.classList.remove('is-active');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (control.value === 'link' && editor.view.state.selection.empty) {
|
|
112
|
+
control.disabled = true;
|
|
113
|
+
} else if (control.value === 'link') {
|
|
114
|
+
control.disabled = false;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function createToolbar(el, editor) {
|
|
120
|
+
const toolbar = document.createElement('div');
|
|
121
|
+
|
|
122
|
+
toolbar.className = className('a-textarea__toolbar');
|
|
123
|
+
|
|
124
|
+
el.parentNode.insertBefore(toolbar, el);
|
|
125
|
+
|
|
126
|
+
['bold', 'italic', 'link', 'bullet-list'].forEach((control) => {
|
|
127
|
+
createToolbarButton(toolbar, control, editor);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function setupTextArea(el) {
|
|
132
|
+
const editorEl = document.createElement('div');
|
|
133
|
+
const editor = new Editor({
|
|
134
|
+
element: editorEl,
|
|
135
|
+
extensions: [
|
|
136
|
+
StarterKit,
|
|
137
|
+
Link.configure({
|
|
138
|
+
openOnClick: false,
|
|
139
|
+
HTMLAttributes: {
|
|
140
|
+
class: 'u-link',
|
|
141
|
+
},
|
|
142
|
+
}),
|
|
143
|
+
],
|
|
144
|
+
content: el.value,
|
|
145
|
+
onTransaction(props) {
|
|
146
|
+
toogleButtonState(props.editor, editorEl);
|
|
147
|
+
},
|
|
148
|
+
onUpdate(props) {
|
|
149
|
+
el.value = props.editor.getHTML();
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
editorEl.className = el.className;
|
|
154
|
+
editorEl.classList.add(className('a-textarea--rich-text'));
|
|
155
|
+
|
|
156
|
+
el.style.display = 'none';
|
|
157
|
+
el.editor = editor;
|
|
158
|
+
|
|
159
|
+
el.parentNode.insertBefore(editorEl, el);
|
|
160
|
+
|
|
161
|
+
createToolbar(editorEl, editor);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const els = document.querySelectorAll('textarea[data-rich-text]');
|
|
165
|
+
|
|
166
|
+
if (els.length) {
|
|
167
|
+
[].forEach.call(els, (el) => setupTextArea(el, Editor, StarterKit));
|
|
168
|
+
}
|
|
@@ -6,7 +6,15 @@ module.exports = {
|
|
|
6
6
|
placeholder: 'Meddelande',
|
|
7
7
|
id:'message',
|
|
8
8
|
required: false,
|
|
9
|
-
disabled: false
|
|
9
|
+
disabled: false,
|
|
10
|
+
button_primary_color: '#e0bff5',
|
|
11
|
+
button_primary_hover_color: '#c27fec',
|
|
12
|
+
button_primary_border_color: '#c27fec',
|
|
13
|
+
button_primary_text_color: '#1f2a36',
|
|
14
|
+
button_secondary_color: '#ff9fb4',
|
|
15
|
+
button_secondary_hover_color: '#ff4069',
|
|
16
|
+
button_secondary_border_color: '#ff4069',
|
|
17
|
+
button_secondary_text_color: '#1f2a36',
|
|
10
18
|
},
|
|
11
19
|
variants: [
|
|
12
20
|
{
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
<style media="screen">
|
|
2
|
+
:root {
|
|
3
|
+
--m-modal-button-primary-color: {{button_primary_color}};
|
|
4
|
+
--m-modal-button-primary-hover-color: {{button_primary_hover_color}};
|
|
5
|
+
--m-modal-button-primary-border-color: {{button_primary_border_color}};
|
|
6
|
+
--m-modal-button-primary-text-color: {{button_primary_text_color}};
|
|
7
|
+
--m-modal-button-secondary-color: {{button_secondary_color}};
|
|
8
|
+
--m-modal-button-secondary-hover-color: {{button_secondary_hover_color}};
|
|
9
|
+
--m-modal-button-secondary-border-color: {{button_secondary_border_color}};
|
|
10
|
+
--m-modal-button-secondary-text-color: {{button_secondary_text_color}};
|
|
11
|
+
}
|
|
12
|
+
</style>
|
|
1
13
|
<div class="field-group{{#if is_invalid}} is-invalid{{/if}}">
|
|
2
14
|
{{> @label for="message" label="Meddelande" }}
|
|
3
|
-
{{#if is_richtext}}
|
|
4
|
-
<div id="toolbar" class="ql-toolbar">
|
|
5
|
-
<!-- Add buttons as you would before -->
|
|
6
|
-
<button class="ql-bold"><span class="u-visuallyhidden">Bold</span>{{> @icon id="richtext-bold"}}</button>
|
|
7
|
-
<button class="ql-italic"><span class="u-visuallyhidden">Italic</span>{{> @icon id="richtext-italic"}}</button>
|
|
8
|
-
<button class="ql-list" value="bullet"><span class="u-visuallyhidden">Bullet list</span>{{> @icon id="richtext-bullet-list"}}</button>
|
|
9
|
-
<button class="ql-link"><span class="u-visuallyhidden">Link</span>{{> @icon id="link"}}</button>
|
|
10
|
-
</div>
|
|
11
|
-
{{/if}}
|
|
12
|
-
<textarea rows="5" class="a-textarea{{#if modifier}} {{modifier}}{{/if}}" id="{{id}}" {{#if is_invalid}}aria-invalid="true"{{/if}} {{#if required}}required {{/if}} {{#if is_disabled}}disabled {{/if}} placeholder="{{placeholder}}" autocomplete="{{autocomplete}}"{{#if has_help}} aria-describedby="textarea-help"{{/if}} {{#if required}} aria-describedby="textarea-help"{{/if}}></textarea>
|
|
15
|
+
<textarea rows="5" class="a-textarea{{#if modifier}} {{modifier}}{{/if}}" id="{{id}}" {{#if is_invalid}}aria-invalid="true"{{/if}} {{#if is_richtext}}data-rich-text{{/if}} {{#if required}}required {{/if}} {{#if is_disabled}}disabled {{/if}} placeholder="{{placeholder}}" autocomplete="{{autocomplete}}"{{#if has_help}} aria-describedby="textarea-help"{{/if}} {{#if required}} aria-describedby="textarea-help"{{/if}}></textarea>
|
|
13
16
|
{{#if has_help}}
|
|
14
17
|
<div class="input-help" id="textarea-help">
|
|
15
18
|
Välj det som passar dig bäst
|
|
@@ -92,3 +92,22 @@ $colors: (
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
/// Generate wordpress color classes with attribute and value
|
|
97
|
+
/// Generates this: .has-color-name{$suffix}
|
|
98
|
+
/// @group Colors
|
|
99
|
+
@mixin wordpress_color_classes($map, $attribute, $separator: '-', $suffix: '', $base: 'base') {
|
|
100
|
+
@each $key, $value in $map {
|
|
101
|
+
@if type-of($value) == 'map' {
|
|
102
|
+
&#{if($key != $base, #{$separator}#{$key}, '')} {
|
|
103
|
+
content: str-replace($key, 'color-', '');
|
|
104
|
+
@include wordpress_color_classes($value, $attribute, $separator, '-color');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
@else {
|
|
108
|
+
&#{if($key != $base, #{$separator}#{$key}, '')}#{$suffix} {
|
|
109
|
+
#{$attribute}: $value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|