colbrush 1.21.0 โ†’ 1.23.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/README.md CHANGED
@@ -24,6 +24,7 @@
24
24
  - `updateTheme(theme: ThemeType)`: update the current theme (supports color-blind modes)
25
25
  - `language`: current language setting (currently supports **Korean** and **English**)
26
26
  - `updateLanguage(language: TLanguage)`: update the language context
27
+
27
28
  - ๐Ÿงช Customizable color scales and transformation algorithms
28
29
 
29
30
  ---
@@ -99,6 +100,42 @@ function App() {
99
100
  }
100
101
  ```
101
102
 
103
+ In CSR apps such as Vite, `ThemeProvider` is usually enough to reduce theme flash. Use it as the default setup.
104
+
105
+ If a CSR app still flashes because the JavaScript bundle loads late, add the same early theme script to `index.html`:
106
+
107
+ ```
108
+ <head>
109
+ <script>
110
+ try {
111
+ var t = localStorage.getItem('colbrush-theme');
112
+ if (['default', 'protanopia', 'deuteranopia', 'tritanopia'].indexOf(t) > -1) {
113
+ document.documentElement.setAttribute('data-theme', t);
114
+ }
115
+ } catch (e) {}
116
+ </script>
117
+ </head>
118
+ ```
119
+
120
+ For SSR apps, or when you need strict first-paint theme protection, render `ThemeScript` inside `<head>`:
121
+
122
+ ```
123
+ import { ThemeProvider, ThemeScript } from 'colbrush/client';
124
+
125
+ export default function RootLayout({ children }) {
126
+ return (
127
+ <html lang="en" suppressHydrationWarning>
128
+ <head>
129
+ <ThemeScript />
130
+ </head>
131
+ <body>
132
+ <ThemeProvider>{children}</ThemeProvider>
133
+ </body>
134
+ </html>
135
+ );
136
+ }
137
+ ```
138
+
102
139
  ### 4. Import colbrush/styles.css
103
140
 
104
141
  ```
@@ -249,4 +286,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
249
286
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
250
287
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
251
288
  SOFTWARE.
252
-
@@ -1,5 +1,12 @@
1
1
  // src/react/ThemeProvider.tsx
2
- import { createContext, useContext, useEffect, useMemo, useState } from "react";
2
+ import {
3
+ createContext,
4
+ useContext,
5
+ useEffect,
6
+ useLayoutEffect,
7
+ useMemo,
8
+ useState
9
+ } from "react";
3
10
 
4
11
  // src/core/constants/modes.ts
5
12
  var SIMULATION_MODES = [
@@ -66,6 +73,7 @@ var ThemeContext = createContext({
66
73
  }
67
74
  });
68
75
  var useTheme = () => useContext(ThemeContext);
76
+ var useSafeLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
69
77
  function normalizeToKey(value) {
70
78
  if (!value) return "default";
71
79
  if (THEME_MODES.includes(value))
@@ -80,17 +88,28 @@ function normalizeToKey(value) {
80
88
  });
81
89
  return reverse[value] ?? "default";
82
90
  }
91
+ function getStorageItem(key) {
92
+ try {
93
+ return typeof window === "undefined" ? null : localStorage.getItem(key);
94
+ } catch {
95
+ return null;
96
+ }
97
+ }
98
+ function setStorageItem(key, value) {
99
+ try {
100
+ localStorage.setItem(key, value);
101
+ } catch {
102
+ }
103
+ }
83
104
  function ThemeProvider({ children }) {
84
105
  const [theme, setTheme] = useState("default");
85
106
  const [simulationFilter, setSimulationFilter] = useState("none");
86
107
  const [language, setLanguage] = useState("English");
87
- useEffect(() => {
108
+ useSafeLayoutEffect(() => {
88
109
  if (typeof window === "undefined") return;
89
- const storedTheme = normalizeToKey(
90
- localStorage.getItem(ThemeStorageKey)
91
- );
92
- const storedLang = localStorage.getItem(LanguageStorageKey) || "English";
93
- const storedFilter = localStorage.getItem(SimulationStorageKey) || "none";
110
+ const storedTheme = normalizeToKey(getStorageItem(ThemeStorageKey));
111
+ const storedLang = getStorageItem(LanguageStorageKey) || "English";
112
+ const storedFilter = getStorageItem(SimulationStorageKey) || "none";
94
113
  setSimulationFilter(storedFilter);
95
114
  setTheme(storedTheme);
96
115
  setLanguage(storedLang);
@@ -99,14 +118,14 @@ function ThemeProvider({ children }) {
99
118
  const updateTheme = (k) => {
100
119
  setTheme(k);
101
120
  if (typeof window !== "undefined") {
102
- localStorage.setItem(ThemeStorageKey, k);
121
+ setStorageItem(ThemeStorageKey, k);
103
122
  document.documentElement.setAttribute("data-theme", k);
104
123
  }
105
124
  };
106
125
  const updateLanguage = (t) => {
107
126
  setLanguage(t);
108
127
  if (typeof window !== "undefined") {
109
- localStorage.setItem(LanguageStorageKey, t);
128
+ setStorageItem(LanguageStorageKey, t);
110
129
  }
111
130
  };
112
131
  const value = useMemo(
@@ -152,8 +171,10 @@ var TOOLBAR_POSITION = {
152
171
 
153
172
  export {
154
173
  SIMULATION_MODES,
174
+ THEME_MODES,
155
175
  MODE_LABELS,
156
176
  SIMULATE_LABEL,
177
+ ThemeStorageKey,
157
178
  SimulationStorageKey,
158
179
  VISION_PORTAL_ID,
159
180
  FILTER_ID,
package/dist/cli.cjs CHANGED
@@ -690,7 +690,7 @@ ${bold("LEARN MORE")}
690
690
 
691
691
  // src/cli/index.ts
692
692
  var import_node_fs3 = __toESM(require("fs"), 1);
693
- var VERSION = "1.21.0";
693
+ var VERSION = "1.23.0";
694
694
  async function main() {
695
695
  const flags = parseFlags();
696
696
  const progress = createCliProgress();