@primer/styled-react 0.0.0-20260326162136 → 0.0.0-20260326174604
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../src/components/ThemeProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../src/components/ThemeProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,eAAO,MAAM,gBAAgB,QAAQ,CAAA;AAKrC,MAAM,MAAM,KAAK,GAAG;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAC,CAAA;AACxC,KAAK,SAAS,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAA;AACnD,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,MAAM,CAAA;AAElD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,SAAS,CAAC,EAAE,iBAAiB,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AA8BD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAkF/E,CAAA;AAED,wBAAgB,QAAQ;YA/Gd,KAAK;kBACC,MAAM;gBACR,iBAAiB;wBACT,SAAS;0BACP,MAAM;gBAChB,MAAM;kBACJ,MAAM;kBACN,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;kBACvD,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;oBAC1C,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;EAwG7D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,UAG1F;AAqGD,eAAe,aAAa,CAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
2
3
|
import { ThemeProvider as ThemeProvider$1 } from 'styled-components';
|
|
3
4
|
import { theme, useId, useSyncedState } from '@primer/react';
|
|
4
5
|
import deepmerge from 'deepmerge';
|
|
@@ -17,27 +18,15 @@ const ThemeContext = /*#__PURE__*/React.createContext({
|
|
|
17
18
|
});
|
|
18
19
|
|
|
19
20
|
// inspired from __NEXT_DATA__, we use application/json to avoid CSRF policy with inline scripts
|
|
20
|
-
const serverHandoffCache = new Map();
|
|
21
|
-
const emptyHandoff = {};
|
|
22
21
|
const getServerHandoff = id => {
|
|
23
|
-
if (typeof document === 'undefined') return emptyHandoff;
|
|
24
|
-
const cached = serverHandoffCache.get(id);
|
|
25
|
-
if (cached !== undefined) return cached;
|
|
26
22
|
try {
|
|
27
23
|
const serverData = document.getElementById(`__PRIMER_DATA_${id}__`)?.textContent;
|
|
28
|
-
if (serverData)
|
|
29
|
-
const parsed = JSON.parse(serverData);
|
|
30
|
-
serverHandoffCache.set(id, parsed);
|
|
31
|
-
return parsed;
|
|
32
|
-
}
|
|
24
|
+
if (serverData) return JSON.parse(serverData);
|
|
33
25
|
} catch (_error) {
|
|
34
26
|
// if document/element does not exist or JSON is invalid, supress error
|
|
35
27
|
}
|
|
36
|
-
|
|
37
|
-
serverHandoffCache.set(id, empty);
|
|
38
|
-
return empty;
|
|
28
|
+
return {};
|
|
39
29
|
};
|
|
40
|
-
const emptySubscribe = () => () => {};
|
|
41
30
|
const ThemeProvider = ({
|
|
42
31
|
children,
|
|
43
32
|
...props
|
|
@@ -53,33 +42,56 @@ const ThemeProvider = ({
|
|
|
53
42
|
// Initialize state
|
|
54
43
|
const theme$1 = props.theme ?? fallbackTheme ?? theme;
|
|
55
44
|
const uniqueDataId = useId();
|
|
45
|
+
const {
|
|
46
|
+
resolvedServerColorMode
|
|
47
|
+
} = getServerHandoff(uniqueDataId);
|
|
48
|
+
const resolvedColorModePassthrough = React.useRef(resolvedServerColorMode);
|
|
56
49
|
const [colorMode, setColorMode] = useSyncedState(props.colorMode ?? fallbackColorMode ?? defaultColorMode);
|
|
57
50
|
const [dayScheme, setDayScheme] = useSyncedState(props.dayScheme ?? fallbackDayScheme ?? defaultDayScheme);
|
|
58
51
|
const [nightScheme, setNightScheme] = useSyncedState(props.nightScheme ?? fallbackNightScheme ?? defaultNightScheme);
|
|
59
52
|
const systemColorMode = useSystemColorMode();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// to avoid mismatches. After hydration, resolve from client state.
|
|
63
|
-
const resolvedColorMode = React.useSyncExternalStore(emptySubscribe, () => clientColorMode, () => getServerHandoff(uniqueDataId).resolvedServerColorMode ?? clientColorMode);
|
|
53
|
+
// eslint-disable-next-line react-hooks/refs
|
|
54
|
+
const resolvedColorMode = resolvedColorModePassthrough.current || resolveColorMode(colorMode, systemColorMode);
|
|
64
55
|
const colorScheme = chooseColorScheme(resolvedColorMode, dayScheme, nightScheme);
|
|
65
56
|
const {
|
|
66
57
|
resolvedTheme,
|
|
67
58
|
resolvedColorScheme
|
|
68
59
|
} = React.useMemo(() => applyColorScheme(theme$1, colorScheme), [theme$1, colorScheme]);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
colorMode,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
60
|
+
|
|
61
|
+
// this effect will only run on client
|
|
62
|
+
React.useEffect(function updateColorModeAfterServerPassthrough() {
|
|
63
|
+
const resolvedColorModeOnClient = resolveColorMode(colorMode, systemColorMode);
|
|
64
|
+
if (resolvedColorModePassthrough.current) {
|
|
65
|
+
// if the resolved color mode passed on from the server is not the resolved color mode on client, change it!
|
|
66
|
+
if (resolvedColorModePassthrough.current !== resolvedColorModeOnClient) {
|
|
67
|
+
window.setTimeout(() => {
|
|
68
|
+
// use ReactDOM.flushSync to prevent automatic batching of state updates since React 18
|
|
69
|
+
// ref: https://github.com/reactwg/react-18/discussions/21
|
|
70
|
+
ReactDOM.flushSync(() => {
|
|
71
|
+
// override colorMode to whatever is resolved on the client to get a re-render
|
|
72
|
+
setColorMode(resolvedColorModeOnClient);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// immediately after that, set the colorMode to what the user passed to respond to system color mode changes
|
|
76
|
+
setColorMode(colorMode);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
resolvedColorModePassthrough.current = null;
|
|
80
|
+
}
|
|
81
|
+
}, [colorMode, systemColorMode, setColorMode]);
|
|
81
82
|
return /*#__PURE__*/jsx(ThemeContext.Provider, {
|
|
82
|
-
value:
|
|
83
|
+
value: {
|
|
84
|
+
theme: resolvedTheme,
|
|
85
|
+
colorScheme,
|
|
86
|
+
colorMode,
|
|
87
|
+
resolvedColorMode,
|
|
88
|
+
resolvedColorScheme,
|
|
89
|
+
dayScheme,
|
|
90
|
+
nightScheme,
|
|
91
|
+
setColorMode,
|
|
92
|
+
setDayScheme,
|
|
93
|
+
setNightScheme
|
|
94
|
+
},
|
|
83
95
|
children: /*#__PURE__*/jsxs(ThemeProvider$1, {
|
|
84
96
|
theme: resolvedTheme,
|
|
85
97
|
children: [children, props.preventSSRMismatch ? /*#__PURE__*/jsx("script", {
|
|
@@ -103,20 +115,48 @@ function useColorSchemeVar(values, fallback) {
|
|
|
103
115
|
} = useTheme();
|
|
104
116
|
return values[colorScheme] ?? fallback;
|
|
105
117
|
}
|
|
106
|
-
function subscribeToSystemColorMode(callback) {
|
|
107
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
108
|
-
const media = window?.matchMedia?.('(prefers-color-scheme: dark)');
|
|
109
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
110
|
-
media?.addEventListener('change', callback);
|
|
111
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
112
|
-
return () => media?.removeEventListener('change', callback);
|
|
113
|
-
}
|
|
114
118
|
function useSystemColorMode() {
|
|
115
|
-
|
|
119
|
+
const [systemColorMode, setSystemColorMode] = React.useState(getSystemColorMode);
|
|
120
|
+
React.useEffect(() => {
|
|
121
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
122
|
+
const media = window?.matchMedia?.('(prefers-color-scheme: dark)');
|
|
123
|
+
function matchesMediaToColorMode(matches) {
|
|
124
|
+
return matches ? 'night' : 'day';
|
|
125
|
+
}
|
|
126
|
+
function handleChange(event) {
|
|
127
|
+
const isNight = event.matches;
|
|
128
|
+
setSystemColorMode(matchesMediaToColorMode(isNight));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
132
|
+
if (media) {
|
|
133
|
+
// just in case the preference changed before the event listener was attached
|
|
134
|
+
const isNight = media.matches;
|
|
135
|
+
setSystemColorMode(matchesMediaToColorMode(isNight));
|
|
136
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
137
|
+
if (media.addEventListener !== undefined) {
|
|
138
|
+
media.addEventListener('change', handleChange);
|
|
139
|
+
return function cleanup() {
|
|
140
|
+
media.removeEventListener('change', handleChange);
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
144
|
+
else if (media.addListener !== undefined) {
|
|
145
|
+
media.addListener(handleChange);
|
|
146
|
+
return function cleanup() {
|
|
147
|
+
media.removeListener(handleChange);
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}, []);
|
|
152
|
+
return systemColorMode;
|
|
116
153
|
}
|
|
117
154
|
function getSystemColorMode() {
|
|
118
155
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
119
|
-
|
|
156
|
+
if (typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)')?.matches) {
|
|
157
|
+
return 'night';
|
|
158
|
+
}
|
|
159
|
+
return 'day';
|
|
120
160
|
}
|
|
121
161
|
function resolveColorMode(colorMode, systemColorMode) {
|
|
122
162
|
switch (colorMode) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primer/styled-react",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-20260326174604",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@babel/preset-react": "^7.28.5",
|
|
47
47
|
"@babel/preset-typescript": "^7.28.5",
|
|
48
48
|
"@primer/primitives": "10.x || 11.x",
|
|
49
|
-
"@primer/react": "0.0.0-
|
|
49
|
+
"@primer/react": "0.0.0-20260326174604",
|
|
50
50
|
"@rollup/plugin-babel": "^6.1.0",
|
|
51
51
|
"@storybook/react-vite": "^10.1.11",
|
|
52
52
|
"@types/react": "18.3.11",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"typescript": "^5.9.2"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"@primer/react": "0.0.0-
|
|
70
|
+
"@primer/react": "0.0.0-20260326174604",
|
|
71
71
|
"@types/react": "18.x || 19.x",
|
|
72
72
|
"@types/react-dom": "18.x || 19.x",
|
|
73
73
|
"@types/react-is": "18.x || 19.x",
|