colbrush 1.2.0 → 1.4.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
@@ -89,16 +89,15 @@ function Settings() {
89
89
  ```
90
90
  ### 5. Use hooks for theme and language switching
91
91
  ```
92
- import { useUpdateLanguage, useUpdateTheme } from 'colbrush/client';
92
+ import { useTheme } from 'colbrush/client';
93
93
 
94
94
  export default function TestPage() {
95
- const updateTheme = useUpdateTheme();
96
- const updateLanguage = useUpdateLanguage();
95
+ const { theme, updateTheme, language, updateLanguage } = useTheme();
97
96
 
98
97
  return (
99
98
  <div className="flex">
100
- <button onClick={() => updateTheme('tritanopia')}>색맹 유형 변경</button>
101
- <button onClick={() => updateLanguage('English')}>언어 변경</button>
99
+ <button onClick={() => updateTheme('tritanopia')}>Change to tritanopia</button>
100
+ <button onClick={() => updateLanguage('English')}>Change to English</button>
102
101
  </div>
103
102
  );
104
103
  }
@@ -128,3 +127,4 @@ The above copyright notice and this permission notice shall be included in all c
128
127
 
129
128
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
130
129
 
130
+
package/dist/cli.cjs CHANGED
@@ -23,7 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  mod
24
24
  ));
25
25
 
26
- // src/node/parseFlags.ts
26
+ // src/cli/parseFlags.ts
27
27
  function parseFlags(argv = process.argv.slice(2)) {
28
28
  const out = { _: [] };
29
29
  for (const s of argv) {
@@ -35,19 +35,19 @@ function parseFlags(argv = process.argv.slice(2)) {
35
35
  return out;
36
36
  }
37
37
 
38
- // src/constants/regex.ts
38
+ // src/core/constants/regex.ts
39
39
  var variableRegex = /(--color-[\w-]+):\s*(#[0-9a-fA-F]{3,8})/g;
40
40
  var variationRegex = /^--(.+?)-(50|100|200|300|400|500|600|700|800|900)$/i;
41
41
 
42
- // src/node/applyThemes.ts
42
+ // src/cli/applyThemes.ts
43
43
  var import_node_fs = __toESM(require("fs"), 1);
44
44
  var import_postcss = __toESM(require("postcss"), 1);
45
45
  var import_postcss_safe_parser = __toESM(require("postcss-safe-parser"), 1);
46
46
 
47
- // src/utils/core/colorScale.ts
47
+ // src/core/utils/colorScale.ts
48
48
  var import_colorjs = __toESM(require("colorjs.io"), 1);
49
49
 
50
- // src/constants/variation.ts
50
+ // src/core/constants/variation.ts
51
51
  var DEFAULT_KEYS = [
52
52
  "50",
53
53
  "100",
@@ -73,7 +73,7 @@ var DEFAULT_SCALE = {
73
73
  "900": { dL: -0.3, cMul: 0.88 }
74
74
  };
75
75
 
76
- // src/utils/core/colorScale.ts
76
+ // src/core/utils/colorScale.ts
77
77
  var CLAMP01 = (x) => Math.max(0, Math.min(1, x));
78
78
  function hexToOKLCH(hex) {
79
79
  const c = new import_colorjs.default(hex);
@@ -103,11 +103,8 @@ function buildScaleFromBaseHex(baseHex, opts) {
103
103
  return out;
104
104
  }
105
105
 
106
- // src/node/applyThemes.ts
106
+ // src/cli/applyThemes.ts
107
107
  var CSS_PATH = "src/index.css";
108
- function toThemeColor(hex, _vision) {
109
- return hex;
110
- }
111
108
  function loadRoot(cssPath = CSS_PATH) {
112
109
  const css = import_node_fs.default.readFileSync(cssPath, "utf8");
113
110
  return (0, import_postcss.default)().process(css, { parser: import_postcss_safe_parser.default }).root;
@@ -152,7 +149,7 @@ function getColorVariablesFromRoot(root) {
152
149
  });
153
150
  return vars;
154
151
  }
155
- function applyThemes(input, cssPath = CSS_PATH) {
152
+ function applyThemes(input, cssPath = CSS_PATH, opts) {
156
153
  const root = loadRoot(cssPath);
157
154
  const originalVars = getColorVariablesFromRoot(root);
158
155
  const varsForTheme = {};
@@ -167,27 +164,31 @@ function applyThemes(input, cssPath = CSS_PATH) {
167
164
  const [, token] = m;
168
165
  const keys = rich.keys && rich.keys.length ? rich.keys : getExistingKeysForToken(root, token).length ? getExistingKeysForToken(root, token) : Array.from(DEFAULT_KEYS);
169
166
  if (rich.scale !== false) {
170
- const scaleMap = buildScaleFromBaseHex(rich.base, { keys });
167
+ const scaleMap = buildScaleFromBaseHex(rich.base, {
168
+ keys
169
+ });
171
170
  for (const k of keys) {
172
171
  const hex = scaleMap[k];
173
- varsForTheme[`--${token}-${k}`] = toThemeColor(hex, input.vision);
172
+ varsForTheme[`--${token}-${k}`] = hex;
174
173
  }
175
174
  } else {
176
- varsForTheme[varName] = toThemeColor(rich.base, input.vision);
175
+ varsForTheme[varName] = rich.base;
177
176
  }
178
177
  } else {
179
- varsForTheme[varName] = toThemeColor(rich.base, input.vision);
178
+ varsForTheme[varName] = rich.base;
180
179
  }
181
180
  }
182
181
  upsertBlock(root, `[data-theme='${input.vision}']`, varsForTheme);
183
182
  import_node_fs.default.writeFileSync(cssPath, root.toString(), "utf8");
184
- console.log(`\u2705 [${input.vision}] theme updated in ${cssPath}`);
183
+ if (!opts?.silent) {
184
+ console.log(`\u2705 [${input.vision}] theme updated in ${cssPath}`);
185
+ }
185
186
  }
186
187
  function inferRich(varName, baseHex) {
187
188
  return variationRegex.test(varName) ? { base: baseHex, scale: true } : { base: baseHex, scale: false };
188
189
  }
189
190
 
190
- // src/node/colorTransform.ts
191
+ // src/cli/colorTransform.ts
191
192
  var import_chroma_js = __toESM(require("chroma-js"), 1);
192
193
  var import_color_blind = __toESM(require("color-blind"), 1);
193
194
  var THRESHOLD = 10;
@@ -199,7 +200,10 @@ function generateCandidates(hex) {
199
200
  candidates[0] = hex;
200
201
  for (let i = 1; i <= CANDIDATE_COUNT / 2; i++) {
201
202
  candidates[i * 2 - 1] = (0, import_chroma_js.default)(hex).set("hcl.h", (baseHue + HUE_STEP / CANDIDATE_COUNT * i) % 360).hex();
202
- candidates[i * 2] = (0, import_chroma_js.default)(hex).set("hcl.h", (baseHue - HUE_STEP / CANDIDATE_COUNT * i + 360) % 360).hex();
203
+ candidates[i * 2] = (0, import_chroma_js.default)(hex).set(
204
+ "hcl.h",
205
+ (baseHue - HUE_STEP / CANDIDATE_COUNT * i + 360) % 360
206
+ ).hex();
203
207
  }
204
208
  return candidates;
205
209
  }
@@ -213,7 +217,7 @@ function findOptimalColorCombination(colorKeys, baseColorsArray, candidateList,
213
217
  case "protanopia":
214
218
  blind = import_color_blind.default.protanopia;
215
219
  break;
216
- // 녹색맹
220
+ // 녹색맹
217
221
  case "deuteranopia":
218
222
  blind = import_color_blind.default.deuteranopia;
219
223
  break;
@@ -244,12 +248,15 @@ function findOptimalColorCombination(colorKeys, baseColorsArray, candidateList,
244
248
  }
245
249
  dfs(0, [], 0);
246
250
  const finalColors = bestColors ?? [...baseColorsArray];
247
- return colorKeys.reduce((acc, key, idx) => {
248
- acc[key] = finalColors[idx];
249
- return acc;
250
- }, {});
251
+ return colorKeys.reduce(
252
+ (acc, key, idx) => {
253
+ acc[key] = finalColors[idx];
254
+ return acc;
255
+ },
256
+ {}
257
+ );
251
258
  }
252
- async function requestColorTransformation(variables) {
259
+ function prepareCandidates(variables, progress) {
253
260
  const scaleGroups = {};
254
261
  const filteredVariables = {};
255
262
  for (const key in variables) {
@@ -275,26 +282,30 @@ async function requestColorTransformation(variables) {
275
282
  }
276
283
  const colorKeys = Object.keys(filteredVariables);
277
284
  const baseColorsArray = Object.values(filteredVariables).map((v) => v.base);
278
- const candidateList = baseColorsArray.map((color) => {
279
- return generateCandidates(color);
280
- });
281
- const colors_d = findOptimalColorCombination(colorKeys, baseColorsArray, candidateList, "deuteranopia");
282
- const colors_p = findOptimalColorCombination(colorKeys, baseColorsArray, candidateList, "protanopia");
283
- const colors_t = findOptimalColorCombination(colorKeys, baseColorsArray, candidateList, "tritanopia");
284
- const visions = ["deuteranopia", "protanopia", "tritanopia"];
285
- const colorsMap = {
286
- deuteranopia: colors_d,
287
- protanopia: colors_p,
288
- tritanopia: colors_t
289
- };
290
- const themes = visions.map((vision) => ({
291
- vision,
292
- variables: Object.entries(colorsMap[vision]).reduce((acc, [varName, baseHex]) => {
285
+ progress?.startSection("Generate candidates");
286
+ const candidateList = [];
287
+ for (let i = 0; i < baseColorsArray.length; i++) {
288
+ candidateList[i] = generateCandidates(baseColorsArray[i]);
289
+ progress?.update((i + 1) / baseColorsArray.length * 100);
290
+ }
291
+ progress?.finishSection("Done");
292
+ return { colorKeys, baseColorsArray, candidateList };
293
+ }
294
+ function buildThemeForVision(colorKeys, baseColorsArray, candidateList, vision) {
295
+ const colors = findOptimalColorCombination(
296
+ colorKeys,
297
+ baseColorsArray,
298
+ candidateList,
299
+ vision
300
+ );
301
+ const variables = Object.entries(colors).reduce(
302
+ (acc, [varName, baseHex]) => {
293
303
  acc[varName] = inferRich(varName, baseHex);
294
304
  return acc;
295
- }, {})
296
- }));
297
- return { themes };
305
+ },
306
+ {}
307
+ );
308
+ return { vision, variables };
298
309
  }
299
310
  function getMiddleScaleKey(keys) {
300
311
  const scaleNumbers = keys.map((k) => {
@@ -311,16 +322,17 @@ function getMiddleScaleKey(keys) {
311
322
  function isValidColors(colors, blind) {
312
323
  for (let i = 0; i < colors.length; i++) {
313
324
  for (let j = i + 1; j < colors.length; j++) {
314
- if (import_chroma_js.default.deltaE(blind(colors[i]), blind(colors[j])) < THRESHOLD) return false;
325
+ if (import_chroma_js.default.deltaE(blind(colors[i]), blind(colors[j])) < THRESHOLD)
326
+ return false;
315
327
  }
316
328
  }
317
329
  return true;
318
330
  }
319
331
 
320
- // src/node/runThemeApply.ts
332
+ // src/cli/runThemeApply.ts
321
333
  var import_node_fs2 = __toESM(require("fs"), 1);
322
334
 
323
- // src/node/removeExistingThemeBlocks.ts
335
+ // src/cli/removeExistingThemeBlocks.ts
324
336
  function removeExistingThemeBlocks(content) {
325
337
  const visions = ["protanopia", "deuteranopia", "tritanopia"];
326
338
  let cleaned = content;
@@ -334,7 +346,7 @@ function removeExistingThemeBlocks(content) {
334
346
  return cleaned.trim();
335
347
  }
336
348
 
337
- // src/node/runThemeApply.ts
349
+ // src/cli/runThemeApply.ts
338
350
  function hexToRgb(hex) {
339
351
  let clean = hex.replace("#", "").toLowerCase();
340
352
  if (clean.length === 3) {
@@ -368,19 +380,30 @@ function calculateScale(varName, hexColor) {
368
380
  }
369
381
  return /\d+$/.test(varName);
370
382
  }
371
- async function runThemeApply(cssPath) {
383
+ async function runThemeApply(cssPath, progress) {
372
384
  if (!import_node_fs2.default.existsSync(cssPath)) {
373
385
  throw new Error(`\u274C CSS \uD30C\uC77C\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${cssPath}`);
374
386
  }
375
387
  let content = import_node_fs2.default.readFileSync(cssPath, "utf8");
388
+ progress?.startSection("Remove existing theme blocks");
376
389
  content = removeExistingThemeBlocks(content);
390
+ progress?.update(100);
391
+ progress?.finishSection("Done");
377
392
  const variables = {};
393
+ progress?.startSection("Extract variables");
394
+ const scanRegex = new RegExp(variableRegex.source, variableRegex.flags);
395
+ const all = Array.from(content.matchAll(scanRegex));
396
+ const totalVars = all.length || 1;
397
+ const loopRegex = new RegExp(variableRegex.source, variableRegex.flags);
378
398
  let match;
379
- while ((match = variableRegex.exec(content)) !== null) {
399
+ let count = 0;
400
+ while ((match = loopRegex.exec(content)) !== null) {
380
401
  const [, key, value] = match;
381
402
  const cleanKey = key.trim();
382
403
  const cleanValue = value.trim().toLowerCase();
383
404
  if (isNeutralColor(cleanValue)) {
405
+ count++;
406
+ progress?.update(count / totalVars * 100);
384
407
  continue;
385
408
  }
386
409
  const scale = calculateScale(cleanKey, cleanValue);
@@ -389,35 +412,159 @@ async function runThemeApply(cssPath) {
389
412
  scale
390
413
  };
391
414
  variables[cleanKey] = rich;
415
+ count++;
416
+ progress?.update(count / totalVars * 100);
392
417
  }
418
+ progress?.finishSection("Done");
393
419
  const visions = ["deuteranopia", "protanopia", "tritanopia"];
394
420
  try {
395
- const algorithmResult = await requestColorTransformation(variables);
396
- for (const themeData of algorithmResult.themes) {
397
- await applyThemes(themeData, cssPath);
421
+ const { colorKeys, baseColorsArray, candidateList } = prepareCandidates(
422
+ variables,
423
+ progress
424
+ );
425
+ for (const vision of visions) {
426
+ const label = `Process \u2014 ${vision}`;
427
+ progress?.startSection(label);
428
+ progress?.update(30, "Optimizing...");
429
+ const themeData = buildThemeForVision(
430
+ colorKeys,
431
+ baseColorsArray,
432
+ candidateList,
433
+ vision
434
+ );
435
+ progress?.update(70, "Applying CSS...");
436
+ await applyThemes(themeData, cssPath, { silent: !!progress });
437
+ progress?.update(100, "Done");
438
+ progress?.finishSection("Done");
398
439
  }
399
440
  } catch (error) {
400
441
  console.log("\u{1F680} ~ runThemeApply ~ error:", error);
401
442
  for (const vision of visions) {
402
- await applyThemes({ vision, variables }, cssPath);
443
+ const label = `Process (fallback) \u2014 ${vision}`;
444
+ progress?.startSection(label);
445
+ await applyThemes({ vision, variables }, cssPath, {
446
+ silent: !!progress
447
+ });
448
+ progress?.finishSection("Done");
449
+ }
450
+ }
451
+ console.log(`
452
+ \u2705 Colbrush themes applied to ${cssPath}`);
453
+ }
454
+
455
+ // src/cli/progress.ts
456
+ function clampPercent(n) {
457
+ if (Number.isNaN(n)) return 0;
458
+ return Math.max(0, Math.min(100, n));
459
+ }
460
+ function createCliProgress() {
461
+ let hasAnyOutput = false;
462
+ let currentSection = null;
463
+ let sectionStartedAt = 0;
464
+ const isTTY = !!process.stdout.isTTY;
465
+ const A = {
466
+ reset: "\x1B[0m",
467
+ // 리셋
468
+ bold: "\x1B[1m",
469
+ // 굵게
470
+ dim: "\x1B[2m",
471
+ // 흐리게
472
+ green: "\x1B[32m",
473
+ // 초록
474
+ cyan: "\x1B[36m",
475
+ // 청록
476
+ clearLine: "\x1B[2K",
477
+ // 줄 지우기
478
+ carriage: "\r"
479
+ // 캐리지 리턴
480
+ };
481
+ const style = (code, text) => isTTY ? `${code}${text}${A.reset}` : text;
482
+ const bold = (t) => style(A.bold, t);
483
+ const dim = (t) => style(A.dim, t);
484
+ const green = (t) => style(A.green, t);
485
+ const cyan = (t) => style(A.cyan, t);
486
+ function writeSameLine(text) {
487
+ if (isTTY) {
488
+ process.stdout.write(A.clearLine + A.carriage + text);
489
+ } else {
490
+ console.log(text);
403
491
  }
492
+ hasAnyOutput = true;
493
+ }
494
+ function newline() {
495
+ if (hasAnyOutput) process.stdout.write("\n");
404
496
  }
405
- console.log(`\u2705 ${cssPath}\uC5D0 \uC0C9\uB9F9 \uD14C\uB9C8\uAC00 \uC801\uC6A9\uB418\uC5C8\uC2B5\uB2C8\uB2E4`);
497
+ function getTerminalColumns() {
498
+ const c = typeof process.stdout.columns === "number" ? process.stdout.columns : 80;
499
+ return Math.max(40, c);
500
+ }
501
+ function renderBar(pct) {
502
+ const columns = getTerminalColumns();
503
+ const width = Math.max(12, Math.min(30, Math.floor(columns * 0.3)));
504
+ const filled = Math.round(pct / 100 * width);
505
+ const fillChar = "\u2588";
506
+ const emptyChar = "\u2591";
507
+ const body = fillChar.repeat(filled) + emptyChar.repeat(width - filled);
508
+ return pct >= 100 ? green(body) : cyan(body);
509
+ }
510
+ function render(pctRaw, suffixLabel, opts) {
511
+ const p = clampPercent(pctRaw);
512
+ const name = currentSection ? bold(currentSection) : "";
513
+ const bar = renderBar(p);
514
+ const percentText = bold(`${p.toFixed(0).padStart(3, " ")}%`);
515
+ const prefix = isTTY ? `${cyan("\u203A")} ${name ? name + " " : ""}` : name ? name + " " : "";
516
+ const suffix = suffixLabel ? ` ${opts?.styledSuffix ? suffixLabel : dim(suffixLabel)}` : "";
517
+ writeSameLine(`${prefix}[${bar}] ${percentText}${suffix}`);
518
+ }
519
+ return {
520
+ startSection(name) {
521
+ if (currentSection) newline();
522
+ currentSection = name;
523
+ sectionStartedAt = Date.now();
524
+ render(0);
525
+ },
526
+ update(percent, label) {
527
+ if (!currentSection) {
528
+ currentSection = "";
529
+ sectionStartedAt = Date.now();
530
+ }
531
+ render(percent, label);
532
+ },
533
+ finishSection() {
534
+ if (!currentSection) return;
535
+ const ms = Date.now() - sectionStartedAt;
536
+ const secText = (ms / 1e3).toFixed(1) + "s";
537
+ const doneStyled = `${green("\u2714 Done")} ${dim(`(${secText})`)}`;
538
+ render(100, doneStyled, { styledSuffix: true });
539
+ newline();
540
+ process.stdout.write("\n\n");
541
+ currentSection = null;
542
+ },
543
+ // 하위 호환: 단일 바를 하나의 섹션처럼 취급
544
+ start(_totalHint, label) {
545
+ this.startSection(label ?? "");
546
+ },
547
+ finish(label) {
548
+ this.finishSection(label);
549
+ }
550
+ };
406
551
  }
407
552
 
408
- // src/cli.ts
553
+ // src/cli/index.ts
409
554
  async function main() {
410
555
  const flags = parseFlags();
411
556
  const cmd = flags._[0] ?? "generate";
412
557
  const cssPath = typeof flags.css === "string" ? flags.css : "src/index.css";
413
558
  if (cmd === "generate") {
414
- await runThemeApply(cssPath);
559
+ const progress = createCliProgress();
560
+ await runThemeApply(cssPath, progress);
415
561
  process.exit(0);
416
562
  }
417
- console.log(`\uC0AC\uC6A9 \uBC29\uBC95:
418
- - cb-theme generate [--css=src/index.css]
419
- CSS \uD30C\uC77C\uC5D0\uC11C \uC0C9\uC0C1 \uBCC0\uC218\uB4E4\uC744 \uCD94\uCD9C\uD558\uACE0, \uC0C9\uB9F9 \uD14C\uB9C8\uB97C \uC790\uB3D9 \uC0DD\uC131\uD558\uC5EC \uAC19\uC740 CSS \uD30C\uC77C\uC5D0 \uC801\uC6A9\uD569\uB2C8\uB2E4.
420
- (\uAE30\uBCF8 \uACBD\uB85C\uB294 src/index.css)
563
+ console.log(`Usage:
564
+ - colbrush generate [--css=src/index.css]
565
+ Extracts color variables from the CSS file and automatically generates color-blind themes,
566
+ then applies them to the same CSS file.
567
+ (Default path: src/index.css)
421
568
  `);
422
569
  process.exit(1);
423
570
  }
@@ -0,0 +1,715 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/client.ts
22
+ var client_exports = {};
23
+ __export(client_exports, {
24
+ THEMES: () => THEMES,
25
+ ThemeProvider: () => ThemeProvider,
26
+ ThemeSwitcher: () => ThemeSwitcher,
27
+ useTheme: () => useTheme
28
+ });
29
+ module.exports = __toCommonJS(client_exports);
30
+
31
+ // src/react/ThemeProvider.tsx
32
+ var import_react = require("react");
33
+ var import_jsx_runtime = require("react/jsx-runtime");
34
+ var THEME_KEYS = [
35
+ "default",
36
+ "protanopia",
37
+ "deuteranopia",
38
+ "tritanopia"
39
+ ];
40
+ var THEME_LABEL = {
41
+ English: {
42
+ default: "default",
43
+ protanopia: "protanopia",
44
+ deuteranopia: "deuteranopia",
45
+ tritanopia: "tritanopia"
46
+ },
47
+ Korean: {
48
+ default: "\uAE30\uBCF8",
49
+ protanopia: "\uC801\uC0C9\uB9F9",
50
+ deuteranopia: "\uB179\uC0C9\uB9F9",
51
+ tritanopia: "\uCCAD\uC0C9\uB9F9"
52
+ }
53
+ };
54
+ var getThemeOptions = (lang) => THEME_KEYS.map((key) => ({ key, label: THEME_LABEL[lang][key] }));
55
+ var KEY = "theme";
56
+ var LANG_KEY = "theme_lang";
57
+ var ThemeContext = (0, import_react.createContext)({
58
+ theme: "default",
59
+ language: "English",
60
+ updateTheme: () => {
61
+ },
62
+ updateLanguage: () => {
63
+ }
64
+ });
65
+ var useTheme = () => (0, import_react.useContext)(ThemeContext);
66
+ function normalizeToKey(value) {
67
+ if (!value) return "default";
68
+ if (THEME_KEYS.includes(value))
69
+ return value;
70
+ const reverse = {};
71
+ ["English", "Korean"].forEach((lang) => {
72
+ Object.entries(THEME_LABEL[lang]).forEach(
73
+ ([k, label]) => {
74
+ reverse[label] = k;
75
+ }
76
+ );
77
+ });
78
+ return reverse[value] ?? "default";
79
+ }
80
+ function ThemeProvider({ children }) {
81
+ const [theme, setTheme] = (0, import_react.useState)("default");
82
+ const [language, setLanguage] = (0, import_react.useState)("English");
83
+ (0, import_react.useEffect)(() => {
84
+ if (typeof window === "undefined") return;
85
+ const storedTheme = normalizeToKey(localStorage.getItem(KEY));
86
+ const storedLang = localStorage.getItem(LANG_KEY) || "English";
87
+ setTheme(storedTheme);
88
+ setLanguage(storedLang);
89
+ document.documentElement.setAttribute("data-theme", storedTheme);
90
+ }, []);
91
+ const updateTheme = (k) => {
92
+ setTheme(k);
93
+ if (typeof window !== "undefined") {
94
+ localStorage.setItem(KEY, k);
95
+ document.documentElement.setAttribute("data-theme", k);
96
+ }
97
+ };
98
+ const updateLanguage = (t) => {
99
+ setLanguage(t);
100
+ if (typeof window !== "undefined") {
101
+ localStorage.setItem(LANG_KEY, t);
102
+ }
103
+ };
104
+ const value = (0, import_react.useMemo)(
105
+ () => ({ theme, language, updateTheme, updateLanguage }),
106
+ [theme, language]
107
+ );
108
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value, children });
109
+ }
110
+ var THEMES = THEME_LABEL;
111
+
112
+ // src/react/ThemeSwitcher.tsx
113
+ var import_react3 = require("react");
114
+
115
+ // src/icons/Logo.tsx
116
+ var import_jsx_runtime2 = require("react/jsx-runtime");
117
+ var SvgLogo = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
118
+ "svg",
119
+ {
120
+ xmlns: "http://www.w3.org/2000/svg",
121
+ width: 39,
122
+ height: 40,
123
+ fill: "none",
124
+ ...props,
125
+ children: [
126
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { fill: "#CE78A9", d: "m.5 17.805 1.516-3.514 16.812-7.924-1.309 3.308z" }),
127
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
128
+ "path",
129
+ {
130
+ fill: "#D55D00",
131
+ d: "M3.187 24.212 1.05 19.32l14.056-7.097-1.378 3.376-9.233 4.685 2.48 5.72z"
132
+ }
133
+ ),
134
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
135
+ "path",
136
+ {
137
+ fill: "#E59F01",
138
+ d: "m22.276.741 3.496 1.556 7.732 16.901-3.292-1.347z"
139
+ }
140
+ ),
141
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
142
+ "path",
143
+ {
144
+ fill: "#000",
145
+ d: "m15.837 3.355 4.916-2.08L27.69 15.41l-3.36-1.417-4.58-9.285-5.747 2.415z"
146
+ }
147
+ ),
148
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
149
+ "path",
150
+ {
151
+ fill: "#0072B1",
152
+ d: "m17.036 39.246-3.493-1.562-7.699-16.917 3.29 1.354z"
153
+ }
154
+ ),
155
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
156
+ "path",
157
+ {
158
+ fill: "#F0E442",
159
+ d: "m23.477 36.645-4.92 2.07-6.908-14.149 3.357 1.423 4.562 9.295 5.751-2.404z"
160
+ }
161
+ ),
162
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
163
+ "path",
164
+ {
165
+ fill: "#009F73",
166
+ d: "m38.889 22.215-1.482 3.529-16.734 8.087 1.277-3.32z"
167
+ }
168
+ ),
169
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
170
+ "path",
171
+ {
172
+ fill: "#56B4E8",
173
+ d: "m36.14 15.833 2.184 4.871-13.987 7.233 1.345-3.389 9.187-4.775-2.536-5.694z"
174
+ }
175
+ )
176
+ ]
177
+ }
178
+ );
179
+ var Logo_default = SvgLogo;
180
+
181
+ // src/icons/Us.tsx
182
+ var import_jsx_runtime3 = require("react/jsx-runtime");
183
+ var SvgUs = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
184
+ "svg",
185
+ {
186
+ xmlns: "http://www.w3.org/2000/svg",
187
+ width: 28,
188
+ height: 21,
189
+ fill: "none",
190
+ ...props,
191
+ children: [
192
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("g", { clipPath: "url(#a)", filter: "url(#b)", children: [
193
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { fill: "#fff", d: "M3.996 4.166h20v13.333h-20z" }),
194
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
195
+ "path",
196
+ {
197
+ fill: "#D80027",
198
+ d: "M3.996 4.166h20v1.025h-20zm0 2.05h20v1.026h-20zm0 2.051h20v1.026h-20zm0 2.051h20v1.025h-20zm0 2.055h20v1.025h-20zm0 2.05h20v1.026h-20zm0 2.051h20v1.025h-20z"
199
+ }
200
+ ),
201
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { fill: "#2E52B2", d: "M3.996 4.166h10v7.177h-10z" }),
202
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
203
+ "path",
204
+ {
205
+ fill: "#fff",
206
+ d: "m5.86 9.581-.156-.499-.172.5h-.514l.417.3-.156.498.425-.308.413.308-.16-.499.425-.3zm2.195 0-.16-.499-.164.5h-.515l.418.3-.156.498.417-.308.42.308-.155-.499.417-.3zm2.202 0-.167-.499-.156.5h-.527l.43.3-.164.498.417-.308.429.308-.164-.499.417-.3zm2.191 0-.156-.499-.163.5h-.519l.421.3-.156.498.417-.308.422.308-.168-.499.429-.3zm-4.553-2.48-.164.5h-.515l.418.308-.156.49.417-.303.42.304-.155-.491.417-.308h-.522zm-2.191 0-.172.5h-.514l.417.308-.156.49.425-.303.413.304-.16-.491.425-.308H5.86zm4.386 0-.156.5h-.527l.43.308-.164.49.417-.303.429.304-.164-.491.417-.308h-.515zm2.202 0-.163.5h-.519l.421.308-.156.49.417-.303.422.304-.168-.491.429-.308h-.527zM5.704 5.13l-.172.491h-.514l.417.308-.156.495.425-.308.413.308-.16-.495.425-.308H5.86zm2.19 0-.163.491h-.515l.418.308-.156.495.417-.308.42.308-.155-.495.417-.308h-.522zm2.196 0-.156.491h-.527l.43.308-.164.495.417-.308.429.308-.164-.495.417-.308h-.515zm2.202 0-.163.491h-.519l.421.308-.156.495.417-.308.422.308-.168-.495.429-.308h-.527z"
207
+ }
208
+ )
209
+ ] }),
210
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("defs", { children: [
211
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("clipPath", { id: "a", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { fill: "#fff", d: "M3.996 4.166h20v13.333h-20z" }) }),
212
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
213
+ "filter",
214
+ {
215
+ id: "b",
216
+ width: 26.973,
217
+ height: 20.307,
218
+ x: 0.509,
219
+ y: 0.679,
220
+ colorInterpolationFilters: "sRGB",
221
+ filterUnits: "userSpaceOnUse",
222
+ children: [
223
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feFlood", { floodOpacity: 0, result: "BackgroundImageFix" }),
224
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
225
+ "feColorMatrix",
226
+ {
227
+ in: "SourceAlpha",
228
+ result: "hardAlpha",
229
+ values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
230
+ }
231
+ ),
232
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feOffset", {}),
233
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feGaussianBlur", { stdDeviation: 1.743 }),
234
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feComposite", { in2: "hardAlpha", operator: "out" }),
235
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feColorMatrix", { values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" }),
236
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
237
+ "feBlend",
238
+ {
239
+ in2: "BackgroundImageFix",
240
+ result: "effect1_dropShadow_306_3300"
241
+ }
242
+ ),
243
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
244
+ "feBlend",
245
+ {
246
+ in: "SourceGraphic",
247
+ in2: "effect1_dropShadow_306_3300",
248
+ result: "shape"
249
+ }
250
+ )
251
+ ]
252
+ }
253
+ )
254
+ ] })
255
+ ]
256
+ }
257
+ );
258
+ var Us_default = SvgUs;
259
+
260
+ // src/icons/Kr.tsx
261
+ var import_jsx_runtime4 = require("react/jsx-runtime");
262
+ var SvgKr = (props) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
263
+ "svg",
264
+ {
265
+ xmlns: "http://www.w3.org/2000/svg",
266
+ width: 24,
267
+ height: 17,
268
+ fill: "none",
269
+ ...props,
270
+ children: [
271
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("g", { clipPath: "url(#a)", filter: "url(#b)", children: [
272
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { fill: "#fff", d: "M1.906 2h20v13.333h-20z" }),
273
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
274
+ "path",
275
+ {
276
+ fill: "#000",
277
+ fillRule: "evenodd",
278
+ d: "m4.959 6.04 1.849-2.774.487.324-1.85 2.773zm.693.461 1.85-2.773.486.324-1.85 2.774zm.694.463L8.195 4.19l.486.324-1.849 2.774zm8.782 5.855 1.85-2.774.486.325-1.849 2.773zm.694.462 1.849-2.774.486.325-1.849 2.773zm3.029-1.987L17 14.068l-.486-.325 1.85-2.773z",
279
+ clipRule: "evenodd"
280
+ }
281
+ ),
282
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
283
+ "path",
284
+ {
285
+ fill: "#fff",
286
+ fillRule: "evenodd",
287
+ d: "m18.01 13.03-2.31-1.542.27-.405 2.31 1.54z",
288
+ clipRule: "evenodd"
289
+ }
290
+ ),
291
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
292
+ "path",
293
+ {
294
+ fill: "#CA163A",
295
+ d: "M14.68 10.514a3.333 3.333 0 1 0-5.548-3.698 3.333 3.333 0 0 0 5.547 3.698"
296
+ }
297
+ ),
298
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
299
+ "path",
300
+ {
301
+ fill: "#0E4896",
302
+ d: "M9.132 6.816a1.667 1.667 0 0 0 2.774 1.85 1.667 1.667 0 0 1 2.773 1.848 3.334 3.334 0 0 1-5.547-3.698"
303
+ }
304
+ ),
305
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
306
+ "path",
307
+ {
308
+ fill: "#000",
309
+ fillRule: "evenodd",
310
+ d: "m17.002 3.266 1.849 2.773-.487.325-1.849-2.774zm-.694.462 1.85 2.773-.487.325-1.85-2.774zm-.693.462 1.85 2.774-.488.324-1.848-2.773zm-8.783 5.855 1.85 2.774-.487.324-1.85-2.773zm-.693.463 1.849 2.773-.487.324-1.849-2.773zm-.693.462 1.849 2.773-.487.325-1.849-2.774z",
311
+ clipRule: "evenodd"
312
+ }
313
+ ),
314
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
315
+ "path",
316
+ {
317
+ fill: "#000",
318
+ d: "m6.475 12.286.693-.462zm9.36-6.24.81-.54zm1.502-1.002.694-.462z"
319
+ }
320
+ ),
321
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
322
+ "path",
323
+ {
324
+ fill: "#fff",
325
+ fillRule: "evenodd",
326
+ d: "m18.166 4.784-.693.463-.27-.406.693-.462zm-1.386.925-.81.54-.27-.406.81-.54zm-9.476 6.317-.694.463-.27-.406.693-.462z",
327
+ clipRule: "evenodd"
328
+ }
329
+ )
330
+ ] }),
331
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("defs", { children: [
332
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("clipPath", { id: "a", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { fill: "#fff", d: "M1.906 2h20v13.333h-20z" }) }),
333
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
334
+ "filter",
335
+ {
336
+ id: "b",
337
+ width: 22.602,
338
+ height: 15.936,
339
+ x: 0.605,
340
+ y: 0.699,
341
+ colorInterpolationFilters: "sRGB",
342
+ filterUnits: "userSpaceOnUse",
343
+ children: [
344
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feFlood", { floodOpacity: 0, result: "BackgroundImageFix" }),
345
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
346
+ "feColorMatrix",
347
+ {
348
+ in: "SourceAlpha",
349
+ result: "hardAlpha",
350
+ values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
351
+ }
352
+ ),
353
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feOffset", {}),
354
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feGaussianBlur", { stdDeviation: 0.65 }),
355
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feComposite", { in2: "hardAlpha", operator: "out" }),
356
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feColorMatrix", { values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" }),
357
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
358
+ "feBlend",
359
+ {
360
+ in2: "BackgroundImageFix",
361
+ result: "effect1_dropShadow_306_2477"
362
+ }
363
+ ),
364
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
365
+ "feBlend",
366
+ {
367
+ in: "SourceGraphic",
368
+ in2: "effect1_dropShadow_306_2477",
369
+ result: "shape"
370
+ }
371
+ )
372
+ ]
373
+ }
374
+ )
375
+ ] })
376
+ ]
377
+ }
378
+ );
379
+ var Kr_default = SvgKr;
380
+
381
+ // src/icons/X.tsx
382
+ var import_jsx_runtime5 = require("react/jsx-runtime");
383
+ var SvgX = (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
384
+ "svg",
385
+ {
386
+ xmlns: "http://www.w3.org/2000/svg",
387
+ width: 30,
388
+ height: 30,
389
+ fill: "none",
390
+ ...props,
391
+ children: [
392
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
393
+ "path",
394
+ {
395
+ fill: "#000",
396
+ fillRule: "evenodd",
397
+ d: "M25.977 4.023a.94.94 0 0 1 0 1.328L5.352 25.976a.939.939 0 0 1-1.327-1.328L24.65 4.023a.94.94 0 0 1 1.327 0",
398
+ clipRule: "evenodd"
399
+ }
400
+ ),
401
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
402
+ "path",
403
+ {
404
+ fill: "#000",
405
+ fillRule: "evenodd",
406
+ d: "M4.023 4.023a.94.94 0 0 0 0 1.328L24.65 25.976a.939.939 0 0 0 1.327-1.328L5.351 4.023a.94.94 0 0 0-1.328 0",
407
+ clipRule: "evenodd"
408
+ }
409
+ )
410
+ ]
411
+ }
412
+ );
413
+ var X_default = SvgX;
414
+
415
+ // src/icons/theme/Tritanopia.tsx
416
+ var import_jsx_runtime6 = require("react/jsx-runtime");
417
+ var SvgTritanopia = (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
418
+ "svg",
419
+ {
420
+ xmlns: "http://www.w3.org/2000/svg",
421
+ fill: "none",
422
+ viewBox: "0 0 28 29",
423
+ ...props,
424
+ children: [
425
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
426
+ "rect",
427
+ {
428
+ width: 26.18,
429
+ height: 26.18,
430
+ x: 0.91,
431
+ y: 1.41,
432
+ stroke: "currentColor",
433
+ strokeWidth: 1.82,
434
+ rx: 13.09
435
+ }
436
+ ),
437
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
438
+ "path",
439
+ {
440
+ fill: "currentColor",
441
+ d: "M8.64 7.152h5.21q1.508 0 2.532.513 1.026.513 1.528 1.405.513.892.513 2.02 0 1.333-.667 2.081-.666.74-1.753 1.036v.144q.717.04 1.415.492.698.45 1.148 1.282.452.819.452 1.938 0 1.158-.534 2.04-.522.882-1.64 1.395-1.118.502-2.81.502H8.641zm5.374 13.207q1.65 0 2.43-.635.79-.636.79-1.682 0-.758-.39-1.395a2.63 2.63 0 0 0-1.097-1.015q-.709-.38-1.63-.38h-3.63v5.107zm-.226-6.706q.8 0 1.456-.307.657-.319 1.036-.892.38-.585.38-1.344 0-1.024-.708-1.671-.708-.646-2.102-.646h-3.364v4.86z"
442
+ }
443
+ ),
444
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
445
+ "path",
446
+ {
447
+ stroke: "currentColor",
448
+ strokeWidth: 1.517,
449
+ d: "m3.5 1.666 23.333 23.333"
450
+ }
451
+ )
452
+ ]
453
+ }
454
+ );
455
+ var Tritanopia_default = SvgTritanopia;
456
+
457
+ // src/icons/theme/Default.tsx
458
+ var import_jsx_runtime7 = require("react/jsx-runtime");
459
+ var SvgDefault = (props) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
460
+ "svg",
461
+ {
462
+ xmlns: "http://www.w3.org/2000/svg",
463
+ fill: "none",
464
+ viewBox: "0 0 31 31",
465
+ ...props,
466
+ children: [
467
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
468
+ "path",
469
+ {
470
+ fill: "currentColor",
471
+ d: "M30.5 15.5s-5.625-10.312-15-10.312S.5 15.5.5 15.5s5.625 10.313 15 10.313 15-10.313 15-10.313m-27.801 0q.16-.245.365-.54c.628-.9 1.554-2.098 2.746-3.29 2.417-2.417 5.716-4.607 9.69-4.607s7.273 2.19 9.69 4.607A24.6 24.6 0 0 1 28.3 15.5q-.16.245-.365.54c-.628.9-1.554 2.098-2.746 3.29-2.417 2.417-5.716 4.608-9.69 4.608s-7.273-2.19-9.69-4.608A24.6 24.6 0 0 1 2.7 15.5"
472
+ }
473
+ ),
474
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
475
+ "path",
476
+ {
477
+ fill: "currentColor",
478
+ d: "M15.5 10.813a4.688 4.688 0 1 0 0 9.375 4.688 4.688 0 0 0 0-9.375M8.938 15.5a6.562 6.562 0 1 1 13.124 0 6.562 6.562 0 0 1-13.125 0"
479
+ }
480
+ )
481
+ ]
482
+ }
483
+ );
484
+ var Default_default = SvgDefault;
485
+
486
+ // src/icons/theme/Protanopia.tsx
487
+ var import_jsx_runtime8 = require("react/jsx-runtime");
488
+ var SvgProtanopia = (props) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
489
+ "svg",
490
+ {
491
+ xmlns: "http://www.w3.org/2000/svg",
492
+ fill: "none",
493
+ viewBox: "0 0 28 29",
494
+ ...props,
495
+ children: [
496
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
497
+ "rect",
498
+ {
499
+ width: 26.18,
500
+ height: 26.18,
501
+ x: 0.91,
502
+ y: 1.41,
503
+ stroke: "currentColor",
504
+ strokeWidth: 1.82,
505
+ rx: 13.09
506
+ }
507
+ ),
508
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
509
+ "path",
510
+ {
511
+ fill: "currentColor",
512
+ d: "M9.252 7.152h5.045q1.692 0 2.83.585 1.14.575 1.682 1.61.554 1.024.554 2.379 0 1.507-.697 2.594-.688 1.086-2.072 1.569L19.937 22h-2.153l-3.107-5.773-.36.01h-3.219V22H9.252zm4.984 7.404q1.711 0 2.502-.728.8-.729.8-2.102 0-1.395-.8-2.164t-2.523-.769h-3.117v5.763z"
513
+ }
514
+ ),
515
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
516
+ "path",
517
+ {
518
+ stroke: "currentColor",
519
+ strokeWidth: 1.517,
520
+ d: "m3.5 1.666 23.333 23.333"
521
+ }
522
+ )
523
+ ]
524
+ }
525
+ );
526
+ var Protanopia_default = SvgProtanopia;
527
+
528
+ // src/icons/theme/Deuteranopia.tsx
529
+ var import_jsx_runtime9 = require("react/jsx-runtime");
530
+ var SvgDeuteranopia = (props) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
531
+ "svg",
532
+ {
533
+ xmlns: "http://www.w3.org/2000/svg",
534
+ fill: "none",
535
+ viewBox: "0 0 15 15",
536
+ ...props,
537
+ children: [
538
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
539
+ "rect",
540
+ {
541
+ width: 13.09,
542
+ height: 13.09,
543
+ x: 1.08,
544
+ y: 0.955,
545
+ stroke: "currentColor",
546
+ strokeWidth: 0.91,
547
+ rx: 6.545
548
+ }
549
+ ),
550
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
551
+ "path",
552
+ {
553
+ fill: "currentColor",
554
+ d: "M9.51 5.894q-.245-.734-.789-1.144-.538-.415-1.312-.415-.667 0-1.205.343-.534.345-.846 1.01-.308.667-.308 1.6t.313 1.6q.313.665.861 1.01.549.343 1.246.343.626 0 1.103-.261a1.87 1.87 0 0 0 .748-.754q.271-.492.282-1.138H7.665v-.81h2.84v.8q0 .907-.39 1.594-.389.687-1.081 1.061-.687.37-1.564.37-.984 0-1.738-.462-.748-.466-1.164-1.328-.41-.866-.41-2.025 0-1.153.41-2.015.416-.866 1.154-1.333.738-.465 1.687-.466.774 0 1.42.307.646.303 1.071.851.426.548.564 1.262z"
555
+ }
556
+ ),
557
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
558
+ "path",
559
+ {
560
+ stroke: "currentColor",
561
+ strokeWidth: 0.758,
562
+ d: "m2.375 1.082 11.667 11.667"
563
+ }
564
+ )
565
+ ]
566
+ }
567
+ );
568
+ var Deuteranopia_default = SvgDeuteranopia;
569
+
570
+ // src/react/ThemeSwitcherPortal.tsx
571
+ var import_react2 = require("react");
572
+ var import_react_dom = require("react-dom");
573
+ var PORTAL_ID = "theme-switcher-portal";
574
+ var portalEl = null;
575
+ var activeOwner = null;
576
+ function ensurePortal() {
577
+ if (typeof document === "undefined") throw new Error("No document");
578
+ if (portalEl && document.body.contains(portalEl)) return portalEl;
579
+ const existing = document.getElementById(PORTAL_ID);
580
+ portalEl = existing ?? Object.assign(document.createElement("div"), { id: PORTAL_ID });
581
+ if (!existing) document.body.appendChild(portalEl);
582
+ return portalEl;
583
+ }
584
+ function ThemeSwitcherPortal({
585
+ children
586
+ }) {
587
+ const [container, setContainer] = (0, import_react2.useState)(null);
588
+ const ownerId = (0, import_react2.useRef)(Symbol("ThemeSwitcherPortal"));
589
+ (0, import_react2.useEffect)(() => {
590
+ const el = ensurePortal();
591
+ setContainer(el);
592
+ if (activeOwner === null) activeOwner = ownerId.current;
593
+ return () => {
594
+ if (activeOwner === ownerId.current) {
595
+ activeOwner = null;
596
+ }
597
+ };
598
+ }, []);
599
+ if (!container) return null;
600
+ const isPrimary = activeOwner === ownerId.current;
601
+ return (0, import_react_dom.createPortal)(isPrimary ? children : null, container);
602
+ }
603
+
604
+ // src/react/ThemeSwitcher.tsx
605
+ var import_jsx_runtime10 = require("react/jsx-runtime");
606
+ var THEME_ICON = {
607
+ default: Default_default,
608
+ protanopia: Protanopia_default,
609
+ deuteranopia: Deuteranopia_default,
610
+ tritanopia: Tritanopia_default
611
+ };
612
+ function ThemeSwitcher({ options }) {
613
+ const { theme, updateTheme, language, updateLanguage } = useTheme();
614
+ const [hovered, setHovered] = (0, import_react3.useState)(null);
615
+ const list = (0, import_react3.useMemo)(
616
+ () => options?.length ? options : getThemeOptions(language),
617
+ [options, language]
618
+ );
619
+ const [isOpen, setIsOpen] = (0, import_react3.useState)(false);
620
+ const wrapperRef = (0, import_react3.useRef)(null);
621
+ (0, import_react3.useEffect)(() => {
622
+ const handleClickOutside = (event) => {
623
+ if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
624
+ setIsOpen(false);
625
+ }
626
+ };
627
+ document.addEventListener("mousedown", handleClickOutside);
628
+ return () => document.removeEventListener("mousedown", handleClickOutside);
629
+ }, []);
630
+ const toggle = (e) => {
631
+ e.stopPropagation();
632
+ setIsOpen((prev) => !prev);
633
+ };
634
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ThemeSwitcherPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref: wrapperRef, className: "z-[10000]", children: [
635
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
636
+ "button",
637
+ {
638
+ type: "button",
639
+ "aria-haspopup": "menu",
640
+ "aria-expanded": isOpen,
641
+ onClick: toggle,
642
+ className: "fixed right-[25px] bottom-[25px] w-[60px] h-[60px] p-[10px] bg-[#ffffff] rounded-full flex justify-center items-center shadow-[0_0_3px_0_rgba(0,0,0,0.17)]",
643
+ children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(X_default, { className: "self-center" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Logo_default, { className: "self-center" })
644
+ }
645
+ ),
646
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
647
+ "div",
648
+ {
649
+ role: "menu",
650
+ "aria-label": "Select theme",
651
+ className: "fixed bottom-[100px] right-[25px] flex-col bg-[#ffffff] rounded-[18px] w-[220px] gap-[11px]",
652
+ children: [
653
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { children: list.map((opt) => {
654
+ const Icon = THEME_ICON[opt.key];
655
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
656
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
657
+ "button",
658
+ {
659
+ type: "button",
660
+ role: "menuitemradio",
661
+ "aria-checked": theme === opt.key,
662
+ onClick: (e) => {
663
+ e.stopPropagation();
664
+ updateTheme(opt.key);
665
+ },
666
+ onMouseEnter: () => setHovered(opt.key),
667
+ onMouseLeave: () => setHovered(null),
668
+ className: [
669
+ "hover:cursor-pointer group text-[18px] text-[#3D4852] py-1 w-full h-[50px] text-center gap-[8px] flex items-center justify-center rounded-[18px] hover:bg-[#3D4852]",
670
+ theme === opt.key ? "bg-[#3D4852] text-[#ffffff]" : ""
671
+ ].join(" "),
672
+ children: [
673
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
674
+ Icon,
675
+ {
676
+ width: 24,
677
+ height: 24,
678
+ className: `inline-block ${theme === opt.key || hovered === opt.key ? "text-white" : "text-[#3D4852]"}`
679
+ }
680
+ ),
681
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "group-hover:text-[#ffffff]", children: opt.label })
682
+ ]
683
+ },
684
+ opt.key
685
+ ),
686
+ opt.key !== "tritanopia" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "border-b-[0.5px] border-b-[#D9D9D9] w-full" })
687
+ ] }, opt.key);
688
+ }) }),
689
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-full border-[0.5px] border-[#B8B8B8]" }),
690
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex justify-evenly items-center gap-[10px] px-[10px] my-[15px]", children: language === "English" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
691
+ "div",
692
+ {
693
+ className: `hover:cursor-pointer flex text-[18px] text-[#3D4852] gap-[8px] items-center justify-center`,
694
+ onClick: () => updateLanguage("Korean"),
695
+ children: [
696
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Us_default, {}),
697
+ "English"
698
+ ]
699
+ }
700
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
701
+ "div",
702
+ {
703
+ className: `hover:cursor-pointer flex text-[18px] text-[#3D4852] gap-[8px] items-center justify-center `,
704
+ onClick: () => updateLanguage("English"),
705
+ children: [
706
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Kr_default, {}),
707
+ "Korean"
708
+ ]
709
+ }
710
+ ) })
711
+ ]
712
+ }
713
+ )
714
+ ] }) });
715
+ }
@@ -0,0 +1,29 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ type TLanguage = 'English' | 'Korean';
5
+ declare const THEME_KEYS: readonly ["default", "protanopia", "deuteranopia", "tritanopia"];
6
+ type ThemeKey = (typeof THEME_KEYS)[number];
7
+ type ThemeContextType = {
8
+ theme: ThemeKey;
9
+ language: TLanguage;
10
+ updateTheme: (k: ThemeKey) => void;
11
+ updateLanguage: (t: TLanguage) => void;
12
+ };
13
+ declare const useTheme: () => ThemeContextType;
14
+ type ThemeProviderProps = {
15
+ children: ReactNode;
16
+ };
17
+ declare function ThemeProvider({ children }: ThemeProviderProps): react_jsx_runtime.JSX.Element;
18
+ type ThemeType = ThemeKey;
19
+ declare const THEMES: Record<TLanguage, Record<"default" | "protanopia" | "deuteranopia" | "tritanopia", string>>;
20
+
21
+ type Props = {
22
+ options?: {
23
+ key: ThemeKey;
24
+ label: string;
25
+ }[];
26
+ };
27
+ declare function ThemeSwitcher({ options }: Props): react_jsx_runtime.JSX.Element;
28
+
29
+ export { THEMES, type TLanguage, ThemeProvider, ThemeSwitcher, type ThemeType, useTheme };
package/dist/client.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
2
3
 
3
4
  type TLanguage = 'English' | 'Korean';
4
5
  declare const THEME_KEYS: readonly ["default", "protanopia", "deuteranopia", "tritanopia"];
@@ -10,9 +11,10 @@ type ThemeContextType = {
10
11
  updateLanguage: (t: TLanguage) => void;
11
12
  };
12
13
  declare const useTheme: () => ThemeContextType;
13
- declare function ThemeProvider({ children }: {
14
- children: React.ReactNode;
15
- }): react_jsx_runtime.JSX.Element;
14
+ type ThemeProviderProps = {
15
+ children: ReactNode;
16
+ };
17
+ declare function ThemeProvider({ children }: ThemeProviderProps): react_jsx_runtime.JSX.Element;
16
18
  type ThemeType = ThemeKey;
17
19
  declare const THEMES: Record<TLanguage, Record<"default" | "protanopia" | "deuteranopia" | "tritanopia", string>>;
18
20
 
@@ -21,8 +23,7 @@ type Props = {
21
23
  key: ThemeKey;
22
24
  label: string;
23
25
  }[];
24
- className?: string;
25
26
  };
26
- declare function ThemeSwitcher({ options, className }: Props): react_jsx_runtime.JSX.Element;
27
+ declare function ThemeSwitcher({ options }: Props): react_jsx_runtime.JSX.Element;
27
28
 
28
29
  export { THEMES, type TLanguage, ThemeProvider, ThemeSwitcher, type ThemeType, useTheme };
package/dist/client.js CHANGED
@@ -1,7 +1,13 @@
1
1
  "use client";
2
2
 
3
- // src/components/ThemeProvider.tsx
4
- import { createContext, useContext, useEffect, useMemo, useState } from "react";
3
+ // src/react/ThemeProvider.tsx
4
+ import {
5
+ createContext,
6
+ useContext,
7
+ useEffect,
8
+ useMemo,
9
+ useState
10
+ } from "react";
5
11
  import { jsx } from "react/jsx-runtime";
6
12
  var THEME_KEYS = [
7
13
  "default",
@@ -81,7 +87,7 @@ function ThemeProvider({ children }) {
81
87
  }
82
88
  var THEMES = THEME_LABEL;
83
89
 
84
- // src/components/ThemeSwitcher.tsx
90
+ // src/react/ThemeSwitcher.tsx
85
91
  import { useEffect as useEffect3, useRef as useRef2, useState as useState3, useMemo as useMemo2 } from "react";
86
92
 
87
93
  // src/icons/Logo.tsx
@@ -539,7 +545,7 @@ var SvgDeuteranopia = (props) => /* @__PURE__ */ jsxs8(
539
545
  );
540
546
  var Deuteranopia_default = SvgDeuteranopia;
541
547
 
542
- // src/components/ThemeSwitcherPortal.tsx
548
+ // src/react/ThemeSwitcherPortal.tsx
543
549
  import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
544
550
  import { createPortal } from "react-dom";
545
551
  var PORTAL_ID = "theme-switcher-portal";
@@ -573,7 +579,7 @@ function ThemeSwitcherPortal({
573
579
  return createPortal(isPrimary ? children : null, container);
574
580
  }
575
581
 
576
- // src/components/ThemeSwitcher.tsx
582
+ // src/react/ThemeSwitcher.tsx
577
583
  import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
578
584
  var THEME_ICON = {
579
585
  default: Default_default,
@@ -581,7 +587,7 @@ var THEME_ICON = {
581
587
  deuteranopia: Deuteranopia_default,
582
588
  tritanopia: Tritanopia_default
583
589
  };
584
- function ThemeSwitcher({ options, className }) {
590
+ function ThemeSwitcher({ options }) {
585
591
  const { theme, updateTheme, language, updateLanguage } = useTheme();
586
592
  const [hovered, setHovered] = useState3(null);
587
593
  const list = useMemo2(
package/dist/styles.css CHANGED
@@ -1,2 +1 @@
1
- /*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-white:#fff;--spacing:.25rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.fixed{position:fixed}.right-\[25px\]{right:25px}.bottom-\[25px\]{bottom:25px}.bottom-\[100px\]{bottom:100px}.z-\[10000\]{z-index:10000}.my-\[15px\]{margin-block:15px}.block{display:block}.contents{display:contents}.flex{display:flex}.inline{display:inline}.inline-block{display:inline-block}.h-\[50px\]{height:50px}.h-\[60px\]{height:60px}.w-\[60px\]{width:60px}.w-\[220px\]{width:220px}.w-full{width:100%}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-evenly{justify-content:space-evenly}.gap-\[8px\]{gap:8px}.gap-\[10px\]{gap:10px}.gap-\[11px\]{gap:11px}.self-center{align-self:center}.rounded-\[18px\]{border-radius:18px}.rounded-full{border-radius:3.40282e38px}.border-\[0\.5px\]{border-style:var(--tw-border-style);border-width:.5px}.border-b-\[0\.5px\]{border-bottom-style:var(--tw-border-style);border-bottom-width:.5px}.border-\[\#B8B8B8\]{border-color:#b8b8b8}.border-b-\[\#D9D9D9\]{border-bottom-color:#d9d9d9}.bg-\[\#3D4852\]{background-color:#3d4852}.bg-\[\#ffffff\]{background-color:#fff}.p-\[10px\]{padding:10px}.px-\[10px\]{padding-inline:10px}.py-1{padding-block:calc(var(--spacing)*1)}.text-center{text-align:center}.text-\[18px\]{font-size:18px}.text-\[\#3D4852\]{color:#3d4852}.text-\[\#ffffff\]{color:#fff}.text-white{color:var(--color-white)}.shadow-\[0_0_3px_0_rgba\(0\,0\,0\,0\.17\)\]{--tw-shadow:0 0 3px 0 var(--tw-shadow-color,#0000002b);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}@media (hover:hover){.group-hover\:text-\[\#ffffff\]:is(:where(.group):hover *){color:#fff}.hover\:cursor-pointer:hover{cursor:pointer}.hover\:bg-\[\#3D4852\]:hover{background-color:#3d4852}}}svg rect{fill:none!important}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
1
+ @source "./src/**/*.{js,ts,jsx,tsx}";svg rect{fill:none!important}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "colbrush",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "A React theme switching library that makes it easy to apply color-blind accessible UI themes",
5
5
  "homepage": "https://colbrush.vercel.app",
6
6
  "repository": {
@@ -75,6 +75,7 @@
75
75
  "svgr": "svgr src/assets --out-dir src/icons --typescript --expand-props end --svgo-config svgo.config.js",
76
76
  "build:css": "tailwindcss -i ./src/styles.css -o ./dist/styles.css --minify",
77
77
  "build": "pnpm svgr && tsup --config tsup.config.ts && pnpm build:css",
78
- "dev": "tsup --config tsup.config.ts --watch"
78
+ "dev": "tsup --config tsup.config.ts --watch",
79
+ "lint": "eslint ."
79
80
  }
80
81
  }