@scaleflex/widget-core 0.0.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,332 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
5
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
6
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
7
+ function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
8
+ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
9
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
10
+ function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
11
+ function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
12
+ function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
13
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
14
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
15
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
16
+ import { RESPONSE_CODES } from '@scaleflex/widget-utils/lib/constants';
17
+ import { saveUserSassKey, selectUserSessionUuid, userLogout } from './slices/user.slice';
18
+
19
+ /**
20
+ * Spec: https://scaleflexhq.atlassian.net/wiki/spaces/SHARED/pages/34570620/Session+handling
21
+ * Task: https://scaleflexhq.atlassian.net/browse/FRA-3494
22
+ *
23
+ * Notice!
24
+ * SassKeyRenewer works only when there is defined a session uuid:
25
+ * - Hub case
26
+ * - standalone Widget with enabled auth
27
+ * Doesn't work for Widget with security template (for this case is used logic to regenerate sass key from sec template user.slice.js:generateUserKey())
28
+ */
29
+
30
+ export var TIMER_DELAY_STORAGE_NAME = 'sassKeyRenewerTimerDelay';
31
+ var LAST_RENEW_TIMESTAMP_STORAGE_NAME = 'keyRenewLastUpdateTimestamp';
32
+ var EMPTY_KEY_TIMER_DELAY_STORAGE_NAME = 'sassKeyRenewerEmptyKeyTimerDelay';
33
+ var LOG_ENABLED_STORAGE_NAME = 'sassKeyRenewerLogEnabled';
34
+ var TIMER_DELAY = 60 * 60 * 1000;
35
+
36
+ // If no sass key from renew API, need to send request again in 1min
37
+ var EMPTY_SASS_KEY_TIMER_DELAY = 60 * 1000;
38
+ var SassKeyRenewer = /*#__PURE__*/_createClass(function SassKeyRenewer(filerobot, client) {
39
+ var _this = this;
40
+ var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
41
+ _classCallCheck(this, SassKeyRenewer);
42
+ _defineProperty(this, "resetProps", function () {
43
+ _this.log('Run resetProps()');
44
+ _this.isSending = false;
45
+ _this.isOffline = false;
46
+ _this.isBrowserTabVisible = true;
47
+ _this.isPaused = false;
48
+ _this.successHandlersQueue = [];
49
+ });
50
+ _defineProperty(this, "reset", function () {
51
+ _this.log('Run reset()');
52
+ _this.resetProps();
53
+ _this.clearTimers();
54
+ });
55
+ _defineProperty(this, "getStorageItemName", function (name) {
56
+ return "".concat(_this.storageNamePrefix || '').concat(name);
57
+ });
58
+ _defineProperty(this, "getItemFromStorage", function (name) {
59
+ return localStorage.getItem(_this.getStorageItemName(name));
60
+ });
61
+ _defineProperty(this, "removeItemFromStorage", function (name) {
62
+ return localStorage.removeItem(_this.getStorageItemName(name));
63
+ });
64
+ _defineProperty(this, "setItemToStorage", function (name, value) {
65
+ return localStorage.setItem(_this.getStorageItemName(name), value);
66
+ });
67
+ _defineProperty(this, "log", function (message) {
68
+ if (_this.opts.logEnabled) {
69
+ var _console;
70
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
71
+ args[_key - 1] = arguments[_key];
72
+ }
73
+ (_console = console).log.apply(_console, ["".concat(_this.opts.namePrefix, "[SassKeyRenewer] ").concat(message || '')].concat(args));
74
+ }
75
+ });
76
+ _defineProperty(this, "logDir", function () {
77
+ if (_this.opts.logEnabled) {
78
+ var _console2;
79
+ (_console2 = console).dir.apply(_console2, arguments);
80
+ }
81
+ });
82
+ _defineProperty(this, "sendRenewRequestForce", function (successHandler, requestId) {
83
+ _this.log('Run sendRenewRequestForce()', {
84
+ requestId: requestId
85
+ });
86
+ _this.removeItemFromStorage(LAST_RENEW_TIMESTAMP_STORAGE_NAME);
87
+ _this.clearTimers();
88
+ _this.successHandlersQueue = [];
89
+ _this.addSuccessHandlerToTheQueue(function () {
90
+ return _this.sendRenewRequestsWithDelay();
91
+ }, 'sendRenewRequestsWithDelay');
92
+ _this.sendRenewRequest(successHandler, requestId);
93
+ });
94
+ _defineProperty(this, "sendRenewRequest", function (successHandler, requestId) {
95
+ _this.log('Run sendRenewRequest()', {
96
+ requestId: requestId,
97
+ isSending: _this.isSending
98
+ });
99
+ _this.addSuccessHandlerToTheQueue(successHandler, requestId);
100
+ if (_this.isSending) {
101
+ _this.log('Request rejected as previous one is still sending');
102
+ return;
103
+ }
104
+ var state = _this.filerobot.store.getState();
105
+ var sessionUuid = selectUserSessionUuid(state);
106
+ if (!sessionUuid) {
107
+ _this.log('Request rejected as sessionUuid doesn\'t exist');
108
+ return;
109
+ }
110
+
111
+ // const { securityTemplateId } = this.filerobot?.opts || {} // TODO: Uncomment when it will be supported by BE
112
+ var headers = {};
113
+ if (sessionUuid) {
114
+ headers['X-Session-Token'] = sessionUuid;
115
+ }
116
+ // TODO: Uncomment when it will be supported by BE
117
+ // else if (securityTemplateId) {
118
+ // headers['X-Security-Template'] = securityTemplateId
119
+ // }
120
+
121
+ _this.log('headers', headers, {
122
+ sessionUuid: sessionUuid
123
+ });
124
+ var handleError = function handleError(error) {
125
+ clearTimeout(_this.noKeyResendTimer);
126
+ if (!_this.isPaused) {
127
+ var codesForLogout = [RESPONSE_CODES.ERR_SASS_INVALID, RESPONSE_CODES.KEY_EXPIRED, RESPONSE_CODES.ERR_SESSION_INVALID, RESPONSE_CODES.INVALID_UUID];
128
+ var code = codesForLogout.includes(error === null || error === void 0 ? void 0 : error.code) ? error.code : codesForLogout.includes(error === null || error === void 0 ? void 0 : error.codeLabel) ? error.codeLabel : null;
129
+ _this.log('Sass key renewal error', {
130
+ error: error,
131
+ code: code
132
+ });
133
+ _this.logDir(error);
134
+ if (code) {
135
+ _this.log("Sass key renewal returned code includes in: ".concat(codesForLogout.join('/'), ", need to logout"), headers, {
136
+ sessionUuid: sessionUuid,
137
+ code: code
138
+ });
139
+ _this.unsubscribe();
140
+ _this.filerobot.dispatch(userLogout());
141
+ return;
142
+ }
143
+ _this.log('Handling missing sass key error. Run timer', {
144
+ delay: _this.opts.emptySassKeyTimerDelay
145
+ });
146
+ _this.noKeyResendTimer = setTimeout(function () {
147
+ _this.sendRenewRequest();
148
+ }, _this.opts.emptySassKeyTimerDelay);
149
+ }
150
+ };
151
+ _this.isSending = true;
152
+ var lastRequestTimestamp = Date.now();
153
+ _this.log('Send request key/renew', {
154
+ headers: headers,
155
+ lastRequestTimestamp: lastRequestTimestamp
156
+ });
157
+ _this.setItemToStorage(LAST_RENEW_TIMESTAMP_STORAGE_NAME, lastRequestTimestamp);
158
+ _this.client.post('key/renew', {
159
+ headers: headers
160
+ }).then(function (response) {
161
+ _this.log('Response', response);
162
+ if (response.key) {
163
+ _this.filerobot.dispatch(saveUserSassKey(response.key));
164
+ _this.successHandlersQueue.forEach(function (_ref) {
165
+ var successHandler = _ref.successHandler;
166
+ successHandler(response);
167
+ });
168
+ _this.successHandlersQueue = [];
169
+ } else {
170
+ handleError(response);
171
+ }
172
+ })["catch"](function (error) {
173
+ _this.log('Error', error);
174
+ handleError(error);
175
+ })["finally"](function () {
176
+ _this.isSending = false;
177
+ });
178
+ });
179
+ /**
180
+ * @param {function} cb - Call back function
181
+ * @param {string} [requestId] - Optional. Should be used in cases when need to cancel previous simil request handler that has same ID.
182
+ */
183
+ _defineProperty(this, "addSuccessHandlerToTheQueue", function (cb, requestId) {
184
+ _this.log('Run addSuccessHandlerToTheQueue()', {
185
+ cb: cb,
186
+ requestId: requestId
187
+ });
188
+ if (typeof cb === 'function') {
189
+ // Remove similar requests
190
+ if (requestId) {
191
+ var similarRequestIndex = _this.successHandlersQueue.findIndex(function (request) {
192
+ return (request === null || request === void 0 ? void 0 : request.requestId) === requestId;
193
+ });
194
+ if (similarRequestIndex > -1) {
195
+ // Similar request exists in the queue
196
+ _this.log('Remove success handler from queue', {
197
+ similarRequestIndex: similarRequestIndex,
198
+ handler: _this.successHandlersQueue[similarRequestIndex]
199
+ });
200
+ var newSuccessHandlersQueue = _toConsumableArray(_this.successHandlersQueue);
201
+ newSuccessHandlersQueue.splice(similarRequestIndex, 1);
202
+ _this.successHandlersQueue = newSuccessHandlersQueue;
203
+ }
204
+ }
205
+ _this.successHandlersQueue.push({
206
+ requestId: requestId,
207
+ successHandler: cb
208
+ });
209
+ _this.log('Added success handler to queue', _toConsumableArray(_this.successHandlersQueue));
210
+ }
211
+ });
212
+ // Run refresh request every hour
213
+ _defineProperty(this, "sendRenewRequestsWithDelay", function (_delay) {
214
+ var delay = _delay || _this.opts.timerDelay;
215
+ _this.timer = setTimeout(function () {
216
+ _this.sendRenewRequest(function () {
217
+ return _this.sendRenewRequestsWithDelay();
218
+ }, 'sendRenewRequestsWithDelay');
219
+ }, delay);
220
+ _this.log('Run sendRenewRequestsWithDelay()', {
221
+ delay: delay,
222
+ timer: _this.timer
223
+ });
224
+ });
225
+ _defineProperty(this, "clearTimers", function () {
226
+ _this.log('Run clearTimers()', {
227
+ timer: _this.timer,
228
+ noKeyResendTimer: _this.noKeyResendTimer
229
+ });
230
+ clearTimeout(_this.timer);
231
+ clearTimeout(_this.noKeyResendTimer);
232
+ });
233
+ _defineProperty(this, "pause", function () {
234
+ _this.log('Paused');
235
+ _this.isSending = false;
236
+ _this.isPaused = true;
237
+ _this.clearTimers();
238
+ });
239
+ _defineProperty(this, "continue", function () {
240
+ _this.isPaused = false;
241
+ _this.log('Continue', {
242
+ isSubscribed: _this.isSubscribed,
243
+ isOffline: _this.isOffline,
244
+ isBrowserTabVisible: _this.isBrowserTabVisible,
245
+ isPaused: _this.isPaused,
246
+ isSending: _this.isSending,
247
+ successHandlersQueue: _this.successHandlersQueue
248
+ });
249
+ if (_this.isSubscribed && !_this.isOffline && _this.isBrowserTabVisible) {
250
+ var lastRequestTimestamp = +(_this.getItemFromStorage(LAST_RENEW_TIMESTAMP_STORAGE_NAME) || 0);
251
+ _this.log('lastRequestTimestamp = ', lastRequestTimestamp);
252
+ if (Number.isFinite(lastRequestTimestamp) && lastRequestTimestamp > 0) {
253
+ var dateNow = Date.now();
254
+ var delayMsec = _this.opts.timerDelay - (dateNow - lastRequestTimestamp);
255
+ _this.log('Delay milliseconds', {
256
+ delayMsec: delayMsec,
257
+ timerDelay: _this.opts.timerDelay,
258
+ lastRequestTimestamp: lastRequestTimestamp,
259
+ dateNow: dateNow
260
+ });
261
+ if (delayMsec > 1000) {
262
+ return _this.sendRenewRequestsWithDelay(delayMsec);
263
+ }
264
+ }
265
+ _this.sendRenewRequest(function () {
266
+ return _this.sendRenewRequestsWithDelay();
267
+ }, 'sendRenewRequestsWithDelay');
268
+ }
269
+ });
270
+ _defineProperty(this, "onlineHandler", function () {
271
+ _this.log('Online');
272
+ _this.isOffline = false;
273
+ _this["continue"]();
274
+ });
275
+ _defineProperty(this, "offlineHandler", function () {
276
+ _this.log('Offline');
277
+ _this.isOffline = true;
278
+ _this.pause();
279
+ });
280
+ _defineProperty(this, "visibilityChangeHandler", function () {
281
+ if (document.hidden) {
282
+ _this.log('Tab not active');
283
+ _this.isBrowserTabVisible = false;
284
+ _this.pause();
285
+ } else {
286
+ _this.log('Tab active');
287
+ _this.isBrowserTabVisible = true;
288
+ _this["continue"]();
289
+ }
290
+ });
291
+ _defineProperty(this, "subscribe", function () {
292
+ _this.log('Run subscribe()');
293
+ _this.reset();
294
+ _this.sendRenewRequestsWithDelay();
295
+ if (!_this.isSubscribed) {
296
+ var offlineHandler = _this.offlineHandler.bind(_this);
297
+ var onlineHandler = _this.onlineHandler.bind(_this);
298
+ var visibilityChangeHandler = _this.visibilityChangeHandler.bind(_this);
299
+ _this.log('Add listeners');
300
+ window.addEventListener('offline', offlineHandler);
301
+ window.addEventListener('online', onlineHandler);
302
+ document.addEventListener('visibilitychange', visibilityChangeHandler);
303
+ _this.unsubscribe = function () {
304
+ _this.log('Run unsubscribe()');
305
+ _this.reset();
306
+ _this.isSubscribed = false;
307
+ _this.log('Remove listeners');
308
+ window.removeEventListener('offline', offlineHandler);
309
+ window.removeEventListener('online', onlineHandler);
310
+ document.removeEventListener('visibilitychange', visibilityChangeHandler);
311
+ };
312
+ }
313
+ _this.isSubscribed = true;
314
+ return _this.unsubscribe.bind(_this);
315
+ });
316
+ this.filerobot = filerobot;
317
+ this.client = client;
318
+ this.timer = null;
319
+ this.noKeyResendTimer = null;
320
+ this.storageNamePrefix = (opts === null || opts === void 0 ? void 0 : opts.namePrefix) || ''; // User for tests only. Solve problem with parallel async tests running when one test override localStorage value for another test.
321
+ this.opts = _objectSpread({
322
+ logEnabled: this.getItemFromStorage(LOG_ENABLED_STORAGE_NAME) === 'true',
323
+ timerDelay: +(this.getItemFromStorage(TIMER_DELAY_STORAGE_NAME) || TIMER_DELAY),
324
+ emptySassKeyTimerDelay: +(this.getItemFromStorage(EMPTY_KEY_TIMER_DELAY_STORAGE_NAME) || EMPTY_SASS_KEY_TIMER_DELAY),
325
+ namePrefix: ''
326
+ }, opts);
327
+ this.isSubscribed = false;
328
+ this.unsubscribe = function () {};
329
+ this.resetProps();
330
+ this.log('Inited');
331
+ });
332
+ export default SassKeyRenewer;
@@ -0,0 +1,240 @@
1
+ /**
2
+ * General Scaleflex styles that apply to everything inside the .filerobot-Root container
3
+ */
4
+
5
+ .filerobot-Root {
6
+ overflow: hidden;
7
+ box-sizing: border-box;
8
+ font-family: $font-family-base;
9
+ line-height: 1;
10
+ -webkit-font-smoothing: antialiased;
11
+ -moz-osx-font-smoothing: grayscale;
12
+ text-align: left;
13
+ position: relative;
14
+ color: $gray-800;
15
+
16
+ :disabled {
17
+ cursor: not-allowed;
18
+ }
19
+ }
20
+
21
+
22
+ .SfxModal-Wrapper, .filerobot-Root *, #SfxPopper * {
23
+ font-family: $font-family-base;
24
+ }
25
+
26
+ .SfxModal-Wrapper *, .filerobot-Root *, #SfxPopper * {
27
+ scrollbar-color: auto !important;
28
+
29
+ &::-webkit-scrollbar {
30
+ width: 12px !important;
31
+ height: 12px !important;
32
+ }
33
+
34
+ /* Track */
35
+ &::-webkit-scrollbar-track {
36
+ background: transparent !important;
37
+ }
38
+
39
+ /* Handle */
40
+ &::-webkit-scrollbar-thumb {
41
+ background: #CCD6DE;
42
+ border: 4px solid #FFFFFF;
43
+ border-radius: 99px;
44
+ padding: 4px 6px;
45
+ }
46
+ }
47
+
48
+ .filerobot-Root *, .filerobot-Root *:before, .filerobot-Root *:after {
49
+ box-sizing: inherit;
50
+ }
51
+
52
+ .filerobot-Root [hidden] {
53
+ display: none;
54
+ }
55
+
56
+ // Utilities
57
+
58
+ // used in a few places
59
+ .filerobot-u-reset {
60
+ -webkit-appearance: none;
61
+ line-height: 1;
62
+ padding: 0;
63
+ margin: 0;
64
+ border: 0;
65
+ color: inherit;
66
+ backface-visibility: visible;
67
+ background: none;
68
+ border: medium none currentColor;
69
+ border-collapse: separate;
70
+ border-image: none;
71
+ border-radius: 0;
72
+ border-spacing: 0;
73
+ box-shadow: none;
74
+ clear: none;
75
+ cursor: auto;
76
+ display: inline;
77
+ empty-cells: show;
78
+ float: none;
79
+ font-family: inherit;
80
+ font-size: inherit;
81
+ font-style: normal;
82
+ font-variant: normal;
83
+ font-weight: normal;
84
+ font-stretch: normal;
85
+ hyphens: none;
86
+ left: auto;
87
+ letter-spacing: normal;
88
+ list-style: none;
89
+ margin: 0;
90
+ max-height: none;
91
+ max-width: none;
92
+ min-height: 0;
93
+ min-width: 0;
94
+ opacity: 1;
95
+ outline: medium none invert;
96
+ overflow: visible;
97
+ overflow-x: visible;
98
+ overflow-y: visible;
99
+ text-align: left;
100
+ text-decoration: none;
101
+ text-indent: 0;
102
+ text-shadow: none;
103
+ text-transform: none;
104
+ top: auto;
105
+ transform: none;
106
+ transform-origin: 50% 50% 0;
107
+ transform-style: flat;
108
+ transition: none 0s ease 0s;
109
+ unicode-bidi: normal;
110
+ vertical-align: baseline;
111
+ visibility: visible;
112
+ white-space: normal;
113
+ z-index: auto;
114
+
115
+ span {
116
+ max-width: 250px;
117
+ overflow: hidden;
118
+ text-overflow: ellipsis;
119
+
120
+ :not(:disabled) {
121
+ :active {
122
+ background-color: #eceef2;
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ //.filerobot-c-separator {
129
+ // height: 60%;
130
+ // border-left: 1px solid $border-primary-stateless;
131
+ // width: 1px;
132
+ // display: inline;
133
+ // margin: 0 8px;
134
+ //}
135
+
136
+ .filerobot-c-horizontal-separator {
137
+ width: 100%;
138
+ border-bottom: 1px solid $border;
139
+ height: 1px;
140
+ display: block;
141
+ position: absolute;
142
+ left: 0;
143
+ right: 0;
144
+ }
145
+
146
+ // Icon
147
+
148
+ // https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4
149
+ // used in a few places
150
+ .filerobot-c-icon {
151
+ max-width: 100%;
152
+ max-height: 100%;
153
+ fill: currentColor;
154
+ display: inline-block;
155
+ overflow: hidden;
156
+ }
157
+
158
+ // Buttons
159
+
160
+ .filerobot-c-btn {
161
+ display: inline-block;
162
+ text-align: center;
163
+ white-space: nowrap;
164
+ vertical-align: middle;
165
+ font-family: inherit;
166
+ font-size: 16px;
167
+ line-height: 1;
168
+ font-weight: 500;
169
+ transition-property: background-color, color;
170
+ transition-duration: 0.3s;
171
+ user-select: none;
172
+ }
173
+
174
+ .filerobot-c-btn:not(:disabled):not(.disabled) {
175
+ cursor: pointer;
176
+ }
177
+
178
+ .filerobot-c-btn::-moz-focus-inner {
179
+ border: 0;
180
+ }
181
+
182
+ .filerobot-c-btn-primary {
183
+ font-size: 14px;
184
+ padding: 10px 18px;
185
+ border-radius: 4px;
186
+ background-color: $blue;
187
+ color: $white;
188
+
189
+ &:hover {
190
+ background-color: darken($blue, 10%);
191
+ }
192
+
193
+ &:focus {
194
+ outline: none;
195
+ box-shadow: 0 0 0 3px rgba($blue, 0.4);
196
+ }
197
+
198
+ .filerobot-size--md & {
199
+ padding: 13px 22px;
200
+ }
201
+
202
+ [data-filerobot-theme="dark"] & {
203
+ color: $gray-200;
204
+ @include blue-border-focus--dark;
205
+ }
206
+ }
207
+
208
+ .filerobot-c-empty {
209
+ &-wrapper {
210
+ display: flex;
211
+ height: 100%;
212
+ }
213
+ height: 100%;
214
+ width: 100%;
215
+ display: flex;
216
+ align-items: center;
217
+ justify-content: center;
218
+ flex-flow: column wrap;
219
+ flex: 1;
220
+ color: $gray-500;
221
+ background-color: #ffffff;
222
+ line-height: 14px;
223
+ font-size: 12px;
224
+
225
+ &.left {
226
+ align-items: flex-start;
227
+ }
228
+ &.right {
229
+ align-items: flex-end;
230
+ }
231
+ }
232
+
233
+ .filerobot-c-empty {
234
+ align-items: flex-start;
235
+ color: $light-txt-secondary;
236
+ }
237
+
238
+ svg {
239
+ outline: none;
240
+ }
@@ -0,0 +1,38 @@
1
+ // Utility Mixins
2
+
3
+ @mixin reset-button() {
4
+ background: none;
5
+ -webkit-appearance: none;
6
+ font-family: inherit;
7
+ font-size: inherit;
8
+ line-height: 1;
9
+ padding: 0;
10
+ margin: 0;
11
+ border: 0;
12
+ color: inherit;
13
+ }
14
+
15
+ @mixin blue-border-focus() {
16
+ @include clear-focus();
17
+
18
+ &:focus {
19
+ box-shadow: 0 0 0 3px rgba($blue, 0.5);
20
+ }
21
+ }
22
+
23
+ @mixin blue-border-focus--dark() {
24
+ @include clear-focus();
25
+
26
+ &:focus {
27
+ box-shadow: 0 0 0 2px rgba($lightblue, 0.85);
28
+ }
29
+ }
30
+
31
+ @mixin clear-focus() {
32
+ &:focus {
33
+ outline: none;
34
+ }
35
+ &::-moz-focus-inner {
36
+ border: 0;
37
+ }
38
+ }
@@ -0,0 +1,64 @@
1
+ // Fonts
2
+ @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
3
+ $font-family-base: 'Roboto', sans-serif, Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol' !default;
4
+
5
+ // Colors
6
+
7
+ $white: #fff !default;
8
+ $black: #000 !default;
9
+ $red: #e32437 !default;
10
+ $blue: #5282DB !default;
11
+ $lightblue: #aae1ff !default;
12
+ $darkgrey: #37414B !default;
13
+ $light-icons-primary: #768A9F;
14
+ $light-icons-secondary: #97A6B6 !default;
15
+ $light-txt-secondary: #768A9F;
16
+
17
+ $primary: #4D4E4E !default;
18
+ $secondary: #768184 !default;
19
+ $accent: #6879EB !default;
20
+ $accent-hover: #606FD1 !default;
21
+ $accent-active: #4958BC !default;
22
+ $error: #E85B46 !default;
23
+
24
+ $background-primary: #F8FAFB !default;
25
+ $background-secondary: #FFFFFF !default;
26
+ $background-light-hover: #F9FBFC !default;
27
+ $background-light-active: #F3F7FA !default;
28
+ $hover: #EFF3F6 !default;
29
+ $active: #5D6D7E !default;
30
+ $active-transition: #d9dde0 !default;
31
+ $active-secondary: #E9EEF2 !default;
32
+ $border: #DFE7ED !default;
33
+ $border-primary-stateless: #CCD6DE;
34
+ $link-active: #92A6BC !default;
35
+
36
+ $gray-50: #fafafa !default;
37
+ $gray-100: #f4f4f4 !default;
38
+ $gray-100--highlighted: #f1f3f6 !default;
39
+ $gray-200: #eaeaea !default;
40
+ $gray-400: #bbb !default;
41
+ $gray-500: #939393 !default;
42
+ $gray-600: #757575 !default;
43
+ $gray-800: #333 !default;
44
+ $gray-900: #1f1f1f !default;
45
+
46
+ $highlight: #eceef2;
47
+ $highlight--dark: #02baf2;
48
+
49
+ $shadow-color: rgba(0, 0, 0, 0.25);
50
+
51
+ // Z-index
52
+
53
+ $zIndex-0: 100 !default;
54
+ $zIndex-1: 1001 !default;
55
+ $zIndex-2: 1002 !default;
56
+ $zIndex-3: 1003 !default;
57
+ $zIndex-5: 1005 !default;
58
+ $zIndex-highest-1: 1199 !default;
59
+ $zIndex-highest: 1200 !default;
60
+ $zIndex-modal: 100000 !default;
61
+
62
+ // Media Queries
63
+ $screen-medium: 'only screen and (min-width: 820px)' !default;
64
+ $screen-xxl: 'only screen and (min-width: 1601px)' !default;