@q9labsai/chalk-ui 4.0.1 → 4.1.1

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/dist/styles.css CHANGED
@@ -33,6 +33,14 @@
33
33
  --color-border: var(--border);
34
34
  --color-input: var(--input);
35
35
  --color-ring: var(--ring);
36
+ --color-sidebar: var(--sidebar);
37
+ --color-sidebar-foreground: var(--sidebar-foreground);
38
+ --color-sidebar-primary: var(--sidebar-primary);
39
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
40
+ --color-sidebar-accent: var(--sidebar-accent);
41
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
42
+ --color-sidebar-border: var(--sidebar-border);
43
+ --color-sidebar-ring: var(--sidebar-ring);
36
44
  --radius-sm: calc(var(--radius) - 4px);
37
45
  --radius-md: calc(var(--radius) - 2px);
38
46
  --radius-lg: var(--radius);
@@ -70,6 +78,19 @@
70
78
  --ring: #0f1115;
71
79
  --radius: 0.5rem;
72
80
 
81
+ /* Sidebar: a chalkboard slate that anchors the paper canvas beside it. */
82
+ --sidebar: #171a18;
83
+ --sidebar-foreground: #b9c0ba;
84
+ --sidebar-primary: #f7f6f2;
85
+ --sidebar-primary-foreground: #121512;
86
+ --sidebar-accent: #2b302c;
87
+ --sidebar-accent-foreground: #ffffff;
88
+ --sidebar-border: #2c312d;
89
+ --sidebar-ring: #8fbf87;
90
+ --sidebar-width: 16rem;
91
+ --sidebar-width-icon: 3.25rem;
92
+ --sidebar-width-mobile: 18rem;
93
+
73
94
  --chalk-paper: #ffffff;
74
95
  --chalk-ink: #0f1115;
75
96
  --chalk-ink-2: #4b5563;
@@ -394,6 +415,14 @@
394
415
  --border: #313a3f;
395
416
  --input: #3d484e;
396
417
  --ring: #ffffff;
418
+ --sidebar: #121719;
419
+ --sidebar-foreground: #a4b0b5;
420
+ --sidebar-primary: #dde3e6;
421
+ --sidebar-primary-foreground: #0f1115;
422
+ --sidebar-accent: #232a2e;
423
+ --sidebar-accent-foreground: #ffffff;
424
+ --sidebar-border: #232a2e;
425
+ --sidebar-ring: #8fbf87;
397
426
  --chalk-paper: #1b2023;
398
427
  --chalk-ink: #dde3e6;
399
428
  --chalk-ink-2: #8b979d;
@@ -634,6 +663,36 @@
634
663
  --chalk-app-shadow-control: 0 6px 18px rgba(0, 0, 0, 0.7);
635
664
  }
636
665
 
666
+ [data-chalk][data-chalk-palette="cosmic-chalk"] {
667
+ --chalk-app-canvas: #080f20;
668
+ --chalk-app-chrome: #10182b;
669
+ --chalk-app-stage: #0b1427;
670
+ --chalk-app-panel: #10182b;
671
+ --chalk-app-tile-base: #10182b;
672
+ --chalk-app-tile-color-strength: 18%;
673
+ --chalk-app-text: #f4ecd7;
674
+ --chalk-app-text-muted: #aeb8c9;
675
+ --chalk-app-line: #2c3d59;
676
+ --chalk-app-line-strong: #415571;
677
+ --chalk-app-control: #121e34;
678
+ --chalk-app-control-hover: #192944;
679
+ --chalk-app-control-group: #0c162a;
680
+ --chalk-app-control-primary: #1b3953;
681
+ --chalk-app-control-primary-hover: #244b68;
682
+ --chalk-app-control-active: #172b45;
683
+ --chalk-app-control-active-line: #8fdcff;
684
+ --chalk-app-control-active-text: #f4ecd7;
685
+ --chalk-app-message-remote: #17243c;
686
+ --chalk-app-message-local: #1b3953;
687
+ --chalk-app-message-local-text: #f4ecd7;
688
+ --chalk-app-input: #0c1629;
689
+ --chalk-app-danger: #ff9ba8;
690
+ --chalk-app-danger-hover: #ffb4be;
691
+ --chalk-app-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.32);
692
+ --chalk-app-shadow-sm: 0 12px 36px rgba(0, 0, 0, 0.34);
693
+ --chalk-app-shadow-control: 0 7px 22px rgba(0, 0, 0, 0.42);
694
+ }
695
+
637
696
  [data-chalk][data-chalk-palette] {
638
697
  --background: var(--chalk-app-canvas);
639
698
  --foreground: var(--chalk-app-text);
@@ -687,67 +746,111 @@
687
746
  background-color: color-mix(in srgb, var(--chalk-participant-color) var(--chalk-app-tile-color-strength), var(--chalk-app-tile-base));
688
747
  }
689
748
 
690
- /* =============================================================================
691
- Base Styles & Scoped Reset
692
- ============================================================================= */
693
-
694
- :where([data-chalk], .chalk-root) {
695
- font-family: var(--chalk-font-family);
696
- color: var(--foreground);
697
- background: var(--background);
698
- line-height: 1.5;
699
- font-size: 16px;
700
- text-align: left;
701
- text-transform: none;
702
- letter-spacing: normal;
703
- text-size-adjust: 100%;
704
- -webkit-font-smoothing: antialiased;
705
- -moz-osx-font-smoothing: grayscale;
706
- isolation: isolate;
749
+ [data-chalk][data-chalk-skin="chalk"][data-chalk-palette="cosmic-chalk"] :where(button, a, input, select, textarea, [tabindex]):focus-visible {
750
+ outline: 2px dashed var(--chalk-focus, #8fdcff);
751
+ outline-offset: 2px;
707
752
  }
708
753
 
709
- :where([data-chalk], .chalk-root),
710
- :where([data-chalk], .chalk-root) *,
711
- :where([data-chalk], .chalk-root) *::before,
712
- :where([data-chalk], .chalk-root) *::after {
713
- box-sizing: border-box;
754
+ main[data-chalk][data-chalk-skin="chalk"][data-chalk-palette="cosmic-chalk"]::before,
755
+ main[data-chalk][data-chalk-skin="chalk"][data-chalk-palette="cosmic-chalk"]::after {
756
+ content: "";
757
+ position: absolute;
758
+ pointer-events: none;
759
+ z-index: 0;
714
760
  }
715
761
 
716
- :where([data-chalk], .chalk-root) :where(h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd) {
717
- margin: 0;
762
+ main[data-chalk][data-chalk-skin="chalk"][data-chalk-palette="cosmic-chalk"]::before {
763
+ inset: 0;
764
+ opacity: 0.28;
765
+ background: radial-gradient(circle at 12% 18%, #8fdcff 0 1px, transparent 1.7px), radial-gradient(circle at 76% 13%, #f5d88c 0 1px, transparent 1.7px), radial-gradient(circle at 88% 72%, #8fdcff 0 1px, transparent 1.7px), radial-gradient(circle at 22% 84%, #f4ecd7 0 1px, transparent 1.7px);
718
766
  }
719
767
 
720
- :where([data-chalk], .chalk-root) :where(ul, ol) {
721
- margin: 0;
722
- padding: 0;
723
- list-style: none;
768
+ main[data-chalk][data-chalk-skin="chalk"][data-chalk-palette="cosmic-chalk"]::after {
769
+ inset: 9% 7%;
770
+ opacity: 0.14;
771
+ background: linear-gradient(24deg, transparent 0 49.4%, #8fdcff 49.6% 49.9%, transparent 50.1%), linear-gradient(156deg, transparent 0 49.6%, #f5d88c 49.8% 50%, transparent 50.2%);
724
772
  }
725
773
 
726
- :where([data-chalk], .chalk-root) :where(button, input, optgroup, select, textarea) {
727
- font: inherit;
728
- color: inherit;
729
- letter-spacing: inherit;
730
- text-transform: none;
731
- margin: 0;
774
+ main[data-chalk][data-chalk-skin="chalk"][data-chalk-palette="cosmic-chalk"] > * {
775
+ position: relative;
776
+ z-index: 1;
732
777
  }
733
778
 
734
- :where([data-chalk], .chalk-root) :where(button, [type="button"], [type="reset"], [type="submit"]) {
735
- appearance: none;
736
- -webkit-appearance: none;
779
+ @media (prefers-reduced-motion: reduce) {
780
+ main[data-chalk][data-chalk-skin="chalk"][data-chalk-palette="cosmic-chalk"]::before,
781
+ main[data-chalk][data-chalk-skin="chalk"][data-chalk-palette="cosmic-chalk"]::after {
782
+ opacity: 0.18;
783
+ }
737
784
  }
738
785
 
739
- :where([data-chalk], .chalk-root) :where(img, svg, video, canvas, audio, iframe, embed, object) {
740
- display: block;
741
- vertical-align: middle;
742
- }
786
+ /* =============================================================================
787
+ Base Styles & Scoped Reset
743
788
 
744
- :where([data-chalk], .chalk-root) :where(img) {
745
- max-width: 100%;
746
- height: auto;
747
- }
789
+ Lives in the `base` layer so that utilities keep beating it. Unlayered, a
790
+ zero-specificity `:where([data-chalk])` reset still outranks every utility,
791
+ which silently strips `bg-*` and `text-*` from any element that opens a
792
+ chalk scope.
793
+ ============================================================================= */
794
+
795
+ @layer base {
796
+ :where([data-chalk], .chalk-root) {
797
+ font-family: var(--chalk-font-family);
798
+ color: var(--foreground);
799
+ background: var(--background);
800
+ line-height: 1.5;
801
+ font-size: 16px;
802
+ text-align: left;
803
+ text-transform: none;
804
+ letter-spacing: normal;
805
+ text-size-adjust: 100%;
806
+ -webkit-font-smoothing: antialiased;
807
+ -moz-osx-font-smoothing: grayscale;
808
+ isolation: isolate;
809
+ }
810
+
811
+ :where([data-chalk], .chalk-root),
812
+ :where([data-chalk], .chalk-root) *,
813
+ :where([data-chalk], .chalk-root) *::before,
814
+ :where([data-chalk], .chalk-root) *::after {
815
+ box-sizing: border-box;
816
+ }
817
+
818
+ :where([data-chalk], .chalk-root) :where(h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd) {
819
+ margin: 0;
820
+ }
821
+
822
+ :where([data-chalk], .chalk-root) :where(ul, ol) {
823
+ margin: 0;
824
+ padding: 0;
825
+ list-style: none;
826
+ }
827
+
828
+ :where([data-chalk], .chalk-root) :where(button, input, optgroup, select, textarea) {
829
+ font: inherit;
830
+ color: inherit;
831
+ letter-spacing: inherit;
832
+ text-transform: none;
833
+ margin: 0;
834
+ }
835
+
836
+ :where([data-chalk], .chalk-root) :where(button, [type="button"], [type="reset"], [type="submit"]) {
837
+ appearance: none;
838
+ -webkit-appearance: none;
839
+ }
840
+
841
+ :where([data-chalk], .chalk-root) :where(img, svg, video, canvas, audio, iframe, embed, object) {
842
+ display: block;
843
+ vertical-align: middle;
844
+ }
845
+
846
+ :where([data-chalk], .chalk-root) :where(img) {
847
+ max-width: 100%;
848
+ height: auto;
849
+ }
748
850
 
749
- :where([data-chalk], .chalk-root) :where(video) {
750
- max-width: 100%;
851
+ :where([data-chalk], .chalk-root) :where(video) {
852
+ max-width: 100%;
853
+ }
751
854
  }
752
855
 
753
856
  /* =============================================================================
package/dist/toast.js CHANGED
@@ -4,6 +4,9 @@
4
4
  import * as React from "react";
5
5
  import { Toast as ToastPrimitive } from "@base-ui/react/toast";
6
6
 
7
+ // src/lib/use-portal-theme.ts
8
+ import { useSyncExternalStore } from "react";
9
+
7
10
  // src/lib/theme.ts
8
11
  var THEME_ATTRIBUTE_NAMES = ["data-chalk-theme", "data-theme"];
9
12
  var THEME_CLASS_NAMES = ["dark", "light"];
@@ -43,6 +46,28 @@ var resolvePortalThemeFromDocument = ({ defaultTheme = "light", allowSystem = tr
43
46
  return resolveThemeFromDocument({ defaultTheme, allowSystem });
44
47
  };
45
48
 
49
+ // src/lib/use-portal-theme.ts
50
+ var SYSTEM_DARK_QUERY2 = "(prefers-color-scheme: dark)";
51
+ var WATCHED_ATTRIBUTES = ["class", "data-chalk-theme", "data-theme"];
52
+ function subscribe(onChange) {
53
+ if (typeof document === "undefined") return () => {
54
+ };
55
+ const observer = new MutationObserver(onChange);
56
+ const options = { attributes: true, attributeFilter: [...WATCHED_ATTRIBUTES] };
57
+ observer.observe(document.documentElement, options);
58
+ if (document.body) observer.observe(document.body, options);
59
+ const media = typeof window.matchMedia === "function" ? window.matchMedia(SYSTEM_DARK_QUERY2) : null;
60
+ media?.addEventListener("change", onChange);
61
+ return () => {
62
+ observer.disconnect();
63
+ media?.removeEventListener("change", onChange);
64
+ };
65
+ }
66
+ function usePortalTheme(defaultTheme = "light") {
67
+ const read = () => resolvePortalThemeFromDocument({ defaultTheme });
68
+ return useSyncExternalStore(subscribe, read, () => defaultTheme);
69
+ }
70
+
46
71
  // src/lib/utils.ts
47
72
  import { clsx } from "clsx";
48
73
  import { twMerge } from "tailwind-merge";
@@ -85,7 +110,7 @@ var ToastAction = React.forwardRef(function ToastAction2({ className, ...props }
85
110
  });
86
111
  function ToastViewport({ className, children, ...props }) {
87
112
  const { toasts } = ToastPrimitive.useToastManager();
88
- const portalTheme = resolvePortalThemeFromDocument();
113
+ const portalTheme = usePortalTheme();
89
114
  return /* @__PURE__ */ jsxs(ToastPrimitive.Viewport, { "data-chalk": true, "data-chalk-theme": portalTheme, "data-slot": "toast-viewport", className: cn("chalk-ui-root chalk-ui-toast-viewport", className), ...props, children: [
90
115
  children,
91
116
  toasts.map((toastObject) => {
package/dist/tooltip.js CHANGED
@@ -11,6 +11,9 @@ function cn(...inputs) {
11
11
  return twMerge(clsx(inputs));
12
12
  }
13
13
 
14
+ // src/lib/use-portal-theme.ts
15
+ import { useSyncExternalStore } from "react";
16
+
14
17
  // src/lib/theme.ts
15
18
  var THEME_ATTRIBUTE_NAMES = ["data-chalk-theme", "data-theme"];
16
19
  var THEME_CLASS_NAMES = ["dark", "light"];
@@ -50,6 +53,28 @@ var resolvePortalThemeFromDocument = ({ defaultTheme = "light", allowSystem = tr
50
53
  return resolveThemeFromDocument({ defaultTheme, allowSystem });
51
54
  };
52
55
 
56
+ // src/lib/use-portal-theme.ts
57
+ var SYSTEM_DARK_QUERY2 = "(prefers-color-scheme: dark)";
58
+ var WATCHED_ATTRIBUTES = ["class", "data-chalk-theme", "data-theme"];
59
+ function subscribe(onChange) {
60
+ if (typeof document === "undefined") return () => {
61
+ };
62
+ const observer = new MutationObserver(onChange);
63
+ const options = { attributes: true, attributeFilter: [...WATCHED_ATTRIBUTES] };
64
+ observer.observe(document.documentElement, options);
65
+ if (document.body) observer.observe(document.body, options);
66
+ const media = typeof window.matchMedia === "function" ? window.matchMedia(SYSTEM_DARK_QUERY2) : null;
67
+ media?.addEventListener("change", onChange);
68
+ return () => {
69
+ observer.disconnect();
70
+ media?.removeEventListener("change", onChange);
71
+ };
72
+ }
73
+ function usePortalTheme(defaultTheme = "light") {
74
+ const read = () => resolvePortalThemeFromDocument({ defaultTheme });
75
+ return useSyncExternalStore(subscribe, read, () => defaultTheme);
76
+ }
77
+
53
78
  // src/tooltip.tsx
54
79
  import { jsx, jsxs } from "react/jsx-runtime";
55
80
  function TooltipProvider({ delay = 0, ...props }) {
@@ -73,7 +98,7 @@ function TooltipTrigger({ ...props }) {
73
98
  return /* @__PURE__ */ jsx(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
74
99
  }
75
100
  function TooltipContent({ className, side = "top", sideOffset = 4, align = "center", alignOffset = 0, children, ...props }) {
76
- const portalTheme = resolvePortalThemeFromDocument();
101
+ const portalTheme = usePortalTheme();
77
102
  return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(TooltipPrimitive.Positioner, { align, alignOffset, side, sideOffset, className: "z-[9999]", children: /* @__PURE__ */ jsxs(
78
103
  TooltipPrimitive.Popup,
79
104
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q9labsai/chalk-ui",
3
- "version": "4.0.1",
3
+ "version": "4.1.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,9 +35,15 @@
35
35
  "input": [
36
36
  "./dist/input.d.ts"
37
37
  ],
38
+ "menu": [
39
+ "./dist/menu.d.ts"
40
+ ],
38
41
  "select": [
39
42
  "./dist/select.d.ts"
40
43
  ],
44
+ "sidebar": [
45
+ "./dist/sidebar.d.ts"
46
+ ],
41
47
  "textarea": [
42
48
  "./dist/textarea.d.ts"
43
49
  ],
@@ -104,10 +110,18 @@
104
110
  "types": "./dist/input.d.ts",
105
111
  "import": "./dist/input.js"
106
112
  },
113
+ "./menu": {
114
+ "types": "./dist/menu.d.ts",
115
+ "import": "./dist/menu.js"
116
+ },
107
117
  "./select": {
108
118
  "types": "./dist/select.d.ts",
109
119
  "import": "./dist/select.js"
110
120
  },
121
+ "./sidebar": {
122
+ "types": "./dist/sidebar.d.ts",
123
+ "import": "./dist/sidebar.js"
124
+ },
111
125
  "./textarea": {
112
126
  "types": "./dist/textarea.d.ts",
113
127
  "import": "./dist/textarea.js"
@@ -165,7 +179,7 @@
165
179
  },
166
180
  "dependencies": {
167
181
  "@base-ui/react": "^1.0.0",
168
- "@q9labsai/chalk-assets": "^4.0.1",
182
+ "@q9labsai/chalk-assets": "^4.1.1",
169
183
  "class-variance-authority": "^0.7.1",
170
184
  "clsx": "^2.1.1",
171
185
  "tailwind-merge": "^3.6.0"
@@ -176,7 +190,7 @@
176
190
  "@types/node": "^24.10.1",
177
191
  "@types/react": "^19.0.0",
178
192
  "@types/react-dom": "^19.2.3",
179
- "happy-dom": "^20.0.11",
193
+ "happy-dom": "^20.11.2",
180
194
  "react-dom": "19.2.7",
181
195
  "tailwindcss": "^4.1.18",
182
196
  "tw-animate-css": "^1.3.0",
@@ -186,11 +200,11 @@
186
200
  "react": "^18.0.0 || ^19.0.0"
187
201
  },
188
202
  "scripts": {
189
- "build": "rm -rf ./dist && tsup ./src/index.ts ./src/assets.ts ./src/badge.tsx ./src/button.tsx ./src/card.tsx ./src/input.tsx ./src/select.tsx ./src/textarea.tsx ./src/spinner.tsx ./src/skeleton.tsx ./src/icon-button.tsx ./src/progress-bar.tsx ./src/lib/utils.ts ./src/reactions.ts ./src/status-badge.tsx ./src/toast.tsx ./src/toggle.tsx ./src/toggle-group.tsx ./src/tooltip.tsx --format esm --out-dir ./dist --platform node --no-splitting --external react --external @base-ui/react --external @q9labsai/chalk-assets --external class-variance-authority --external clsx --external tailwind-merge && pnpm run build:types && pnpm run build:css && pnpm run build:logos",
203
+ "build": "rm -rf ./dist && tsup ./src/index.ts ./src/assets.ts ./src/badge.tsx ./src/button.tsx ./src/card.tsx ./src/input.tsx ./src/menu.tsx ./src/select.tsx ./src/sidebar.tsx ./src/textarea.tsx ./src/spinner.tsx ./src/skeleton.tsx ./src/icon-button.tsx ./src/progress-bar.tsx ./src/lib/utils.ts ./src/reactions.ts ./src/status-badge.tsx ./src/toast.tsx ./src/toggle.tsx ./src/toggle-group.tsx ./src/tooltip.tsx --format esm --out-dir ./dist --platform node --no-splitting --external react --external @base-ui/react --external @q9labsai/chalk-assets --external class-variance-authority --external clsx --external tailwind-merge && pnpm run build:types && pnpm run build:css && pnpm run build:logos",
190
204
  "build:types": "rm -f tsconfig.tsbuildinfo && tsc --emitDeclarationOnly --declaration --outDir dist",
191
205
  "build:css": "mkdir -p ./dist && cp ./src/styles/index.css ./dist/styles.css",
192
206
  "build:logos": "mkdir -p ./dist && cp -R ../assets/src/logos ./dist/",
193
- "dev": "pnpm run build:css && pnpm run build:logos && tsup ./src/index.ts ./src/assets.ts ./src/badge.tsx ./src/button.tsx ./src/card.tsx ./src/input.tsx ./src/select.tsx ./src/textarea.tsx ./src/spinner.tsx ./src/skeleton.tsx ./src/icon-button.tsx ./src/progress-bar.tsx ./src/lib/utils.ts ./src/reactions.ts ./src/status-badge.tsx ./src/toast.tsx ./src/toggle.tsx ./src/toggle-group.tsx ./src/tooltip.tsx --format esm --out-dir ./dist --platform node --no-splitting --external react --external @base-ui/react --external @q9labsai/chalk-assets --external class-variance-authority --external clsx --external tailwind-merge --watch",
207
+ "dev": "pnpm run build:css && pnpm run build:logos && tsup ./src/index.ts ./src/assets.ts ./src/badge.tsx ./src/button.tsx ./src/card.tsx ./src/input.tsx ./src/menu.tsx ./src/select.tsx ./src/sidebar.tsx ./src/textarea.tsx ./src/spinner.tsx ./src/skeleton.tsx ./src/icon-button.tsx ./src/progress-bar.tsx ./src/lib/utils.ts ./src/reactions.ts ./src/status-badge.tsx ./src/toast.tsx ./src/toggle.tsx ./src/toggle-group.tsx ./src/tooltip.tsx --format esm --out-dir ./dist --platform node --no-splitting --external react --external @base-ui/react --external @q9labsai/chalk-assets --external class-variance-authority --external clsx --external tailwind-merge --watch",
194
208
  "test": "pnpm exec vitest run --config ./vitest.config.ts",
195
209
  "check-types": "tsc --project tsconfig.check-types.json --noEmit",
196
210
  "lint": "pnpm exec oxfmt --check . && tsc --project tsconfig.check-types.json --noEmit",