@atlaskit/app-provider 1.4.2 → 1.5.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.
- package/CHANGELOG.md +21 -0
- package/dist/cjs/theme-provider.js +80 -0
- package/dist/es2019/theme-provider.js +45 -1
- package/dist/esm/theme-provider.js +81 -1
- package/package.json +11 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @atlaskit/app-provider
|
|
2
2
|
|
|
3
|
+
## 1.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#101755](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/101755)
|
|
8
|
+
[`07ee1368bd69d`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/07ee1368bd69d) -
|
|
9
|
+
Fixes a race condition with setting the theme. This change is behind a feature flag.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
|
|
15
|
+
## 1.4.3
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [#168743](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/168743)
|
|
20
|
+
[`90605435312ea`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/90605435312ea) -
|
|
21
|
+
Remove react-router-dom from devDependencies as it is incompatible with React 18.
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
|
|
3
24
|
## 1.4.2
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
|
@@ -12,10 +12,13 @@ exports.useColorMode = useColorMode;
|
|
|
12
12
|
exports.useSetColorMode = useSetColorMode;
|
|
13
13
|
exports.useSetTheme = useSetTheme;
|
|
14
14
|
exports.useTheme = useTheme;
|
|
15
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
16
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
15
17
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
16
18
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
17
19
|
var _react = _interopRequireWildcard(require("react"));
|
|
18
20
|
var _bindEventListener = require("bind-event-listener");
|
|
21
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
19
22
|
var _tokens = require("@atlaskit/tokens");
|
|
20
23
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
21
24
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -153,10 +156,87 @@ function ThemeProvider(_ref) {
|
|
|
153
156
|
});
|
|
154
157
|
}, []);
|
|
155
158
|
(0, _react.useEffect)(function () {
|
|
159
|
+
if ((0, _platformFeatureFlags.fg)('platform_dst_fix_set_theme_race')) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
156
162
|
(0, _tokens.setGlobalTheme)(_objectSpread(_objectSpread({}, theme), {}, {
|
|
157
163
|
colorMode: reconciledColorMode
|
|
158
164
|
}));
|
|
159
165
|
}, [theme, reconciledColorMode]);
|
|
166
|
+
var lastSetGlobalThemePromiseRef = (0, _react.useRef)(null);
|
|
167
|
+
(0, _react.useEffect)(function () {
|
|
168
|
+
if (!(0, _platformFeatureFlags.fg)('platform_dst_fix_set_theme_race')) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* We need to wait for any previous `setGlobalTheme` calls to finish before calling it again.
|
|
174
|
+
* This is to prevent race conditions as `setGlobalTheme` is async and mutates the DOM (e.g. sets the
|
|
175
|
+
* `data-color-mode` attribute on the root element).
|
|
176
|
+
*
|
|
177
|
+
* Since we can't safely abort the `setGlobalTheme` execution, we need to wait for it to properly finish before
|
|
178
|
+
* applying the new theme.
|
|
179
|
+
*
|
|
180
|
+
* Without this, we can end up in the following scenario:
|
|
181
|
+
* 1. app loads with the default 'light' theme, kicking off `setGlobalTheme`
|
|
182
|
+
* 2. app switches to 'dark' theme after retrieving value persisted in local storage, calling `setGlobalTheme` again
|
|
183
|
+
* 3. `setGlobalTheme` function execution for `dark` finishes before the initial `light` execution
|
|
184
|
+
* 4. `setGlobalTheme` function execution for `light` then finishes, resulting in the 'light' theme being applied.
|
|
185
|
+
*/
|
|
186
|
+
var cleanupLastFnCall = /*#__PURE__*/function () {
|
|
187
|
+
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
188
|
+
var unbindFn;
|
|
189
|
+
return _regenerator.default.wrap(function _callee$(_context) {
|
|
190
|
+
while (1) switch (_context.prev = _context.next) {
|
|
191
|
+
case 0:
|
|
192
|
+
if (!lastSetGlobalThemePromiseRef.current) {
|
|
193
|
+
_context.next = 6;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
_context.next = 3;
|
|
197
|
+
return lastSetGlobalThemePromiseRef.current;
|
|
198
|
+
case 3:
|
|
199
|
+
unbindFn = _context.sent;
|
|
200
|
+
unbindFn();
|
|
201
|
+
lastSetGlobalThemePromiseRef.current = null;
|
|
202
|
+
case 6:
|
|
203
|
+
case "end":
|
|
204
|
+
return _context.stop();
|
|
205
|
+
}
|
|
206
|
+
}, _callee);
|
|
207
|
+
}));
|
|
208
|
+
return function cleanupLastFnCall() {
|
|
209
|
+
return _ref2.apply(this, arguments);
|
|
210
|
+
};
|
|
211
|
+
}();
|
|
212
|
+
var safelySetGlobalTheme = /*#__PURE__*/function () {
|
|
213
|
+
var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
214
|
+
var promise;
|
|
215
|
+
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
216
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
217
|
+
case 0:
|
|
218
|
+
_context2.next = 2;
|
|
219
|
+
return cleanupLastFnCall();
|
|
220
|
+
case 2:
|
|
221
|
+
promise = (0, _tokens.setGlobalTheme)(_objectSpread(_objectSpread({}, theme), {}, {
|
|
222
|
+
colorMode: reconciledColorMode
|
|
223
|
+
}));
|
|
224
|
+
lastSetGlobalThemePromiseRef.current = promise;
|
|
225
|
+
case 4:
|
|
226
|
+
case "end":
|
|
227
|
+
return _context2.stop();
|
|
228
|
+
}
|
|
229
|
+
}, _callee2);
|
|
230
|
+
}));
|
|
231
|
+
return function safelySetGlobalTheme() {
|
|
232
|
+
return _ref3.apply(this, arguments);
|
|
233
|
+
};
|
|
234
|
+
}();
|
|
235
|
+
safelySetGlobalTheme();
|
|
236
|
+
return function cleanup() {
|
|
237
|
+
cleanupLastFnCall();
|
|
238
|
+
};
|
|
239
|
+
}, [theme, reconciledColorMode]);
|
|
160
240
|
(0, _react.useEffect)(function () {
|
|
161
241
|
if (!prefersDarkModeMql) {
|
|
162
242
|
return;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
|
1
|
+
import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { bind } from 'bind-event-listener';
|
|
3
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
4
|
import { setGlobalTheme } from '@atlaskit/tokens';
|
|
4
5
|
const defaultThemeSettings = {
|
|
5
6
|
dark: 'dark',
|
|
@@ -123,11 +124,54 @@ export function ThemeProvider({
|
|
|
123
124
|
}));
|
|
124
125
|
}, []);
|
|
125
126
|
useEffect(() => {
|
|
127
|
+
if (fg('platform_dst_fix_set_theme_race')) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
126
130
|
setGlobalTheme({
|
|
127
131
|
...theme,
|
|
128
132
|
colorMode: reconciledColorMode
|
|
129
133
|
});
|
|
130
134
|
}, [theme, reconciledColorMode]);
|
|
135
|
+
const lastSetGlobalThemePromiseRef = useRef(null);
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
if (!fg('platform_dst_fix_set_theme_race')) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* We need to wait for any previous `setGlobalTheme` calls to finish before calling it again.
|
|
143
|
+
* This is to prevent race conditions as `setGlobalTheme` is async and mutates the DOM (e.g. sets the
|
|
144
|
+
* `data-color-mode` attribute on the root element).
|
|
145
|
+
*
|
|
146
|
+
* Since we can't safely abort the `setGlobalTheme` execution, we need to wait for it to properly finish before
|
|
147
|
+
* applying the new theme.
|
|
148
|
+
*
|
|
149
|
+
* Without this, we can end up in the following scenario:
|
|
150
|
+
* 1. app loads with the default 'light' theme, kicking off `setGlobalTheme`
|
|
151
|
+
* 2. app switches to 'dark' theme after retrieving value persisted in local storage, calling `setGlobalTheme` again
|
|
152
|
+
* 3. `setGlobalTheme` function execution for `dark` finishes before the initial `light` execution
|
|
153
|
+
* 4. `setGlobalTheme` function execution for `light` then finishes, resulting in the 'light' theme being applied.
|
|
154
|
+
*/
|
|
155
|
+
const cleanupLastFnCall = async () => {
|
|
156
|
+
if (lastSetGlobalThemePromiseRef.current) {
|
|
157
|
+
const unbindFn = await lastSetGlobalThemePromiseRef.current;
|
|
158
|
+
unbindFn();
|
|
159
|
+
lastSetGlobalThemePromiseRef.current = null;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const safelySetGlobalTheme = async () => {
|
|
163
|
+
await cleanupLastFnCall();
|
|
164
|
+
const promise = setGlobalTheme({
|
|
165
|
+
...theme,
|
|
166
|
+
colorMode: reconciledColorMode
|
|
167
|
+
});
|
|
168
|
+
lastSetGlobalThemePromiseRef.current = promise;
|
|
169
|
+
};
|
|
170
|
+
safelySetGlobalTheme();
|
|
171
|
+
return function cleanup() {
|
|
172
|
+
cleanupLastFnCall();
|
|
173
|
+
};
|
|
174
|
+
}, [theme, reconciledColorMode]);
|
|
131
175
|
useEffect(() => {
|
|
132
176
|
if (!prefersDarkModeMql) {
|
|
133
177
|
return;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
1
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
3
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
4
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
5
|
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; }
|
|
4
6
|
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; }
|
|
5
|
-
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
|
7
|
+
import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
6
8
|
import { bind } from 'bind-event-listener';
|
|
9
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
10
|
import { setGlobalTheme } from '@atlaskit/tokens';
|
|
8
11
|
var defaultThemeSettings = {
|
|
9
12
|
dark: 'dark',
|
|
@@ -137,10 +140,87 @@ export function ThemeProvider(_ref) {
|
|
|
137
140
|
});
|
|
138
141
|
}, []);
|
|
139
142
|
useEffect(function () {
|
|
143
|
+
if (fg('platform_dst_fix_set_theme_race')) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
140
146
|
setGlobalTheme(_objectSpread(_objectSpread({}, theme), {}, {
|
|
141
147
|
colorMode: reconciledColorMode
|
|
142
148
|
}));
|
|
143
149
|
}, [theme, reconciledColorMode]);
|
|
150
|
+
var lastSetGlobalThemePromiseRef = useRef(null);
|
|
151
|
+
useEffect(function () {
|
|
152
|
+
if (!fg('platform_dst_fix_set_theme_race')) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* We need to wait for any previous `setGlobalTheme` calls to finish before calling it again.
|
|
158
|
+
* This is to prevent race conditions as `setGlobalTheme` is async and mutates the DOM (e.g. sets the
|
|
159
|
+
* `data-color-mode` attribute on the root element).
|
|
160
|
+
*
|
|
161
|
+
* Since we can't safely abort the `setGlobalTheme` execution, we need to wait for it to properly finish before
|
|
162
|
+
* applying the new theme.
|
|
163
|
+
*
|
|
164
|
+
* Without this, we can end up in the following scenario:
|
|
165
|
+
* 1. app loads with the default 'light' theme, kicking off `setGlobalTheme`
|
|
166
|
+
* 2. app switches to 'dark' theme after retrieving value persisted in local storage, calling `setGlobalTheme` again
|
|
167
|
+
* 3. `setGlobalTheme` function execution for `dark` finishes before the initial `light` execution
|
|
168
|
+
* 4. `setGlobalTheme` function execution for `light` then finishes, resulting in the 'light' theme being applied.
|
|
169
|
+
*/
|
|
170
|
+
var cleanupLastFnCall = /*#__PURE__*/function () {
|
|
171
|
+
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
172
|
+
var unbindFn;
|
|
173
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
174
|
+
while (1) switch (_context.prev = _context.next) {
|
|
175
|
+
case 0:
|
|
176
|
+
if (!lastSetGlobalThemePromiseRef.current) {
|
|
177
|
+
_context.next = 6;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
_context.next = 3;
|
|
181
|
+
return lastSetGlobalThemePromiseRef.current;
|
|
182
|
+
case 3:
|
|
183
|
+
unbindFn = _context.sent;
|
|
184
|
+
unbindFn();
|
|
185
|
+
lastSetGlobalThemePromiseRef.current = null;
|
|
186
|
+
case 6:
|
|
187
|
+
case "end":
|
|
188
|
+
return _context.stop();
|
|
189
|
+
}
|
|
190
|
+
}, _callee);
|
|
191
|
+
}));
|
|
192
|
+
return function cleanupLastFnCall() {
|
|
193
|
+
return _ref2.apply(this, arguments);
|
|
194
|
+
};
|
|
195
|
+
}();
|
|
196
|
+
var safelySetGlobalTheme = /*#__PURE__*/function () {
|
|
197
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
198
|
+
var promise;
|
|
199
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
200
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
201
|
+
case 0:
|
|
202
|
+
_context2.next = 2;
|
|
203
|
+
return cleanupLastFnCall();
|
|
204
|
+
case 2:
|
|
205
|
+
promise = setGlobalTheme(_objectSpread(_objectSpread({}, theme), {}, {
|
|
206
|
+
colorMode: reconciledColorMode
|
|
207
|
+
}));
|
|
208
|
+
lastSetGlobalThemePromiseRef.current = promise;
|
|
209
|
+
case 4:
|
|
210
|
+
case "end":
|
|
211
|
+
return _context2.stop();
|
|
212
|
+
}
|
|
213
|
+
}, _callee2);
|
|
214
|
+
}));
|
|
215
|
+
return function safelySetGlobalTheme() {
|
|
216
|
+
return _ref3.apply(this, arguments);
|
|
217
|
+
};
|
|
218
|
+
}();
|
|
219
|
+
safelySetGlobalTheme();
|
|
220
|
+
return function cleanup() {
|
|
221
|
+
cleanupLastFnCall();
|
|
222
|
+
};
|
|
223
|
+
}, [theme, reconciledColorMode]);
|
|
144
224
|
useEffect(function () {
|
|
145
225
|
if (!prefersDarkModeMql) {
|
|
146
226
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/app-provider",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "A top level provider for the Design System.",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"team": "Design System Team",
|
|
12
12
|
"website": {
|
|
13
13
|
"name": "App provider",
|
|
14
|
-
"category": "
|
|
14
|
+
"category": "Tooling",
|
|
15
15
|
"status": {
|
|
16
16
|
"type": "beta"
|
|
17
17
|
}
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
".": "./src/index.tsx"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@atlaskit/
|
|
42
|
+
"@atlaskit/platform-feature-flags": "^0.3.0",
|
|
43
|
+
"@atlaskit/tokens": "^3.0.0",
|
|
43
44
|
"@babel/runtime": "^7.0.0",
|
|
44
45
|
"bind-event-listener": "^3.0.0"
|
|
45
46
|
},
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@af/visual-regression": "*",
|
|
51
|
-
"@atlaskit/ds-lib": "^3.
|
|
52
|
+
"@atlaskit/ds-lib": "^3.3.0",
|
|
52
53
|
"@atlaskit/ssr": "*",
|
|
53
54
|
"@atlaskit/visual-regression": "*",
|
|
54
55
|
"@testing-library/react": "^12.1.5",
|
|
@@ -56,7 +57,6 @@
|
|
|
56
57
|
"@testing-library/user-event": "^14.4.3",
|
|
57
58
|
"react-dom": "^16.8.0",
|
|
58
59
|
"react-resource-router": "^0.20.0",
|
|
59
|
-
"react-router-dom": "^4.2.2",
|
|
60
60
|
"typescript": "~5.4.2",
|
|
61
61
|
"wait-for-expect": "^1.2.0"
|
|
62
62
|
},
|
|
@@ -91,5 +91,10 @@
|
|
|
91
91
|
]
|
|
92
92
|
}
|
|
93
93
|
},
|
|
94
|
-
"homepage": "https://atlassian.design/components/app-provider"
|
|
94
|
+
"homepage": "https://atlassian.design/components/app-provider",
|
|
95
|
+
"platform-feature-flags": {
|
|
96
|
+
"platform_dst_fix_set_theme_race": {
|
|
97
|
+
"type": "boolean"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
95
100
|
}
|