@thesage/ui 0.0.12 → 0.0.13

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
@@ -1,4 +1,4 @@
1
- # Sage UI (@thesage/ui)
1
+ # Sage Design Engine (@thesage/ui)
2
2
 
3
3
  <div align="center">
4
4
 
@@ -14,7 +14,7 @@
14
14
 
15
15
  ---
16
16
 
17
- **Sage UI** is not just a component library—it's a systematic design engine built for speed, consistency, and beauty. Built on top of **Radix UI** for headless accessibility and **Tailwind CSS** for styling, it provides a comprehensive suite of 45+ polished components that work together seamlessly.
17
+ **Sage Design Engine** is not just a component library—it's a systematic design engine built for speed, consistency, and beauty. Built on top of **Radix UI** for headless accessibility and **Tailwind CSS** for styling, it provides a comprehensive suite of 45+ polished components that work together seamlessly.
18
18
 
19
19
  ## ✨ Features
20
20
 
@@ -27,7 +27,7 @@
27
27
  ## 🚀 Installation
28
28
 
29
29
  ### 1. Install Dependencies
30
- Sage UI is built on Tailwind CSS. You need to install the package and its peer dependencies.
30
+ Sage Design Engine is built on Tailwind CSS. You need to install the package and its peer dependencies.
31
31
 
32
32
  ```bash
33
33
  pnpm add @thesage/ui @thesage/tokens @thesage/hooks lucide-react clsx tailwind-merge
@@ -61,7 +61,7 @@ import '@thesage/ui/globals.css';
61
61
 
62
62
  ## 💻 Usage
63
63
 
64
- Sage UI components are designed to be dropped into any React application.
64
+ Sage Design Engine components are designed to be dropped into any React application.
65
65
 
66
66
  ```tsx
67
67
  import { Button, Card, Text, Heading } from '@thesage/ui';
@@ -84,7 +84,7 @@ export default function WelcomeCard() {
84
84
 
85
85
  ## 🖌️ Theming
86
86
 
87
- Sage UI uses a 4-layer token system. Changing a single primary color automatically updates buttons, focus rings, and chart colors across your entire application.
87
+ Sage Design Engine uses a 4-layer token system. Changing a single primary color automatically updates buttons, focus rings, and chart colors across your entire application.
88
88
 
89
89
  ```tsx
90
90
  // Example: Customizing the theme
package/dist/index.d.mts CHANGED
@@ -2207,9 +2207,28 @@ interface OrbBackgroundProps {
2207
2207
  hoverIntensity?: number;
2208
2208
  rotateOnHover?: boolean;
2209
2209
  forceHoverState?: boolean;
2210
+ /**
2211
+ * Background color (hex). If not provided, uses CSS variable --color-background.
2212
+ * @default undefined (reads from theme)
2213
+ */
2210
2214
  backgroundColor?: string;
2215
+ /**
2216
+ * Primary orb color (hex). Creates the main vibrant tone.
2217
+ * @default '#9c43fe' (purple)
2218
+ */
2219
+ orbColor1?: string;
2220
+ /**
2221
+ * Secondary orb color (hex). Adds cool cyan tones.
2222
+ * @default '#4cc2e9' (cyan)
2223
+ */
2224
+ orbColor2?: string;
2225
+ /**
2226
+ * Tertiary orb color (hex). Provides deep blue accent tones.
2227
+ * @default '#101499' (deep blue)
2228
+ */
2229
+ orbColor3?: string;
2211
2230
  }
2212
- declare function OrbBackground({ className, hue, hoverIntensity, rotateOnHover, forceHoverState, backgroundColor }: OrbBackgroundProps): react_jsx_runtime.JSX.Element;
2231
+ declare function OrbBackground({ className, hue, hoverIntensity, rotateOnHover, forceHoverState, backgroundColor, orbColor1, orbColor2, orbColor3, }: OrbBackgroundProps): react_jsx_runtime.JSX.Element;
2213
2232
 
2214
2233
  interface HeroBlockProps {
2215
2234
  className?: string;
package/dist/index.d.ts CHANGED
@@ -2207,9 +2207,28 @@ interface OrbBackgroundProps {
2207
2207
  hoverIntensity?: number;
2208
2208
  rotateOnHover?: boolean;
2209
2209
  forceHoverState?: boolean;
2210
+ /**
2211
+ * Background color (hex). If not provided, uses CSS variable --color-background.
2212
+ * @default undefined (reads from theme)
2213
+ */
2210
2214
  backgroundColor?: string;
2215
+ /**
2216
+ * Primary orb color (hex). Creates the main vibrant tone.
2217
+ * @default '#9c43fe' (purple)
2218
+ */
2219
+ orbColor1?: string;
2220
+ /**
2221
+ * Secondary orb color (hex). Adds cool cyan tones.
2222
+ * @default '#4cc2e9' (cyan)
2223
+ */
2224
+ orbColor2?: string;
2225
+ /**
2226
+ * Tertiary orb color (hex). Provides deep blue accent tones.
2227
+ * @default '#101499' (deep blue)
2228
+ */
2229
+ orbColor3?: string;
2211
2230
  }
2212
- declare function OrbBackground({ className, hue, hoverIntensity, rotateOnHover, forceHoverState, backgroundColor }: OrbBackgroundProps): react_jsx_runtime.JSX.Element;
2231
+ declare function OrbBackground({ className, hue, hoverIntensity, rotateOnHover, forceHoverState, backgroundColor, orbColor1, orbColor2, orbColor3, }: OrbBackgroundProps): react_jsx_runtime.JSX.Element;
2213
2232
 
2214
2233
  interface HeroBlockProps {
2215
2234
  className?: string;
package/dist/index.js CHANGED
@@ -9880,13 +9880,30 @@ var AnimatedBeam = ({
9880
9880
  var import_ogl3 = require("ogl");
9881
9881
  var import_react36 = require("react");
9882
9882
  var import_jsx_runtime85 = require("react/jsx-runtime");
9883
+ function hexToRgb4(hex) {
9884
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
9885
+ if (!result) return [0, 0, 0];
9886
+ return [
9887
+ parseInt(result[1], 16) / 255,
9888
+ parseInt(result[2], 16) / 255,
9889
+ parseInt(result[3], 16) / 255
9890
+ ];
9891
+ }
9892
+ function getCSSVariable2(name, fallback) {
9893
+ if (typeof window === "undefined") return fallback;
9894
+ const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
9895
+ return value || fallback;
9896
+ }
9883
9897
  function OrbBackground({
9884
9898
  className,
9885
9899
  hue = 0,
9886
9900
  hoverIntensity = 0.2,
9887
9901
  rotateOnHover = true,
9888
9902
  forceHoverState = false,
9889
- backgroundColor = "#000000"
9903
+ backgroundColor,
9904
+ orbColor1,
9905
+ orbColor2,
9906
+ orbColor3
9890
9907
  }) {
9891
9908
  const ctnDom = (0, import_react36.useRef)(null);
9892
9909
  const vert = (
@@ -9914,6 +9931,10 @@ function OrbBackground({
9914
9931
  uniform float rot;
9915
9932
  uniform float hoverIntensity;
9916
9933
  uniform vec3 backgroundColor;
9934
+ // THEME-AWARE: Orb colors from theme (to revert: change back to const)
9935
+ uniform vec3 orbColor1;
9936
+ uniform vec3 orbColor2;
9937
+ uniform vec3 orbColor3;
9917
9938
  varying vec2 vUv;
9918
9939
 
9919
9940
  vec3 rgb2yiq(vec3 c) {
@@ -9982,10 +10003,12 @@ function OrbBackground({
9982
10003
  float a = max(max(colorIn.r, colorIn.g), colorIn.b);
9983
10004
  return vec4(colorIn.rgb / (a + 1e-5), a);
9984
10005
  }
9985
-
9986
- const vec3 baseColor1 = vec3(0.611765, 0.262745, 0.996078);
9987
- const vec3 baseColor2 = vec3(0.298039, 0.760784, 0.913725);
9988
- const vec3 baseColor3 = vec3(0.062745, 0.078431, 0.600000);
10006
+
10007
+ // THEME-AWARE: Colors now come from uniforms (orbColor1, orbColor2, orbColor3)
10008
+ // To revert to hardcoded: uncomment these and remove uniforms above
10009
+ // const vec3 baseColor1 = vec3(0.611765, 0.262745, 0.996078);
10010
+ // const vec3 baseColor2 = vec3(0.298039, 0.760784, 0.913725);
10011
+ // const vec3 baseColor3 = vec3(0.062745, 0.078431, 0.600000);
9989
10012
  const float innerRadius = 0.6;
9990
10013
  const float noiseScale = 0.65;
9991
10014
 
@@ -9998,9 +10021,10 @@ function OrbBackground({
9998
10021
  }
9999
10022
 
10000
10023
  vec4 draw(vec2 uv) {
10001
- vec3 color1 = adjustHue(baseColor1, hue);
10002
- vec3 color2 = adjustHue(baseColor2, hue);
10003
- vec3 color3 = adjustHue(baseColor3, hue);
10024
+ // THEME-AWARE: Use uniform colors instead of hardcoded consts
10025
+ vec3 color1 = adjustHue(orbColor1, hue);
10026
+ vec3 color2 = adjustHue(orbColor2, hue);
10027
+ vec3 color3 = adjustHue(orbColor3, hue);
10004
10028
 
10005
10029
  float ang = atan(uv.y, uv.x);
10006
10030
  float len = length(uv);
@@ -10069,6 +10093,14 @@ function OrbBackground({
10069
10093
  (0, import_react36.useEffect)(() => {
10070
10094
  const container = ctnDom.current;
10071
10095
  if (!container) return;
10096
+ const bgColor = backgroundColor || getCSSVariable2("--color-background", "#000000");
10097
+ const color1 = orbColor1 || "#9c43fe";
10098
+ const color2 = orbColor2 || "#4cc2e9";
10099
+ const color3 = orbColor3 || "#101499";
10100
+ const bgRgb = hexToRgb4(bgColor);
10101
+ const color1Rgb = hexToRgb4(color1);
10102
+ const color2Rgb = hexToRgb4(color2);
10103
+ const color3Rgb = hexToRgb4(color3);
10072
10104
  const renderer = new import_ogl3.Renderer({ alpha: true, premultipliedAlpha: false });
10073
10105
  const gl = renderer.gl;
10074
10106
  gl.clearColor(0, 0, 0, 0);
@@ -10086,7 +10118,11 @@ function OrbBackground({
10086
10118
  hover: { value: 0 },
10087
10119
  rot: { value: 0 },
10088
10120
  hoverIntensity: { value: hoverIntensity },
10089
- backgroundColor: { value: hexToVec3(backgroundColor) }
10121
+ // THEME-AWARE: Pass theme colors to shader
10122
+ backgroundColor: { value: new import_ogl3.Vec3(...bgRgb) },
10123
+ orbColor1: { value: new import_ogl3.Vec3(...color1Rgb) },
10124
+ orbColor2: { value: new import_ogl3.Vec3(...color2Rgb) },
10125
+ orbColor3: { value: new import_ogl3.Vec3(...color3Rgb) }
10090
10126
  }
10091
10127
  });
10092
10128
  const mesh = new import_ogl3.Mesh(gl, { geometry, program });
@@ -10143,7 +10179,6 @@ function OrbBackground({
10143
10179
  currentRot += dt * rotationSpeed;
10144
10180
  }
10145
10181
  program.uniforms.rot.value = currentRot;
10146
- program.uniforms.backgroundColor.value = hexToVec3(backgroundColor);
10147
10182
  renderer.render({ scene: mesh });
10148
10183
  };
10149
10184
  rafId = requestAnimationFrame(update);
@@ -10160,47 +10195,6 @@ function OrbBackground({
10160
10195
  }, [hue, hoverIntensity, rotateOnHover, forceHoverState, backgroundColor]);
10161
10196
  return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { ref: ctnDom, className: cn("w-full h-full pointer-events-auto", className) });
10162
10197
  }
10163
- function hslToRgb(h, s, l) {
10164
- let r, g, b;
10165
- if (s === 0) {
10166
- r = g = b = l;
10167
- } else {
10168
- const hue2rgb = (p2, q2, t) => {
10169
- if (t < 0) t += 1;
10170
- if (t > 1) t -= 1;
10171
- if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
10172
- if (t < 1 / 2) return q2;
10173
- if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
10174
- return p2;
10175
- };
10176
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
10177
- const p = 2 * l - q;
10178
- r = hue2rgb(p, q, h + 1 / 3);
10179
- g = hue2rgb(p, q, h);
10180
- b = hue2rgb(p, q, h - 1 / 3);
10181
- }
10182
- return new import_ogl3.Vec3(r, g, b);
10183
- }
10184
- function hexToVec3(color) {
10185
- if (color.startsWith("#")) {
10186
- const r = parseInt(color.slice(1, 3), 16) / 255;
10187
- const g = parseInt(color.slice(3, 5), 16) / 255;
10188
- const b = parseInt(color.slice(5, 7), 16) / 255;
10189
- return new import_ogl3.Vec3(r, g, b);
10190
- }
10191
- const rgbMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
10192
- if (rgbMatch) {
10193
- return new import_ogl3.Vec3(parseInt(rgbMatch[1]) / 255, parseInt(rgbMatch[2]) / 255, parseInt(rgbMatch[3]) / 255);
10194
- }
10195
- const hslMatch = color.match(/hsla?\((\d+),\s*(\d+)%,\s*(\d+)%/);
10196
- if (hslMatch) {
10197
- const h = parseInt(hslMatch[1]) / 360;
10198
- const s = parseInt(hslMatch[2]) / 100;
10199
- const l = parseInt(hslMatch[3]) / 100;
10200
- return hslToRgb(h, s, l);
10201
- }
10202
- return new import_ogl3.Vec3(0, 0, 0);
10203
- }
10204
10198
 
10205
10199
  // src/components/blocks/Hero.tsx
10206
10200
  var import_lucide_react22 = require("lucide-react");
@@ -11679,6 +11673,49 @@ function mergeCustomColorTokens(baseTokens2, customPalette) {
11679
11673
  ...customPalette.derivedTokens
11680
11674
  };
11681
11675
  }
11676
+ function validateThemeTokens(theme, mode) {
11677
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
11678
+ const root = document.documentElement;
11679
+ const style = getComputedStyle(root);
11680
+ const requiredTokens = [
11681
+ "--color-background",
11682
+ "--color-foreground",
11683
+ "--color-primary",
11684
+ "--color-primary-foreground",
11685
+ "--color-border",
11686
+ "--color-ring",
11687
+ "--font-heading",
11688
+ "--font-body",
11689
+ "--font-mono"
11690
+ ];
11691
+ const missingTokens = [];
11692
+ const invalidTokens = [];
11693
+ requiredTokens.forEach((token) => {
11694
+ const value = style.getPropertyValue(token).trim();
11695
+ if (!value) {
11696
+ missingTokens.push(token);
11697
+ } else if (token.startsWith("--color-") && !value.match(/^(#|rgb|hsl|var\()/)) {
11698
+ invalidTokens.push(`${token} = "${value}"`);
11699
+ } else if (token.startsWith("--font-") && value === "") {
11700
+ invalidTokens.push(`${token} = empty`);
11701
+ }
11702
+ });
11703
+ if (missingTokens.length > 0) {
11704
+ console.warn(
11705
+ `[ThemeProvider] Missing CSS variables for theme "${theme}" (${mode} mode):`,
11706
+ missingTokens
11707
+ );
11708
+ }
11709
+ if (invalidTokens.length > 0) {
11710
+ console.warn(
11711
+ `[ThemeProvider] Invalid CSS variable values for theme "${theme}" (${mode} mode):`,
11712
+ invalidTokens
11713
+ );
11714
+ }
11715
+ if (missingTokens.length === 0 && invalidTokens.length === 0) {
11716
+ console.log(`[ThemeProvider] \u2713 Theme validation passed for "${theme}" (${mode} mode)`);
11717
+ }
11718
+ }
11682
11719
  function ThemeProvider({ children }) {
11683
11720
  const { theme, mode } = useThemeStore();
11684
11721
  const customPalette = useCustomizer((state) => state.customColors?.[theme]?.[mode]);
@@ -11712,6 +11749,7 @@ function ThemeProvider({ children }) {
11712
11749
  } else {
11713
11750
  root.classList.remove("dark");
11714
11751
  }
11752
+ validateThemeTokens(theme, mode);
11715
11753
  const timeout = setTimeout(() => {
11716
11754
  root.classList.remove("theme-transitioning");
11717
11755
  setIsTransitioning(false);