@jirawatpyk/aura-react 4.5.1 → 4.6.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.
@@ -0,0 +1,106 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { useStrings } from "./locale.js";
4
+ import { IconButton } from "./IconButton.js";
5
+ import { DropdownMenu } from "./DropdownMenu.js";
6
+ const DEFAULT_KEY = "aura-color-scheme";
7
+ const SCHEMES = ["light", "dark", "system"];
8
+ const EVENT = "aura-color-scheme";
9
+ function valid(v) {
10
+ return typeof v === "string" && SCHEMES.indexOf(v) >= 0;
11
+ }
12
+ function colorSchemeScript(options) {
13
+ const key = JSON.stringify(options && options.storageKey || DEFAULT_KEY);
14
+ const fallback = JSON.stringify(options && options.defaultScheme || "system");
15
+ return "(function(){try{var s=localStorage.getItem(" + key + ");if(s!=='light'&&s!=='dark'&&s!=='system')s=" + fallback + `;var d=document.documentElement;d.setAttribute("data-theme",s);var dark=s==='dark'||(s==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);d.classList.toggle("dark",dark);}catch(e){}})();`;
16
+ }
17
+ function ColorSchemeScript(props) {
18
+ return /* @__PURE__ */ React.createElement("script", { "data-aura-color-scheme": "", dangerouslySetInnerHTML: { __html: colorSchemeScript(props) } });
19
+ }
20
+ function systemDark() {
21
+ return typeof window !== "undefined" && !!window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
22
+ }
23
+ function readScheme(fallback) {
24
+ if (typeof document === "undefined") return fallback;
25
+ const attr = document.documentElement.getAttribute("data-theme");
26
+ return valid(attr) ? attr : fallback;
27
+ }
28
+ function apply(scheme) {
29
+ const d = document.documentElement;
30
+ d.setAttribute("data-theme", scheme);
31
+ d.classList.toggle("dark", scheme === "dark" || scheme === "system" && systemDark());
32
+ }
33
+ function useColorScheme(options) {
34
+ const key = options && options.storageKey || DEFAULT_KEY;
35
+ const fallback = options && options.defaultScheme || "system";
36
+ const subscribe = React.useCallback(
37
+ function(cb) {
38
+ const mq = window.matchMedia ? window.matchMedia("(prefers-color-scheme: dark)") : null;
39
+ function onSystem() {
40
+ if (readScheme(fallback) === "system") apply("system");
41
+ cb();
42
+ }
43
+ if (mq) mq.addEventListener("change", onSystem);
44
+ window.addEventListener(EVENT, cb);
45
+ window.addEventListener("storage", cb);
46
+ return function() {
47
+ if (mq) mq.removeEventListener("change", onSystem);
48
+ window.removeEventListener(EVENT, cb);
49
+ window.removeEventListener("storage", cb);
50
+ };
51
+ },
52
+ [fallback]
53
+ );
54
+ const snapshot = React.useSyncExternalStore(
55
+ subscribe,
56
+ function() {
57
+ const s = readScheme(fallback);
58
+ return s + "|" + (s === "dark" || s === "system" && systemDark() ? "dark" : "light");
59
+ },
60
+ function() {
61
+ return fallback + "|light";
62
+ }
63
+ );
64
+ const parts = snapshot.split("|");
65
+ const setScheme = React.useCallback(
66
+ function(next) {
67
+ if (!valid(next)) return;
68
+ try {
69
+ localStorage.setItem(key, next);
70
+ } catch (e) {
71
+ }
72
+ apply(next);
73
+ window.dispatchEvent(new Event(EVENT));
74
+ },
75
+ [key]
76
+ );
77
+ return { scheme: parts[0], resolved: parts[1], setScheme };
78
+ }
79
+ function ColorSchemeToggle(props) {
80
+ const t = useStrings();
81
+ const cs = useColorScheme(props);
82
+ const names = { light: t.schemeLight, dark: t.schemeDark, system: t.schemeSystem };
83
+ const label = props.label || t.colorScheme;
84
+ return /* @__PURE__ */ React.createElement(
85
+ DropdownMenu,
86
+ {
87
+ label,
88
+ trigger: /* @__PURE__ */ React.createElement(IconButton, { icon: cs.resolved === "dark" ? "moon" : "sun", label: label + ": " + names[cs.scheme] }),
89
+ items: SCHEMES.map(function(s) {
90
+ return {
91
+ label: names[s],
92
+ checked: cs.scheme === s,
93
+ onSelect: function() {
94
+ cs.setScheme(s);
95
+ }
96
+ };
97
+ })
98
+ }
99
+ );
100
+ }
101
+ export {
102
+ ColorSchemeScript,
103
+ ColorSchemeToggle,
104
+ colorSchemeScript,
105
+ useColorScheme
106
+ };
package/dist/esm/index.js CHANGED
@@ -21,6 +21,7 @@ import { TimePicker, parseTime } from "./TimePicker.js";
21
21
  import { FileUpload, formatBytes } from "./FileUpload.js";
22
22
  import { createTheme, contrast, scale } from "./theme.js";
23
23
  import { ThemeStyle } from "./ThemeStyle.js";
24
+ import { ColorSchemeScript, ColorSchemeToggle, colorSchemeScript, useColorScheme } from "./colorScheme.js";
24
25
  import { Badge, Tag, Progress, Skeleton, EmptyState, Pagination, Accordion, Popover } from "./extra.js";
25
26
  export {
26
27
  Accordion,
@@ -34,6 +35,8 @@ export {
34
35
  Calendar,
35
36
  Card,
36
37
  Checkbox,
38
+ ColorSchemeScript,
39
+ ColorSchemeToggle,
37
40
  Combobox,
38
41
  Container,
39
42
  DataTable,
@@ -73,6 +76,7 @@ export {
73
76
  Tooltip,
74
77
  scale as brandScale,
75
78
  breakpoints,
79
+ colorSchemeScript,
76
80
  defaultFilter as comboboxFilter,
77
81
  contrast,
78
82
  createTheme,
@@ -85,5 +89,6 @@ export {
85
89
  toast,
86
90
  useAuraLocale,
87
91
  useBreakpoint,
92
+ useColorScheme,
88
93
  useResponsive
89
94
  };
@@ -82,6 +82,10 @@ const STRINGS = {
82
82
  tooManyFiles: function(n2) {
83
83
  return "Up to " + n2 + " files";
84
84
  },
85
+ colorScheme: "Colour scheme",
86
+ schemeLight: "Light",
87
+ schemeDark: "Dark",
88
+ schemeSystem: "System",
85
89
  uploading: "Uploading\u2026",
86
90
  images: "Images",
87
91
  pagination: "Pagination",
@@ -170,6 +174,10 @@ const STRINGS = {
170
174
  tooManyFiles: function(n2) {
171
175
  return "\u0E41\u0E19\u0E1A\u0E44\u0E14\u0E49\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 " + n2 + " \u0E44\u0E1F\u0E25\u0E4C";
172
176
  },
177
+ colorScheme: "\u0E42\u0E2B\u0E21\u0E14\u0E2A\u0E35",
178
+ schemeLight: "\u0E2A\u0E27\u0E48\u0E32\u0E07",
179
+ schemeDark: "\u0E21\u0E37\u0E14",
180
+ schemeSystem: "\u0E15\u0E32\u0E21\u0E23\u0E30\u0E1A\u0E1A",
173
181
  uploading: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E2D\u0E31\u0E1B\u0E42\u0E2B\u0E25\u0E14\u2026",
174
182
  images: "\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E",
175
183
  pagination: "\u0E40\u0E25\u0E02\u0E2B\u0E19\u0E49\u0E32",
package/dist/esm/theme.js CHANGED
@@ -211,12 +211,13 @@ function createTheme(opts) {
211
211
  function css(selector) {
212
212
  const light = selector ? selector : ':root, [data-theme="light"]';
213
213
  const dark = selector ? selector + ".dark, .dark " + selector + ", " + selector + '[data-theme="dark"], [data-theme="dark"] ' + selector : '.dark, [data-theme="dark"]';
214
+ const system = selector ? '[data-theme="system"] ' + selector + ", " + selector + '[data-theme="system"]' : '[data-theme="system"]';
214
215
  function block(sel, m) {
215
216
  return sel + " {\n" + Object.keys(m).map(function(k) {
216
217
  return " --aura-" + k + ": " + m[k] + ";";
217
218
  }).join("\n") + "\n}";
218
219
  }
219
- return "/* AURA theme" + (o.name ? ' "' + o.name + '"' : "") + ": brand " + o.brand + (o.signal ? ", signal " + o.signal : "") + (o.primary === "brand" ? ", brand primary buttons" : "") + ". Load after aura.css. Generated by createTheme. */\n" + block(light, L) + "\n" + block(dark, D) + "\n";
220
+ return "/* AURA theme" + (o.name ? ' "' + o.name + '"' : "") + ": brand " + o.brand + (o.signal ? ", signal " + o.signal : "") + (o.primary === "brand" ? ", brand primary buttons" : "") + ". Load after aura.css. Generated by createTheme. */\n" + block(light, L) + "\n" + block(dark, D) + "\n@media (prefers-color-scheme: dark) {\n" + block(system, D) + "\n}\n";
220
221
  }
221
222
  return {
222
223
  name: o.name || null,
package/dist/index.d.ts CHANGED
@@ -117,7 +117,7 @@ export interface DataTableProps {
117
117
  stackBelow?: number;
118
118
  className?: string;
119
119
  }
120
- export type IconName = "check" | "x" | "plus" | "minus" | "search" | "chevron-down" | "chevron-up" | "chevron-left" | "chevron-right" | "arrow-right" | "arrow-up-right" | "arrow-up-down" | "loader-circle" | "circle-alert" | "circle-check" | "info" | "triangle-alert" | "settings" | "user" | "users" | "filter" | "ellipsis" | "external-link" | "copy" | "trash-2" | "pencil" | "download" | "upload" | "calendar" | "bell" | "menu" | "eye" | "log-out" | "circle" | "circle-dot-dashed" | "ban" | "arrow-up" | "arrow-down" | "inbox" | "pin" | "pin-off" | "eye-off" | "columns-3" | "arrow-left" | "rotate-ccw" | "house" | "layout-dashboard" | "folder" | "chart-column" | "file-text" | "mail" | "lock" | "clock" | "trending-up" | "trending-down" | "image" | "paperclip" | "cloud-upload" | "file";
120
+ export type IconName = "check" | "x" | "plus" | "minus" | "search" | "chevron-down" | "chevron-up" | "chevron-left" | "chevron-right" | "arrow-right" | "arrow-up-right" | "arrow-up-down" | "loader-circle" | "circle-alert" | "circle-check" | "info" | "triangle-alert" | "settings" | "user" | "users" | "filter" | "ellipsis" | "external-link" | "copy" | "trash-2" | "pencil" | "download" | "upload" | "calendar" | "bell" | "menu" | "eye" | "log-out" | "circle" | "circle-dot-dashed" | "ban" | "arrow-up" | "arrow-down" | "inbox" | "pin" | "pin-off" | "eye-off" | "columns-3" | "arrow-left" | "rotate-ccw" | "house" | "layout-dashboard" | "folder" | "chart-column" | "file-text" | "mail" | "lock" | "clock" | "trending-up" | "trending-down" | "image" | "paperclip" | "cloud-upload" | "file" | "sun" | "moon" | "monitor";
121
121
  /** Lucide stroke icon drawn inline in currentColor. */
122
122
  export interface IconProps {
123
123
  name: IconName;
@@ -929,6 +929,10 @@ export interface AuraStrings {
929
929
  fileTooBig: (max?: number | string) => string;
930
930
  fileWrongType: string;
931
931
  tooManyFiles: (n: number | string) => string;
932
+ colorScheme: string;
933
+ schemeLight: string;
934
+ schemeDark: string;
935
+ schemeSystem: string;
932
936
  uploading: string;
933
937
  images: string;
934
938
  pagination: string;
@@ -970,6 +974,32 @@ export interface ThemeStyleProps extends ThemeOptions {
970
974
  selector?: string;
971
975
  }
972
976
  export declare function ThemeStyle(props: ThemeStyleProps): React$1.ReactElement;
977
+ /** `system` follows the operating system and changes with it. */
978
+ export type ColorScheme = "light" | "dark" | "system";
979
+ export interface ColorSchemeOptions {
980
+ /** localStorage key for the choice. Default `aura-color-scheme`. */
981
+ storageKey?: string;
982
+ /** Used when nothing is saved. Default `system`. */
983
+ defaultScheme?: ColorScheme;
984
+ }
985
+ /** The script ColorSchemeScript renders, as a string — for frameworks that want it in a raw <head> template. */
986
+ export declare function colorSchemeScript(options?: ColorSchemeOptions): string;
987
+ /** Put in <head>: applies the saved colour scheme before the page paints. Server-rendering safe. */
988
+ export declare function ColorSchemeScript(props: ColorSchemeOptions): React$1.ReactElement;
989
+ /** Current colour scheme and a setter. `resolved` is what is on screen (system resolved to light or dark). */
990
+ export interface ColorSchemeState {
991
+ scheme: ColorScheme;
992
+ resolved: "light" | "dark";
993
+ setScheme: (scheme: ColorScheme) => void;
994
+ }
995
+ /** Read and change the colour scheme. Every component using it stays in sync, and `system` follows OS changes. */
996
+ export declare function useColorScheme(options?: ColorSchemeOptions): ColorSchemeState;
997
+ export interface ColorSchemeToggleProps extends ColorSchemeOptions {
998
+ /** Accessible name of the button. Default: the built-in "Colour scheme" label. */
999
+ label?: string;
1000
+ }
1001
+ /** Icon button with a menu: Light, Dark, System. Shows a sun or a moon for what is on screen. */
1002
+ export declare function ColorSchemeToggle(props: ColorSchemeToggleProps): React$1.ReactElement;
973
1003
  export declare const Badge: React$1.ForwardRefExoticComponent<BadgeProps & React$1.RefAttributes<HTMLSpanElement>>;
974
1004
  export declare const Tag: React$1.ForwardRefExoticComponent<TagProps & React$1.RefAttributes<HTMLElement>>;
975
1005
  export declare const Progress: React$1.ForwardRefExoticComponent<ProgressProps & React$1.RefAttributes<HTMLDivElement>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "4.5.1",
3
+ "version": "4.6.0",
4
4
  "description": "AURA Design System — React components (Enterprise Standard, Human Creative). Thai-first: Buddhist-era dates, Thai collation.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,7 +37,8 @@
37
37
  "prepack": "npm run build",
38
38
  "pretest:ssr": "node scripts/build.mjs",
39
39
  "prethemes": "node scripts/build.mjs",
40
- "test:hydrate": "node scripts/hydrate-test.mjs"
40
+ "test:hydrate": "node scripts/hydrate-test.mjs",
41
+ "size": "node scripts/size-check.mjs"
41
42
  },
42
43
  "peerDependencies": {
43
44
  "react": ">=18",