@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.
@@ -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
@@ -1,5 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = focusTrap;
7
+
3
8
  var _focusTrap = require('focus-trap');
4
9
 
5
10
  var _focusTrap2 = _interopRequireDefault(_focusTrap);
@@ -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 a-button--' + action.color) + ' ' + (0, _className2.default)('m-modal__button-' + action.modifier) + ' u-m-l-2';
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
- modalActions.appendChild(document.createRange().createContextualFragment(button));
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.19.5",
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-open': 'modal-container',
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
- &:focus {
31
- @extend %input-focus;
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
- &[disabled] {
35
- @extend %disabled;
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
- margin-right: rhythm(0.5);
48
- margin-bottom: rhythm(1);
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
@@ -137,7 +137,7 @@
137
137
  &:hover,
138
138
  &:focus,
139
139
  &:active,
140
- &.ql-active {
140
+ &.is-active {
141
141
  background-color: $color-cyberspace;
142
142
 
143
143
  svg {
@@ -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
+ }
@@ -0,0 +1,12 @@
1
+ @charset "UTF-8";
2
+
3
+ // Generate wordpress color classes e.g. .has-ruby-color
4
+ /// @group Colors
5
+ .has {
6
+ @include wordpress_color_classes (
7
+ $colors,
8
+ $attribute: 'color',
9
+ $separator: '-',
10
+ $suffix: '-color'
11
+ );
12
+ }