nuxt-ui-elements 0.1.1 → 0.1.3

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/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-ui-elements",
3
3
  "configKey": "uiElements",
4
- "version": "0.1.1",
4
+ "version": "0.1.3",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -9,7 +9,8 @@ const module$1 = defineNuxtModule({
9
9
  prefix: "UE"
10
10
  },
11
11
  moduleDependencies: {
12
- "motion-v/nuxt": {}
12
+ "motion-v/nuxt": {},
13
+ "@nuxtjs/color-mode": {}
13
14
  },
14
15
  setup(options, _nuxt) {
15
16
  const resolver = createResolver(import.meta.url);
@@ -48,13 +48,13 @@ export interface AuroraSlots {
48
48
  }
49
49
  declare const _default: typeof __VLS_export;
50
50
  export default _default;
51
- declare const __VLS_export: __VLS_WithSlots<import("@vue/runtime-core").DefineComponent<AuroraProps, {}, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<AuroraProps> & Readonly<{}>, {
51
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<AuroraProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<AuroraProps> & Readonly<{}>, {
52
52
  pin: "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
53
53
  color: "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral";
54
54
  speed: number;
55
55
  intensity: number;
56
56
  reverse: boolean;
57
- }, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, false, {}, any>, AuroraSlots>;
57
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, AuroraSlots>;
58
58
  type __VLS_WithSlots<T, S> = T & {
59
59
  new (): {
60
60
  $slots: S;
@@ -48,13 +48,13 @@ export interface AuroraSlots {
48
48
  }
49
49
  declare const _default: typeof __VLS_export;
50
50
  export default _default;
51
- declare const __VLS_export: __VLS_WithSlots<import("@vue/runtime-core").DefineComponent<AuroraProps, {}, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<AuroraProps> & Readonly<{}>, {
51
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<AuroraProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<AuroraProps> & Readonly<{}>, {
52
52
  pin: "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
53
53
  color: "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral";
54
54
  speed: number;
55
55
  intensity: number;
56
56
  reverse: boolean;
57
- }, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, false, {}, any>, AuroraSlots>;
57
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, AuroraSlots>;
58
58
  type __VLS_WithSlots<T, S> = T & {
59
59
  new (): {
60
60
  $slots: S;
@@ -1,3 +1,4 @@
1
+ import { type ColorInput } from "../../composables/useColorResolver.js";
1
2
  import type { ComponentConfig } from "../../types/tv.js";
2
3
  import backgroundFlickeringGridTheme from "../../themes/background-flickering-grid.js";
3
4
  type BackgroundFlickeringGrid = ComponentConfig<typeof backgroundFlickeringGridTheme>;
@@ -7,61 +8,70 @@ type BackgroundFlickeringGrid = ComponentConfig<typeof backgroundFlickeringGridT
7
8
  export interface FlickeringGridProps {
8
9
  /**
9
10
  * The square size of the grid (before scaling)
10
- * @default 12
11
+ * @default 8
11
12
  */
12
- squareSize?: number;
13
+ size?: number;
13
14
  /**
14
15
  * The gap between grid squares
15
- * @default 6
16
+ * @default 8
16
17
  */
17
- gridGap?: number;
18
+ gap?: number;
18
19
  /**
19
- * The flicker animation speed (higher = faster)
20
- * @default 0.3
20
+ * Animation speed (higher = faster flicker)
21
+ * Scale from 1 (slowest) to 10 (fastest)
22
+ * @default 5
21
23
  */
22
- flickerChance?: number;
24
+ speed?: number;
23
25
  /**
24
- * Speed multiplier for flicker animation
25
- * @default 1
26
+ * Apply fade/vignette effect with directional masking
27
+ * - 'radial': Radial fade from center (spotlight effect)
28
+ * - 'left', 'right', 'top', 'bottom': Linear fade from specified edge
29
+ *
26
30
  */
27
- flickerSpeed?: number;
31
+ fade?: "radial" | "left" | "right" | "top" | "bottom";
28
32
  /**
29
- * Gradient direction for the grid
30
- * @default 'left-right'
31
- */
32
- gradientDirection?: "left-right" | "right-left" | "top-bottom" | "bottom-top" | "in-out" | "out-in" | "top-left-bottom-right" | "bottom-right-top-left";
33
- /**
34
- * Maximum opacity of flickering squares
35
- * @default 0.3
36
- */
37
- maxOpacity?: number;
38
- /**
39
- * Apply radial fade to edges
40
- * @default true
41
- */
42
- fade?: boolean;
43
- /**
44
- * Canvas width (defaults to container width)
45
- */
46
- width?: number;
47
- /**
48
- * Canvas height (defaults to container height)
49
- */
50
- height?: number;
51
- /**
52
- * Color variant
33
+ * Color for the grid. Supports:
34
+ * - Nuxt UI semantic: 'primary', 'secondary', 'success', 'info', 'warning', 'error', 'neutral'
35
+ * - Tailwind colors: 'blue-500', 'red-600', 'slate-200', etc.
36
+ * - Direct values: '#3b82f6', 'oklch(0.6 0.15 250)', 'rgb(59, 130, 246)'
37
+ *
38
+ * Choose lighter shades (e.g., 'blue-200') for subtle backgrounds or darker shades (e.g., 'blue-600') for bolder effects.
39
+ *
40
+ * @example 'primary' - Nuxt UI semantic color
41
+ * @example 'blue-200' - Light Tailwind color for subtle effect
42
+ * @example 'blue-600' - Dark Tailwind color for bold effect
43
+ * @example '#e0f2fe' - Direct hex color value (light blue)
44
+ *
53
45
  * @default 'neutral'
54
46
  */
55
- color?: BackgroundFlickeringGrid["variants"]["color"];
47
+ color?: ColorInput;
56
48
  /**
57
- * Style variant
58
- * @default 'subtle'
49
+ * Opacity/visibility of the grid squares.
50
+ * Controls how transparent the grid appears.
51
+ *
52
+ * - 0: Completely invisible
53
+ * - 0.3: Subtle, background texture
54
+ * - 0.5: Medium visibility
55
+ * - 0.8: Bold, prominent
56
+ * - 1: Fully opaque
57
+ *
58
+ * Range: 0-1
59
+ *
60
+ * @default 0.5
59
61
  */
60
- variant?: BackgroundFlickeringGrid["variants"]["variant"];
62
+ opacity?: number;
61
63
  /**
62
- * Additional CSS classes for the container
64
+ * Dark mode overrides for color and opacity.
65
+ *
66
+ * Allows you to customize the grid appearance specifically for dark mode.
67
+ * Any property not specified will use the default light mode value.
68
+ *
69
+ * @example { color: 'blue-300', opacity: 0.3 }
63
70
  */
64
- class?: any;
71
+ dark?: {
72
+ color?: ColorInput;
73
+ opacity?: number;
74
+ };
65
75
  /**
66
76
  * UI slot customization
67
77
  */
@@ -75,18 +85,7 @@ export interface FlickeringGridSlots {
75
85
  }
76
86
  declare const _default: typeof __VLS_export;
77
87
  export default _default;
78
- declare const __VLS_export: __VLS_WithSlots<import("@vue/runtime-core").DefineComponent<FlickeringGridProps, {}, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<FlickeringGridProps> & Readonly<{}>, {
79
- color: BackgroundFlickeringGrid["variants"]["color"];
80
- variant: BackgroundFlickeringGrid["variants"]["variant"];
81
- class: any;
82
- squareSize: number;
83
- gridGap: number;
84
- flickerChance: number;
85
- flickerSpeed: number;
86
- gradientDirection: "left-right" | "right-left" | "top-bottom" | "bottom-top" | "in-out" | "out-in" | "top-left-bottom-right" | "bottom-right-top-left";
87
- maxOpacity: number;
88
- fade: boolean;
89
- }, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, false, {}, any>, FlickeringGridSlots>;
88
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<FlickeringGridProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<FlickeringGridProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, FlickeringGridSlots>;
90
89
  type __VLS_WithSlots<T, S> = T & {
91
90
  new (): {
92
91
  $slots: S;
@@ -4,66 +4,95 @@ import backgroundFlickeringGridTheme from "../../themes/background-flickering-gr
4
4
 
5
5
  <script setup>
6
6
  import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
7
+ import { useColorMode } from "#imports";
7
8
  import { tv } from "../../utils/tv";
8
- import { calculateGradientIntensity } from "../../composables/useGradient";
9
9
  import theme from "../../themes/background-flickering-grid";
10
- import { getThemeColor, adjustLightness, oklchToRgb } from "../../composables/useThemeColors";
11
- const props = defineProps({
12
- squareSize: { type: Number, required: false, default: 8 },
13
- gridGap: { type: Number, required: false, default: 8 },
14
- flickerChance: { type: Number, required: false, default: 0.3 },
15
- flickerSpeed: { type: Number, required: false, default: 0.2 },
16
- gradientDirection: { type: String, required: false, default: "left-right" },
17
- maxOpacity: { type: Number, required: false, default: 0.3 },
18
- fade: { type: Boolean, required: false, default: true },
19
- width: { type: Number, required: false },
20
- height: { type: Number, required: false },
21
- color: { type: null, required: false, default: "neutral" },
22
- variant: { type: null, required: false, default: "subtle" },
23
- class: { type: null, required: false, default: "" },
10
+ import { darkenColor, oklchToRgb } from "../../composables/useThemeColors";
11
+ import {
12
+ resolveColor
13
+ } from "../../composables/useColorResolver";
14
+ const {
15
+ size = 8,
16
+ gap = 9,
17
+ speed = 5,
18
+ color = "neutral",
19
+ opacity = 0.5,
20
+ ...props
21
+ } = defineProps({
22
+ size: { type: Number, required: false },
23
+ gap: { type: Number, required: false },
24
+ speed: { type: Number, required: false },
25
+ fade: { type: String, required: false },
26
+ color: { type: null, required: false },
27
+ opacity: { type: Number, required: false },
28
+ dark: { type: Object, required: false },
24
29
  ui: { type: null, required: false }
25
30
  });
31
+ const colorMode = useColorMode();
32
+ const isDark = computed(() => colorMode.value === "dark");
33
+ const effectiveColor = computed(() => {
34
+ if (isDark.value && props.dark?.color) {
35
+ return props.dark.color;
36
+ }
37
+ return color;
38
+ });
39
+ const effectiveOpacity = computed(() => {
40
+ if (isDark.value && props.dark?.opacity !== void 0) {
41
+ return props.dark.opacity;
42
+ }
43
+ return opacity;
44
+ });
45
+ const internalSpeed = computed(() => {
46
+ return speed * 0.01;
47
+ });
26
48
  defineSlots();
27
- const ui = computed(
28
- () => tv(theme)({
29
- color: props.color,
30
- variant: props.variant
31
- })
32
- );
49
+ const ui = computed(() => tv(theme)());
33
50
  const maskStyle = computed(() => {
34
51
  if (!props.fade) return {};
52
+ let maskImage;
53
+ switch (props.fade) {
54
+ case "radial":
55
+ maskImage = "radial-gradient(circle at center, black 20%, transparent 90%)";
56
+ break;
57
+ case "left":
58
+ maskImage = "linear-gradient(to right, transparent 0%, black 30%)";
59
+ break;
60
+ case "right":
61
+ maskImage = "linear-gradient(to left, transparent 0%, black 30%)";
62
+ break;
63
+ case "top":
64
+ maskImage = "linear-gradient(to bottom, transparent 0%, black 30%)";
65
+ break;
66
+ case "bottom":
67
+ maskImage = "linear-gradient(to top, transparent 0%, black 30%)";
68
+ break;
69
+ default:
70
+ return {};
71
+ }
35
72
  return {
36
- maskImage: "radial-gradient(circle at center, black 20%, transparent 90%)",
37
- WebkitMaskImage: "radial-gradient(circle at center, black 20%, transparent 90%)"
73
+ maskImage,
74
+ WebkitMaskImage: maskImage
38
75
  };
39
76
  });
40
77
  const containerRef = ref();
41
78
  const canvasRef = ref();
42
79
  const context = ref(null);
43
80
  const isInView = ref(false);
44
- const canvasSize = ref({ width: 0, height: 0 });
45
81
  const gridParams = ref(null);
46
- function parseColor(color) {
47
- const match = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
82
+ function parseColor(color2) {
83
+ const match = color2.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
48
84
  if (match && match[1] && match[2] && match[3]) {
49
85
  return [Number(match[1]), Number(match[2]), Number(match[3])];
50
86
  }
51
87
  return [255, 255, 255];
52
88
  }
53
89
  const gridColors = computed(() => {
54
- const baseColor = getThemeColor(props.color, 500);
55
- const lightnessMap = {
56
- subtle: { start: 96, end: 98, flicker: 93 },
57
- soft: { start: 92, end: 96, flicker: 88 },
58
- solid: { start: 80, end: 92, flicker: 70 }
59
- };
60
- const lightness = lightnessMap[props.variant];
61
- const startRgb = oklchToRgb(adjustLightness(baseColor, lightness.start));
62
- const endRgb = oklchToRgb(adjustLightness(baseColor, lightness.end));
63
- const flickerRgb = oklchToRgb(adjustLightness(baseColor, lightness.flicker));
90
+ const baseColor = resolveColor(effectiveColor.value);
91
+ const baseRgb = oklchToRgb(baseColor);
92
+ const darkerColor = darkenColor(baseColor, 10);
93
+ const flickerRgb = oklchToRgb(darkerColor);
64
94
  return {
65
- start: parseColor(startRgb),
66
- end: parseColor(endRgb),
95
+ base: parseColor(baseRgb),
67
96
  flicker: parseColor(flickerRgb)
68
97
  };
69
98
  });
@@ -82,64 +111,56 @@ function lerpColor(a, b, t) {
82
111
  function rgbToString(rgb, alpha = 1) {
83
112
  return `rgba(${rgb[0]},${rgb[1]},${rgb[2]},${alpha})`;
84
113
  }
85
- function getGradientT(i, j, cols, rows) {
86
- const x = cols > 1 ? i / (cols - 1) : 0.5;
87
- const y = rows > 1 ? j / (rows - 1) : 0.5;
88
- return calculateGradientIntensity(x, y, props.gradientDirection);
89
- }
90
114
  function setupCanvas(canvas, width, height) {
91
115
  const dpr = window.devicePixelRatio || 1;
92
116
  canvas.width = width * dpr;
93
117
  canvas.height = height * dpr;
94
118
  canvas.style.width = `${width}px`;
95
119
  canvas.style.height = `${height}px`;
96
- const cols = Math.floor(width / (props.squareSize + props.gridGap));
97
- const rows = Math.floor(height / (props.squareSize + props.gridGap));
120
+ const cols = Math.floor(width / (size + gap));
121
+ const rows = Math.floor(height / (size + gap));
98
122
  const squares = new Float32Array(cols * rows);
99
123
  for (let i = 0; i < squares.length; i++) {
100
- squares[i] = Math.random() * props.maxOpacity;
124
+ squares[i] = Math.random() * effectiveOpacity.value;
101
125
  }
102
126
  return { cols, rows, squares, dpr };
103
127
  }
104
128
  function updateSquares(squares, deltaTime) {
105
129
  for (let i = 0; i < squares.length; i++) {
106
- if (Math.random() < props.flickerChance * props.flickerSpeed * deltaTime) {
107
- squares[i] = Math.random() * props.maxOpacity;
130
+ if (Math.random() < internalSpeed.value * deltaTime) {
131
+ squares[i] = Math.random() * effectiveOpacity.value;
108
132
  }
109
133
  }
110
134
  }
111
- function drawGrid(ctx, width, height, cols, rows, squares, dpr) {
112
- ctx.clearRect(0, 0, width, height);
135
+ function drawGrid(ctx, canvasWidth, canvasHeight, cols, rows, squares, dpr) {
136
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
113
137
  ctx.fillStyle = "transparent";
114
- ctx.fillRect(0, 0, width, height);
138
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
115
139
  const colors = gridColors.value;
116
140
  for (let i = 0; i < cols; i++) {
117
141
  for (let j = 0; j < rows; j++) {
118
142
  const idx = i * rows + j;
119
- const opacity = squares[idx] ?? 0;
120
- const t = getGradientT(i, j, cols, rows);
121
- const baseColor = lerpColor(colors.start, colors.end, t);
122
- let cellColor = baseColor;
123
- let cellAlpha = opacity;
124
- if (opacity > 0.5 * props.maxOpacity) {
125
- const blendT = (opacity - 0.5 * props.maxOpacity) / (0.5 * props.maxOpacity);
126
- cellColor = lerpColor(baseColor, colors.flicker, blendT);
127
- cellAlpha = Math.min(1, opacity + 0.2);
143
+ const opacity2 = squares[idx] ?? 0;
144
+ let cellColor = colors.base;
145
+ let cellAlpha = opacity2;
146
+ if (opacity2 > 0.5 * effectiveOpacity.value) {
147
+ const blendT = (opacity2 - 0.5 * effectiveOpacity.value) / (0.5 * effectiveOpacity.value);
148
+ cellColor = lerpColor(colors.base, colors.flicker, blendT);
149
+ cellAlpha = Math.min(1, opacity2 + 0.2);
128
150
  }
129
151
  ctx.fillStyle = rgbToString(cellColor, cellAlpha);
130
152
  ctx.fillRect(
131
- i * (props.squareSize + props.gridGap) * dpr,
132
- j * (props.squareSize + props.gridGap) * dpr,
133
- props.squareSize * dpr,
134
- props.squareSize * dpr
153
+ i * (size + gap) * dpr,
154
+ j * (size + gap) * dpr,
155
+ size * dpr,
156
+ size * dpr
135
157
  );
136
158
  }
137
159
  }
138
160
  }
139
161
  function updateCanvasSize() {
140
- const newWidth = props.width || containerRef.value?.clientWidth || 0;
141
- const newHeight = props.height || containerRef.value?.clientHeight || 0;
142
- canvasSize.value = { width: newWidth, height: newHeight };
162
+ const newWidth = containerRef.value?.clientWidth || 0;
163
+ const newHeight = containerRef.value?.clientHeight || 0;
143
164
  if (canvasRef.value) {
144
165
  gridParams.value = setupCanvas(canvasRef.value, newWidth, newHeight);
145
166
  }
@@ -194,12 +215,12 @@ onBeforeUnmount(() => {
194
215
  });
195
216
  watch(
196
217
  [
197
- () => props.gradientDirection,
198
- () => props.squareSize,
199
- () => props.gridGap,
200
- () => props.maxOpacity,
201
- () => props.color,
202
- () => props.variant
218
+ () => size,
219
+ () => gap,
220
+ () => color,
221
+ () => opacity,
222
+ () => props.dark?.color,
223
+ () => props.dark?.opacity
203
224
  ],
204
225
  () => {
205
226
  updateCanvasSize();
@@ -208,19 +229,8 @@ watch(
208
229
  </script>
209
230
 
210
231
  <template>
211
- <div
212
- ref="containerRef"
213
- data-slot="base"
214
- :class="ui.base({ class: [props.ui?.base, props.class] })"
215
- >
216
- <canvas
217
- ref="canvasRef"
218
- data-slot="canvas"
219
- :class="ui.canvas({ class: props.ui?.canvas })"
220
- :style="maskStyle"
221
- :width="canvasSize.width"
222
- :height="canvasSize.height"
223
- />
232
+ <div ref="containerRef" :class="ui.base({ class: [props.ui?.base] })">
233
+ <canvas ref="canvasRef" :class="ui.canvas({ class: props.ui?.canvas })" :style="maskStyle" />
224
234
  <slot />
225
235
  </div>
226
236
  </template>
@@ -1,3 +1,4 @@
1
+ import { type ColorInput } from "../../composables/useColorResolver.js";
1
2
  import type { ComponentConfig } from "../../types/tv.js";
2
3
  import backgroundFlickeringGridTheme from "../../themes/background-flickering-grid.js";
3
4
  type BackgroundFlickeringGrid = ComponentConfig<typeof backgroundFlickeringGridTheme>;
@@ -7,61 +8,70 @@ type BackgroundFlickeringGrid = ComponentConfig<typeof backgroundFlickeringGridT
7
8
  export interface FlickeringGridProps {
8
9
  /**
9
10
  * The square size of the grid (before scaling)
10
- * @default 12
11
+ * @default 8
11
12
  */
12
- squareSize?: number;
13
+ size?: number;
13
14
  /**
14
15
  * The gap between grid squares
15
- * @default 6
16
+ * @default 8
16
17
  */
17
- gridGap?: number;
18
+ gap?: number;
18
19
  /**
19
- * The flicker animation speed (higher = faster)
20
- * @default 0.3
20
+ * Animation speed (higher = faster flicker)
21
+ * Scale from 1 (slowest) to 10 (fastest)
22
+ * @default 5
21
23
  */
22
- flickerChance?: number;
24
+ speed?: number;
23
25
  /**
24
- * Speed multiplier for flicker animation
25
- * @default 1
26
+ * Apply fade/vignette effect with directional masking
27
+ * - 'radial': Radial fade from center (spotlight effect)
28
+ * - 'left', 'right', 'top', 'bottom': Linear fade from specified edge
29
+ *
26
30
  */
27
- flickerSpeed?: number;
31
+ fade?: "radial" | "left" | "right" | "top" | "bottom";
28
32
  /**
29
- * Gradient direction for the grid
30
- * @default 'left-right'
31
- */
32
- gradientDirection?: "left-right" | "right-left" | "top-bottom" | "bottom-top" | "in-out" | "out-in" | "top-left-bottom-right" | "bottom-right-top-left";
33
- /**
34
- * Maximum opacity of flickering squares
35
- * @default 0.3
36
- */
37
- maxOpacity?: number;
38
- /**
39
- * Apply radial fade to edges
40
- * @default true
41
- */
42
- fade?: boolean;
43
- /**
44
- * Canvas width (defaults to container width)
45
- */
46
- width?: number;
47
- /**
48
- * Canvas height (defaults to container height)
49
- */
50
- height?: number;
51
- /**
52
- * Color variant
33
+ * Color for the grid. Supports:
34
+ * - Nuxt UI semantic: 'primary', 'secondary', 'success', 'info', 'warning', 'error', 'neutral'
35
+ * - Tailwind colors: 'blue-500', 'red-600', 'slate-200', etc.
36
+ * - Direct values: '#3b82f6', 'oklch(0.6 0.15 250)', 'rgb(59, 130, 246)'
37
+ *
38
+ * Choose lighter shades (e.g., 'blue-200') for subtle backgrounds or darker shades (e.g., 'blue-600') for bolder effects.
39
+ *
40
+ * @example 'primary' - Nuxt UI semantic color
41
+ * @example 'blue-200' - Light Tailwind color for subtle effect
42
+ * @example 'blue-600' - Dark Tailwind color for bold effect
43
+ * @example '#e0f2fe' - Direct hex color value (light blue)
44
+ *
53
45
  * @default 'neutral'
54
46
  */
55
- color?: BackgroundFlickeringGrid["variants"]["color"];
47
+ color?: ColorInput;
56
48
  /**
57
- * Style variant
58
- * @default 'subtle'
49
+ * Opacity/visibility of the grid squares.
50
+ * Controls how transparent the grid appears.
51
+ *
52
+ * - 0: Completely invisible
53
+ * - 0.3: Subtle, background texture
54
+ * - 0.5: Medium visibility
55
+ * - 0.8: Bold, prominent
56
+ * - 1: Fully opaque
57
+ *
58
+ * Range: 0-1
59
+ *
60
+ * @default 0.5
59
61
  */
60
- variant?: BackgroundFlickeringGrid["variants"]["variant"];
62
+ opacity?: number;
61
63
  /**
62
- * Additional CSS classes for the container
64
+ * Dark mode overrides for color and opacity.
65
+ *
66
+ * Allows you to customize the grid appearance specifically for dark mode.
67
+ * Any property not specified will use the default light mode value.
68
+ *
69
+ * @example { color: 'blue-300', opacity: 0.3 }
63
70
  */
64
- class?: any;
71
+ dark?: {
72
+ color?: ColorInput;
73
+ opacity?: number;
74
+ };
65
75
  /**
66
76
  * UI slot customization
67
77
  */
@@ -75,18 +85,7 @@ export interface FlickeringGridSlots {
75
85
  }
76
86
  declare const _default: typeof __VLS_export;
77
87
  export default _default;
78
- declare const __VLS_export: __VLS_WithSlots<import("@vue/runtime-core").DefineComponent<FlickeringGridProps, {}, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {}, string, import("@vue/runtime-core").PublicProps, Readonly<FlickeringGridProps> & Readonly<{}>, {
79
- color: BackgroundFlickeringGrid["variants"]["color"];
80
- variant: BackgroundFlickeringGrid["variants"]["variant"];
81
- class: any;
82
- squareSize: number;
83
- gridGap: number;
84
- flickerChance: number;
85
- flickerSpeed: number;
86
- gradientDirection: "left-right" | "right-left" | "top-bottom" | "bottom-top" | "in-out" | "out-in" | "top-left-bottom-right" | "bottom-right-top-left";
87
- maxOpacity: number;
88
- fade: boolean;
89
- }, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, false, {}, any>, FlickeringGridSlots>;
88
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<FlickeringGridProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<FlickeringGridProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, FlickeringGridSlots>;
90
89
  type __VLS_WithSlots<T, S> = T & {
91
90
  new (): {
92
91
  $slots: S;
@@ -0,0 +1,40 @@
1
+ import colors from "tailwindcss/colors";
2
+ /**
3
+ * Nuxt UI semantic colors
4
+ */
5
+ declare const SEMANTIC_COLORS: readonly ["primary", "secondary", "success", "info", "warning", "error", "neutral"];
6
+ export type SemanticColor = (typeof SEMANTIC_COLORS)[number];
7
+ /**
8
+ * Tailwind color names
9
+ */
10
+ type TailwindColorName = keyof typeof colors;
11
+ /**
12
+ * Tailwind color shades
13
+ */
14
+ type TailwindShade = "50" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900" | "950";
15
+ /**
16
+ * Tailwind color format: colorName-shade (e.g., 'blue-500', 'red-600')
17
+ */
18
+ export type TailwindColor = `${TailwindColorName}-${TailwindShade}`;
19
+ /**
20
+ * Supported color input formats
21
+ */
22
+ export type ColorInput = SemanticColor | TailwindColor | (string & {});
23
+ /**
24
+ * Resolve a color input to an actual color value
25
+ * Supports:
26
+ * - Nuxt UI semantic colors: 'primary', 'secondary', etc.
27
+ * - Tailwind colors: 'blue-500', 'red-600', etc.
28
+ * - Direct color values: '#3b82f6', 'oklch(0.6 0.15 250)', etc.
29
+ *
30
+ * @param colorInput - The color string to resolve
31
+ * @param fallback - Fallback color if resolution fails (default: 'neutral')
32
+ * @returns The resolved color value
33
+ */
34
+ export declare function resolveColor(colorInput: string | undefined, fallback?: SemanticColor): string;
35
+ /**
36
+ * Resolve a color and ensure it returns an OKLCH string
37
+ * Useful when you need consistent color space for manipulation
38
+ */
39
+ export declare function resolveColorAsOklch(colorInput: string | undefined, fallback?: SemanticColor): string;
40
+ export {};
@@ -0,0 +1,68 @@
1
+ import { parse } from "culori";
2
+ import { getThemeColor } from "./useThemeColors.js";
3
+ import colors from "tailwindcss/colors";
4
+ const SEMANTIC_COLORS = [
5
+ "primary",
6
+ "secondary",
7
+ "success",
8
+ "info",
9
+ "warning",
10
+ "error",
11
+ "neutral"
12
+ ];
13
+ function getTailwindDefaultColor(colorName, shade) {
14
+ const colorObj = colors[colorName];
15
+ if (colorObj && typeof colorObj === "object" && !Array.isArray(colorObj)) {
16
+ return colorObj[shade.toString()] || null;
17
+ }
18
+ return null;
19
+ }
20
+ function isSemanticColor(color) {
21
+ return SEMANTIC_COLORS.includes(color);
22
+ }
23
+ function isDirectColor(color) {
24
+ return color.startsWith("#") || color.startsWith("rgb") || color.startsWith("hsl") || color.startsWith("oklch") || color.startsWith("lab") || color.startsWith("lch");
25
+ }
26
+ export function resolveColor(colorInput, fallback = "neutral") {
27
+ if (!colorInput || colorInput.trim() === "") {
28
+ return getThemeColor(fallback, 500);
29
+ }
30
+ const color = colorInput.trim();
31
+ if (isDirectColor(color)) {
32
+ const parsed = parse(color);
33
+ if (parsed) {
34
+ return color;
35
+ }
36
+ console.warn(`[resolveColor] Invalid color format: "${color}"`);
37
+ }
38
+ if (isSemanticColor(color)) {
39
+ return getThemeColor(color, 500);
40
+ }
41
+ const tailwindColorMatch = color.match(/^([a-z]+)-(\d{2,3})$/);
42
+ if (tailwindColorMatch) {
43
+ const [, colorName, shade] = tailwindColorMatch;
44
+ if (colorName && shade) {
45
+ if (typeof document !== "undefined") {
46
+ const resolvedColor = getThemeColor(colorName, parseInt(shade));
47
+ if (resolvedColor !== "oklch(50% 0 0)") {
48
+ return resolvedColor;
49
+ }
50
+ }
51
+ const defaultColor = getTailwindDefaultColor(colorName, parseInt(shade));
52
+ if (defaultColor) {
53
+ return defaultColor;
54
+ }
55
+ }
56
+ }
57
+ console.warn(
58
+ `[resolveColor] Could not resolve color: "${colorInput}". Supported formats: Nuxt UI semantic colors ('primary', 'secondary', etc.), Tailwind colors ('blue-500', 'red-600', etc.), or direct color values ('#3b82f6', 'oklch(...)', 'rgb(...)'). Falling back to "${fallback}".`
59
+ );
60
+ return getThemeColor(fallback, 500);
61
+ }
62
+ export function resolveColorAsOklch(colorInput, fallback = "neutral") {
63
+ const resolved = resolveColor(colorInput, fallback);
64
+ if (isSemanticColor(colorInput || "")) {
65
+ return resolved;
66
+ }
67
+ return resolved;
68
+ }
@@ -1,4 +1,4 @@
1
- export type GradientDirection = "left-right" | "right-left" | "top-bottom" | "bottom-top" | "in-out" | "out-in" | "top-left-bottom-right" | "bottom-right-top-left";
1
+ export type GradientDirection = "left-right" | "right-left" | "top-bottom" | "bottom-top" | "in-out" | "out-in";
2
2
  /**
3
3
  * Calculate gradient intensity for a position based on direction
4
4
  * @param x - X coordinate (0-1)
@@ -18,10 +18,6 @@ export function calculateGradientIntensity(x, y, direction) {
18
18
  const dy = y - 0.5;
19
19
  return 1 - Math.sqrt(dx * dx + dy * dy) * Math.sqrt(2);
20
20
  }
21
- case "top-left-bottom-right":
22
- return (x + y) / 2;
23
- case "bottom-right-top-left":
24
- return 1 - (x + y) / 2;
25
21
  default:
26
22
  return 0;
27
23
  }
@@ -16,6 +16,13 @@ export declare function createOklch(l: number, c: number, h: number): string;
16
16
  * Accepts any valid CSS color string
17
17
  */
18
18
  export declare function adjustLightness(colorStr: string, targetLightness: number): string;
19
+ /**
20
+ * Darken a color by reducing its lightness
21
+ * @param colorStr - Any valid CSS color string
22
+ * @param amount - Amount to reduce lightness by (in percentage points, 0-100)
23
+ * @returns Darkened color string
24
+ */
25
+ export declare function darkenColor(colorStr: string, amount?: number): string;
19
26
  /**
20
27
  * Adjust the chroma (saturation) of a color while preserving lightness and hue
21
28
  */
@@ -24,6 +24,16 @@ export function adjustLightness(colorStr, targetLightness) {
24
24
  oklch.l = targetLightness / 100;
25
25
  return formatCss(oklch);
26
26
  }
27
+ export function darkenColor(colorStr, amount = 10) {
28
+ const parsed = parse(colorStr);
29
+ if (!parsed) return colorStr;
30
+ const oklch = toOklch(parsed);
31
+ if (!oklch || oklch.l === void 0) return colorStr;
32
+ const currentLightness = oklch.l * 100;
33
+ const newLightness = Math.max(0, currentLightness - amount);
34
+ oklch.l = newLightness / 100;
35
+ return formatCss(oklch);
36
+ }
27
37
  export function adjustChroma(colorStr, targetChroma) {
28
38
  const parsed = parse(colorStr);
29
39
  if (!parsed) return colorStr;
@@ -64,10 +74,7 @@ export function oklchToRgb(colorString) {
64
74
  export function getThemeColor(colorName, shade = 500) {
65
75
  if (typeof document === "undefined") return "oklch(50% 0 0)";
66
76
  const styles = getComputedStyle(document.documentElement);
67
- let colorValue = styles.getPropertyValue(`--ui-color-${colorName}-${shade}`).trim();
68
- if (!colorValue) {
69
- colorValue = styles.getPropertyValue(`--color-${colorName}-${shade}`).trim();
70
- }
77
+ const colorValue = styles.getPropertyValue(`--ui-color-${colorName}-${shade}`).trim();
71
78
  return colorValue || "oklch(50% 0 0)";
72
79
  }
73
80
  export function getColorShades(colorName, lightnessValues) {
@@ -1,2 +1,2 @@
1
- declare const _default: any;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -3,62 +3,5 @@ declare const _default: {
3
3
  base: string;
4
4
  canvas: string;
5
5
  };
6
- variants: {
7
- color: {
8
- primary: string;
9
- secondary: string;
10
- success: string;
11
- info: string;
12
- warning: string;
13
- error: string;
14
- neutral: string;
15
- };
16
- variant: {
17
- subtle: string;
18
- soft: string;
19
- solid: string;
20
- };
21
- };
22
- compoundVariants: ({
23
- color: "primary" | "secondary" | "success" | "info" | "warning" | "error";
24
- variant: "subtle";
25
- class: {
26
- canvas: string;
27
- };
28
- } | {
29
- color: "primary" | "secondary" | "success" | "info" | "warning" | "error";
30
- variant: "soft";
31
- class: {
32
- canvas: string;
33
- };
34
- } | {
35
- color: "primary" | "secondary" | "success" | "info" | "warning" | "error";
36
- variant: "solid";
37
- class: {
38
- canvas: string;
39
- };
40
- } | {
41
- color: "neutral";
42
- variant: "subtle";
43
- class: {
44
- canvas: string;
45
- };
46
- } | {
47
- color: "neutral";
48
- variant: "soft";
49
- class: {
50
- canvas: string;
51
- };
52
- } | {
53
- color: "neutral";
54
- variant: "solid";
55
- class: {
56
- canvas: string;
57
- };
58
- })[];
59
- defaultVariants: {
60
- color: "neutral";
61
- variant: "subtle";
62
- };
63
6
  };
64
7
  export default _default;
@@ -1,75 +1,6 @@
1
- const colors = ["primary", "secondary", "success", "info", "warning", "error"];
2
1
  export default {
3
2
  slots: {
4
- base: "w-full h-full absolute inset-0 pointer-events-none",
5
- canvas: "w-full h-full block"
6
- },
7
- variants: {
8
- color: {
9
- primary: "",
10
- secondary: "",
11
- success: "",
12
- info: "",
13
- warning: "",
14
- error: "",
15
- neutral: ""
16
- },
17
- variant: {
18
- subtle: "",
19
- soft: "",
20
- solid: ""
21
- }
22
- },
23
- compoundVariants: [
24
- // Generate variants for each color + variant combination
25
- ...colors.flatMap((color) => [
26
- {
27
- color,
28
- variant: "subtle",
29
- class: {
30
- canvas: `[.bg-${color}-50_&]:_[--grid-end-color:theme(colors.${color}.50)] [.bg-${color}-100_&]:_[--grid-start-color:theme(colors.${color}.100)] [.bg-${color}-200_&]:_[--grid-flicker-color:theme(colors.${color}.200)]`
31
- }
32
- },
33
- {
34
- color,
35
- variant: "soft",
36
- class: {
37
- canvas: `[.bg-${color}-100_&]:_[--grid-end-color:theme(colors.${color}.100)] [.bg-${color}-200_&]:_[--grid-start-color:theme(colors.${color}.200)] [.bg-${color}-300_&]:_[--grid-flicker-color:theme(colors.${color}.300)]`
38
- }
39
- },
40
- {
41
- color,
42
- variant: "solid",
43
- class: {
44
- canvas: `[.bg-${color}-200_&]:_[--grid-end-color:theme(colors.${color}.200)] [.bg-${color}-400_&]:_[--grid-start-color:theme(colors.${color}.400)] [.bg-${color}-500_&]:_[--grid-flicker-color:theme(colors.${color}.500)]`
45
- }
46
- }
47
- ]),
48
- // Neutral variants (using gray)
49
- {
50
- color: "neutral",
51
- variant: "subtle",
52
- class: {
53
- canvas: "[.bg-gray-50_&]:_[--grid-end-color:theme(colors.gray.50)] [.bg-gray-100_&]:_[--grid-start-color:theme(colors.gray.100)] [.bg-gray-200_&]:_[--grid-flicker-color:theme(colors.gray.200)]"
54
- }
55
- },
56
- {
57
- color: "neutral",
58
- variant: "soft",
59
- class: {
60
- canvas: "[.bg-gray-100_&]:_[--grid-end-color:theme(colors.gray.100)] [.bg-gray-200_&]:_[--grid-start-color:theme(colors.gray.200)] [.bg-gray-300_&]:_[--grid-flicker-color:theme(colors.gray.300)]"
61
- }
62
- },
63
- {
64
- color: "neutral",
65
- variant: "solid",
66
- class: {
67
- canvas: "[.bg-gray-200_&]:_[--grid-end-color:theme(colors.gray.200)] [.bg-gray-400_&]:_[--grid-start-color:theme(colors.gray.400)] [.bg-gray-500_&]:_[--grid-flicker-color:theme(colors.gray.500)]"
68
- }
69
- }
70
- ],
71
- defaultVariants: {
72
- color: "neutral",
73
- variant: "subtle"
3
+ base: "w-full h-full absolute inset-0",
4
+ canvas: "w-full h-full block pointer-events-none"
74
5
  }
75
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-ui-elements",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "A collection of beautiful, animated UI components for Nuxt applications",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/genu/nuxt-ui-elements.git",
@@ -55,7 +55,7 @@
55
55
  "lint:fix": "oxlint --fix --type-aware",
56
56
  "format": "oxfmt --write",
57
57
  "format:check": "oxfmt --check",
58
- "release": "pnpm lint && pnpm test && pnpm prepack && changelogen --release && pnpm publish && git push --follow-tags",
58
+ "release": "pnpm lint && pnpm test && pnpm prepack && changelogen --release",
59
59
  "test": "vitest run",
60
60
  "test:watch": "vitest watch",
61
61
  "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"