@scalar/use-hooks 0.3.7 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @scalar/use-hooks
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#8466](https://github.com/scalar/scalar/pull/8466): chore: new build pipeline
8
+
9
+ ## 0.4.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#8322](https://github.com/scalar/scalar/pull/8322): chore: bump required node version to >=22 (LTS)
14
+
15
+ ### Patch Changes
16
+
17
+ #### Updated Dependencies
18
+
19
+ - **@scalar/use-toasts@0.10.0**
20
+ - [#8322](https://github.com/scalar/scalar/pull/8322): chore: bump required node version to >=22 (LTS)
21
+
3
22
  ## 0.3.7
4
23
 
5
24
  ### Patch Changes
@@ -1,22 +1,30 @@
1
- import { defineConfig } from "cva";
2
- import { extendTailwindMerge } from "tailwind-merge";
1
+ import { defineConfig } from 'cva';
2
+ import { extendTailwindMerge } from 'tailwind-merge';
3
+ /**
4
+ * Tailwind Merge Config
5
+ *
6
+ * By default tailwind merge only knows about the default tailwind classes
7
+ * this is because it does not load in the tailwind config at runtime (perf reasons)
8
+ * we must specify any custom classes if they are getting overwritten
9
+ *
10
+ * https://github.com/dcastil/tailwind-merge/blob/v3.4.0/docs/configuration.md#class-groups
11
+ */
3
12
  const tw = extendTailwindMerge({
4
- extend: {
5
- classGroups: {
6
- "font-size": ["text-3xs", "text-xxs"],
7
- "font-weight": ["font-sidebar", "font-sidebar-active"]
8
- }
9
- }
13
+ extend: {
14
+ classGroups: {
15
+ 'font-size': ['text-3xs', 'text-xxs'],
16
+ 'font-weight': ['font-sidebar', 'font-sidebar-active'],
17
+ },
18
+ },
10
19
  });
20
+ /**
21
+ * CVA Config
22
+ *
23
+ * https://beta.cva.style/api-reference/#defineconfig
24
+ */
11
25
  const { cva, cx, compose } = defineConfig({
12
- hooks: {
13
- onComplete: (className) => tw(className)
14
- }
26
+ hooks: {
27
+ onComplete: (className) => tw(className),
28
+ },
15
29
  });
16
- export {
17
- compose,
18
- cva,
19
- cx,
20
- tw
21
- };
22
- //# sourceMappingURL=cva.js.map
30
+ export { cva, cx, compose, tw };
@@ -1,10 +1,2 @@
1
- import { compose, cva, cx, tw } from "./cva.js";
2
- import { useBindCx } from "./useBindCx.js";
3
- export {
4
- compose,
5
- cva,
6
- cx,
7
- tw,
8
- useBindCx
9
- };
10
- //# sourceMappingURL=index.js.map
1
+ export { compose, cva, cx, tw } from './cva.js';
2
+ export { useBindCx } from './useBindCx.js';
@@ -1,92 +1,115 @@
1
- import { computed, useAttrs } from "vue";
2
- import { cx } from "./cva.js";
3
- function useBindCx() {
4
- const attrs = useAttrs();
5
- const destructured = computed(() => {
6
- const { class: className, style, ...rest } = attrs;
7
- return { class: className || "", style, rest };
8
- });
9
- function bindCx(...args) {
1
+ import { computed, useAttrs } from 'vue';
2
+ import { cx } from './cva.js';
3
+ /**
4
+ * Provides a wrapper around the `cx` function that merges the
5
+ * component's class attribute with the provided classes and binds the
6
+ * remaining attributes
7
+ *
8
+ * @see https://beta.cva.style/api-reference#cx
9
+ *
10
+ * @example
11
+ * <script setup>
12
+ * import { useBindCx, cva } from '@scalar/components'
13
+ *
14
+ * defineProps<{ active?: boolean }>()
15
+ *
16
+ * // Important: disable inheritance of attributes
17
+ * defineOptions({ inheritAttrs: false })
18
+ *
19
+ * const { cx } = useBindCx()
20
+ *
21
+ * const variants = cva({
22
+ * base: 'border rounded p-2 bg-b-1',
23
+ * variants: { active: { true: 'bg-b-2' } },
24
+ * })
25
+ * </script>
26
+ * <template>
27
+ * <div v-bind="cx(variants({ active }))">MockComponent</div>
28
+ * </template>
29
+ */
30
+ export function useBindCx() {
31
+ const attrs = useAttrs();
32
+ const destructured = computed(() => {
33
+ const { class: className, style, ...rest } = attrs;
34
+ return { class: className || '', style: style, rest };
35
+ });
36
+ function bindCx(...args) {
37
+ return {
38
+ class: cx(...args, destructured.value.class),
39
+ style: destructured.value.style,
40
+ ...destructured.value.rest,
41
+ };
42
+ }
43
+ function bindClassAndStyle(...args) {
44
+ return { class: cx(...args, destructured.value.class), style: destructured.value.style };
45
+ }
10
46
  return {
11
- class: cx(...args, destructured.value.class),
12
- style: destructured.value.style,
13
- ...destructured.value.rest
47
+ /**
48
+ * Provides a wrapper around the `cx` function that merges the
49
+ * component's class attribute with the provided classes and binds the
50
+ * remaining attributes
51
+ *
52
+ * @example
53
+ * ```html
54
+ * <script setup>
55
+ * ...
56
+ * const { cx } = useBindCx()
57
+ * </script>
58
+ * <template>
59
+ * <div v-bind="cx(...)">...</div>
60
+ * </template>
61
+ * ```
62
+ */
63
+ cx: bindCx,
64
+ /**
65
+ * Provides a wrapper around the `cx` function that merges the
66
+ * component's class attribute with the provided classes and binds the
67
+ * style attribute but **does not** bind any other attributes.
68
+ *
69
+ * Typically used in conjunction with `otherAttrs` to apply the stylistic
70
+ * attributes to a styled wrapper element, but apply the remaining
71
+ * attributes to an internal semantic element like an `<input>`.
72
+ *
73
+ * @example
74
+ * ```html
75
+ * <script setup>
76
+ * ...
77
+ * const { stylingAttrsCx, otherAttrs } = useBindCx()
78
+ * </script>
79
+ * <template>
80
+ * <!-- Bind the class and style attributes to a wrapper element -->
81
+ * <div v-bind="stylingAttrsCx(...)">
82
+ * ...
83
+ * <!-- Bind the other attributes to a semantic internal element -->
84
+ * <input v-bind="otherAttrs" />
85
+ * </div>
86
+ * </template>
87
+ * ```
88
+ */
89
+ stylingAttrsCx: bindClassAndStyle,
90
+ /**
91
+ * The remaining attributes that **are not** the class or style attributes
92
+ * of the component.
93
+ *
94
+ * Typically used in conjunction with `stylingAttrsCx` to apply the stylistic
95
+ * attributes to a styled wrapper element, but apply the remaining
96
+ * attributes to an internal semantic element like an `<input>`.
97
+ *
98
+ * @example
99
+ * ```html
100
+ * <script setup>
101
+ * ...
102
+ * const { stylingAttrsCx, otherAttrs } = useBindCx()
103
+ * </script>
104
+ * <template>
105
+ * <!-- Bind the class and style attributes to a wrapper element -->
106
+ * <div v-bind="stylingAttrsCx(...)">
107
+ * ...
108
+ * <!-- Bind the other attributes to a semantic internal element -->
109
+ * <input v-bind="otherAttrs" />
110
+ * </div>
111
+ * </template>
112
+ */
113
+ otherAttrs: computed(() => destructured.value.rest),
14
114
  };
15
- }
16
- function bindClassAndStyle(...args) {
17
- return { class: cx(...args, destructured.value.class), style: destructured.value.style };
18
- }
19
- return {
20
- /**
21
- * Provides a wrapper around the `cx` function that merges the
22
- * component's class attribute with the provided classes and binds the
23
- * remaining attributes
24
- *
25
- * @example
26
- * ```html
27
- * <script setup>
28
- * ...
29
- * const { cx } = useBindCx()
30
- * <\/script>
31
- * <template>
32
- * <div v-bind="cx(...)">...</div>
33
- * </template>
34
- * ```
35
- */
36
- cx: bindCx,
37
- /**
38
- * Provides a wrapper around the `cx` function that merges the
39
- * component's class attribute with the provided classes and binds the
40
- * style attribute but **does not** bind any other attributes.
41
- *
42
- * Typically used in conjunction with `otherAttrs` to apply the stylistic
43
- * attributes to a styled wrapper element, but apply the remaining
44
- * attributes to an internal semantic element like an `<input>`.
45
- *
46
- * @example
47
- * ```html
48
- * <script setup>
49
- * ...
50
- * const { stylingAttrsCx, otherAttrs } = useBindCx()
51
- * <\/script>
52
- * <template>
53
- * <!-- Bind the class and style attributes to a wrapper element -->
54
- * <div v-bind="stylingAttrsCx(...)">
55
- * ...
56
- * <!-- Bind the other attributes to a semantic internal element -->
57
- * <input v-bind="otherAttrs" />
58
- * </div>
59
- * </template>
60
- * ```
61
- */
62
- stylingAttrsCx: bindClassAndStyle,
63
- /**
64
- * The remaining attributes that **are not** the class or style attributes
65
- * of the component.
66
- *
67
- * Typically used in conjunction with `stylingAttrsCx` to apply the stylistic
68
- * attributes to a styled wrapper element, but apply the remaining
69
- * attributes to an internal semantic element like an `<input>`.
70
- *
71
- * @example
72
- * ```html
73
- * <script setup>
74
- * ...
75
- * const { stylingAttrsCx, otherAttrs } = useBindCx()
76
- * <\/script>
77
- * <template>
78
- * <!-- Bind the class and style attributes to a wrapper element -->
79
- * <div v-bind="stylingAttrsCx(...)">
80
- * ...
81
- * <!-- Bind the other attributes to a semantic internal element -->
82
- * <input v-bind="otherAttrs" />
83
- * </div>
84
- * </template>
85
- */
86
- otherAttrs: computed(() => destructured.value.rest)
87
- };
88
115
  }
89
- export {
90
- useBindCx
91
- };
92
- //# sourceMappingURL=useBindCx.js.map
@@ -1,18 +1,19 @@
1
- const screens = {
2
- /** Mobile */
3
- xs: "(min-width: 400px)",
4
- /** Large Mobile */
5
- sm: "(min-width: 600px)",
6
- /** Tablet */
7
- md: "(min-width: 800px)",
8
- /** Desktop */
9
- lg: "(min-width: 1000px)",
10
- /** Ultrawide and larger */
11
- xl: "(min-width: 1200px)",
12
- /** Custom breakpoint for zoomed in screens (should trigger at about 200% zoom) */
13
- zoomed: "(max-width: 720px) and (max-height: 480px)"
1
+ /**
2
+ * Breakpoints for useBreakpoints hook
3
+ *
4
+ * Should match the tailwind breakpoints in \@scalar/themes
5
+ */
6
+ export const screens = {
7
+ /** Mobile */
8
+ xs: '(min-width: 400px)',
9
+ /** Large Mobile */
10
+ sm: '(min-width: 600px)',
11
+ /** Tablet */
12
+ md: '(min-width: 800px)',
13
+ /** Desktop */
14
+ lg: '(min-width: 1000px)',
15
+ /** Ultrawide and larger */
16
+ xl: '(min-width: 1200px)',
17
+ /** Custom breakpoint for zoomed in screens (should trigger at about 200% zoom) */
18
+ zoomed: '(max-width: 720px) and (max-height: 480px)',
14
19
  };
15
- export {
16
- screens
17
- };
18
- //# sourceMappingURL=constants.js.map
@@ -1,7 +1,2 @@
1
- import { screens } from "./constants.js";
2
- import { useBreakpoints } from "./useBreakpoints.js";
3
- export {
4
- screens,
5
- useBreakpoints
6
- };
7
- //# sourceMappingURL=index.js.map
1
+ export { screens } from './constants.js';
2
+ export { useBreakpoints } from './useBreakpoints.js';
@@ -1,30 +1,28 @@
1
- import { useMediaQuery } from "@vueuse/core";
2
- import { computed, unref } from "vue";
3
- import { screens } from "./constants.js";
4
- function useBreakpoints() {
5
- const mediaQueries = {
6
- xs: useMediaQuery(screens.xs),
7
- sm: useMediaQuery(screens.sm),
8
- md: useMediaQuery(screens.md),
9
- lg: useMediaQuery(screens.lg),
10
- xl: useMediaQuery(screens.xl),
11
- zoomed: useMediaQuery(screens.zoomed)
12
- };
13
- const breakpoints = computed(
14
- () => Object.fromEntries(
15
- Object.entries(mediaQueries).map(([breakpoint, queryRef]) => [breakpoint, unref(queryRef)])
16
- )
17
- );
18
- return {
19
- /** The screen sizes defined in the preset */
20
- screens,
21
- /** Reactive media queries for each of the screen sizes */
22
- mediaQueries,
23
- /** The breakpoints as reactive media queries */
24
- breakpoints
25
- };
1
+ import { useMediaQuery } from '@vueuse/core';
2
+ import { computed, unref } from 'vue';
3
+ import { screens } from './constants.js';
4
+ /**
5
+ * Exposes Tailwind CSS breakpoints as reactive media queries
6
+ *
7
+ * **Warning:** This hook is not a replacement for Tailwind CSS breakpoints. Using breakpoints in Javascript can cause issues with Server Side Rendering (SSR) and the Tailwind CSS breakpoints should be used when possible.
8
+ */
9
+ export function useBreakpoints() {
10
+ const mediaQueries = {
11
+ xs: useMediaQuery(screens.xs),
12
+ sm: useMediaQuery(screens.sm),
13
+ md: useMediaQuery(screens.md),
14
+ lg: useMediaQuery(screens.lg),
15
+ xl: useMediaQuery(screens.xl),
16
+ zoomed: useMediaQuery(screens.zoomed),
17
+ };
18
+ // We make the breakpoints a computed object so that we can use them in templates as `breakpoints.x` instead of `breakpoints.x.value`
19
+ const breakpoints = computed(() => Object.fromEntries(Object.entries(mediaQueries).map(([breakpoint, queryRef]) => [breakpoint, unref(queryRef)])));
20
+ return {
21
+ /** The screen sizes defined in the preset */
22
+ screens,
23
+ /** Reactive media queries for each of the screen sizes */
24
+ mediaQueries,
25
+ /** The breakpoints as reactive media queries */
26
+ breakpoints,
27
+ };
26
28
  }
27
- export {
28
- useBreakpoints
29
- };
30
- //# sourceMappingURL=useBreakpoints.js.map
@@ -1,5 +1 @@
1
- import { useClipboard } from "./useClipboard.js";
2
- export {
3
- useClipboard
4
- };
5
- //# sourceMappingURL=index.js.map
1
+ export { useClipboard } from './useClipboard.js';
@@ -1 +1 @@
1
- //# sourceMappingURL=types.js.map
1
+ export {};
@@ -1,30 +1,31 @@
1
- import { useToasts } from "@scalar/use-toasts";
1
+ import { useToasts } from '@scalar/use-toasts';
2
+ /** Safely serialize a value to a string */
2
3
  const serializeValue = (value) => {
3
- if (value === void 0) {
4
- return "undefined";
5
- }
6
- if (typeof value === "string") {
7
- return value;
8
- }
9
- return JSON.stringify(value);
4
+ if (value === undefined) {
5
+ return 'undefined';
6
+ }
7
+ if (typeof value === 'string') {
8
+ return value;
9
+ }
10
+ return JSON.stringify(value);
10
11
  };
11
- function useClipboard(opts = {}) {
12
- const { notify = (m) => toast(m, "info") } = opts;
13
- const { toast } = useToasts();
14
- async function copyToClipboard(value) {
15
- try {
16
- const serialized = serializeValue(value);
17
- await navigator.clipboard.writeText(serialized);
18
- notify("Copied to the clipboard");
19
- } catch (e) {
20
- const error = e;
21
- console.error(error.message);
22
- notify("Failed to copy to clipboard");
12
+ /**
13
+ * A hook for interacting with the clipboard
14
+ */
15
+ export function useClipboard(opts = {}) {
16
+ const { notify = (m) => toast(m, 'info') } = opts;
17
+ const { toast } = useToasts();
18
+ async function copyToClipboard(value) {
19
+ try {
20
+ const serialized = serializeValue(value);
21
+ await navigator.clipboard.writeText(serialized);
22
+ notify('Copied to the clipboard');
23
+ }
24
+ catch (e) {
25
+ const error = e;
26
+ console.error(error.message);
27
+ notify('Failed to copy to clipboard');
28
+ }
23
29
  }
24
- }
25
- return { copyToClipboard };
30
+ return { copyToClipboard };
26
31
  }
27
- export {
28
- useClipboard
29
- };
30
- //# sourceMappingURL=useClipboard.js.map
@@ -1,5 +1 @@
1
- import { useColorMode } from "./useColorMode.js";
2
- export {
3
- useColorMode
4
- };
5
- //# sourceMappingURL=index.js.map
1
+ export { useColorMode } from './useColorMode.js';
@@ -1,88 +1,97 @@
1
- import { computed, onMounted, onUnmounted, ref, watch } from "vue";
2
- import { z } from "zod";
3
- const colorMode = ref("dark");
4
- const colorModeSchema = z.enum(["dark", "light", "system"]).optional().catch(void 0);
5
- function useColorMode(opts = {}) {
6
- const { initialColorMode = "system", overrideColorMode } = opts;
7
- function toggleColorMode() {
8
- colorMode.value = darkLightMode.value === "dark" ? "light" : "dark";
9
- if (typeof window === "undefined") {
10
- return;
11
- }
12
- window?.localStorage?.setItem("colorMode", colorMode.value);
13
- }
14
- function setColorMode(value) {
15
- colorMode.value = value;
16
- if (typeof window === "undefined") {
17
- return;
18
- }
19
- window?.localStorage?.setItem("colorMode", colorMode.value);
20
- }
21
- function getSystemModePreference() {
22
- if (typeof window === "undefined") {
23
- return "light";
24
- }
25
- if (typeof window?.matchMedia !== "function") {
26
- return "dark";
1
+ import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
2
+ import { z } from 'zod';
3
+ const colorMode = ref('dark');
4
+ const colorModeSchema = z.enum(['dark', 'light', 'system']).optional().catch(undefined);
5
+ /**
6
+ * A composable hook that provides color mode (dark/light) functionality.
7
+ */
8
+ export function useColorMode(opts = {}) {
9
+ const { initialColorMode = 'system', overrideColorMode } = opts;
10
+ /** Toggles the color mode between light and dark. */
11
+ function toggleColorMode() {
12
+ // Update state
13
+ colorMode.value = darkLightMode.value === 'dark' ? 'light' : 'dark';
14
+ // Store in local storage
15
+ if (typeof window === 'undefined') {
16
+ return;
17
+ }
18
+ window?.localStorage?.setItem('colorMode', colorMode.value);
27
19
  }
28
- return window?.matchMedia("(prefers-color-scheme: dark)")?.matches ? "dark" : "light";
29
- }
30
- const darkLightMode = computed({
31
- get: () => colorMode.value === "system" ? getSystemModePreference() : colorMode.value,
32
- set: setColorMode
33
- });
34
- const isDarkMode = computed({
35
- get: () => darkLightMode.value === "dark",
36
- set: (value) => setColorMode(value ? "dark" : "light")
37
- });
38
- function applyColorMode(mode) {
39
- if (typeof document === "undefined" || typeof window === "undefined") {
40
- return;
20
+ /** Sets the color mode to the specified value. */
21
+ function setColorMode(value) {
22
+ colorMode.value = value;
23
+ if (typeof window === 'undefined') {
24
+ return;
25
+ }
26
+ window?.localStorage?.setItem('colorMode', colorMode.value);
41
27
  }
42
- const classMode = overrideColorMode ?? (mode === "system" ? getSystemModePreference() : mode);
43
- if (classMode === "dark") {
44
- document.body.classList.add("dark-mode");
45
- document.body.classList.remove("light-mode");
46
- } else {
47
- document.body.classList.add("light-mode");
48
- document.body.classList.remove("dark-mode");
28
+ /** Gets the system mode preference. */
29
+ function getSystemModePreference() {
30
+ if (typeof window === 'undefined') {
31
+ return 'light';
32
+ }
33
+ if (typeof window?.matchMedia !== 'function') {
34
+ return 'dark';
35
+ }
36
+ return window?.matchMedia('(prefers-color-scheme: dark)')?.matches ? 'dark' : 'light';
49
37
  }
50
- }
51
- const savedColorMode = colorModeSchema.parse(
52
- typeof window !== "undefined" ? window?.localStorage?.getItem("colorMode") : "system"
53
- );
54
- colorMode.value = overrideColorMode ?? savedColorMode ?? initialColorMode;
55
- watch(colorMode, applyColorMode, { immediate: true });
56
- const handleChange = () => colorMode.value === "system" && applyColorMode("system");
57
- const mediaQuery = ref(null);
58
- onMounted(() => {
59
- if (typeof window !== "undefined" && typeof window?.matchMedia === "function") {
60
- mediaQuery.value = window.matchMedia("(prefers-color-scheme: dark)");
61
- mediaQuery.value?.addEventListener("change", handleChange);
38
+ /** Writable computed ref for dark/light mode with system preference applied */
39
+ const darkLightMode = computed({
40
+ get: () => (colorMode.value === 'system' ? getSystemModePreference() : colorMode.value),
41
+ set: setColorMode,
42
+ });
43
+ /** Writable computed ref for whether the current color mode is dark */
44
+ const isDarkMode = computed({
45
+ get: () => darkLightMode.value === 'dark',
46
+ set: (value) => setColorMode(value ? 'dark' : 'light'),
47
+ });
48
+ /** Applies the appropriate color mode class to the body. */
49
+ function applyColorMode(mode) {
50
+ if (typeof document === 'undefined' || typeof window === 'undefined') {
51
+ return;
52
+ }
53
+ const classMode = overrideColorMode ?? (mode === 'system' ? getSystemModePreference() : mode);
54
+ if (classMode === 'dark') {
55
+ document.body.classList.add('dark-mode');
56
+ document.body.classList.remove('light-mode');
57
+ }
58
+ else {
59
+ document.body.classList.add('light-mode');
60
+ document.body.classList.remove('dark-mode');
61
+ }
62
62
  }
63
- });
64
- onUnmounted(() => {
65
- mediaQuery.value?.removeEventListener("change", handleChange);
66
- });
67
- return {
68
- /** The current color mode (writable). */
69
- colorMode: computed({
70
- get: () => colorMode.value,
71
- set: setColorMode
72
- }),
73
- /** The computed dark/light mode (writable). */
74
- darkLightMode,
75
- /** Whether the current color mode is dark (writable). */
76
- isDarkMode,
77
- /** Toggles the color mode between light and dark. */
78
- toggleColorMode,
79
- /** Sets the color mode to the specified value. */
80
- setColorMode,
81
- /** Gets the system mode preference. */
82
- getSystemModePreference
83
- };
63
+ // Priority of initial values is: forceDarkModeState -> LocalStorage -> App Config -> initial / Fallback
64
+ const savedColorMode = colorModeSchema.parse(typeof window !== 'undefined' ? window?.localStorage?.getItem('colorMode') : 'system');
65
+ colorMode.value = overrideColorMode ?? savedColorMode ?? initialColorMode;
66
+ // Watch for colorMode changes and update the body class
67
+ watch(colorMode, applyColorMode, { immediate: true });
68
+ const handleChange = () => colorMode.value === 'system' && applyColorMode('system');
69
+ const mediaQuery = ref(null);
70
+ // Listen to system preference changes
71
+ onMounted(() => {
72
+ if (typeof window !== 'undefined' && typeof window?.matchMedia === 'function') {
73
+ mediaQuery.value = window.matchMedia('(prefers-color-scheme: dark)');
74
+ mediaQuery.value?.addEventListener('change', handleChange);
75
+ }
76
+ });
77
+ onUnmounted(() => {
78
+ mediaQuery.value?.removeEventListener('change', handleChange);
79
+ });
80
+ return {
81
+ /** The current color mode (writable). */
82
+ colorMode: computed({
83
+ get: () => colorMode.value,
84
+ set: setColorMode,
85
+ }),
86
+ /** The computed dark/light mode (writable). */
87
+ darkLightMode,
88
+ /** Whether the current color mode is dark (writable). */
89
+ isDarkMode,
90
+ /** Toggles the color mode between light and dark. */
91
+ toggleColorMode,
92
+ /** Sets the color mode to the specified value. */
93
+ setColorMode,
94
+ /** Gets the system mode preference. */
95
+ getSystemModePreference,
96
+ };
84
97
  }
85
- export {
86
- useColorMode
87
- };
88
- //# sourceMappingURL=useColorMode.js.map
package/package.json CHANGED
@@ -10,9 +10,9 @@
10
10
  "url": "git+https://github.com/scalar/scalar.git",
11
11
  "directory": "packages/use-hooks"
12
12
  },
13
- "version": "0.3.7",
13
+ "version": "0.4.1",
14
14
  "engines": {
15
- "node": ">=20"
15
+ "node": ">=22"
16
16
  },
17
17
  "type": "module",
18
18
  "exports": {
@@ -47,20 +47,15 @@
47
47
  "tailwind-merge": "3.4.0",
48
48
  "vue": "^3.5.26",
49
49
  "zod": "^4.3.5",
50
- "@scalar/use-toasts": "0.9.1"
50
+ "@scalar/use-toasts": "0.10.1"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@vue/test-utils": "2.4.6",
54
- "jsdom": "27.4.0",
55
- "vite": "^7.3.1",
56
- "@scalar/build-tooling": "0.4.1"
54
+ "jsdom": "27.4.0"
57
55
  },
58
56
  "scripts": {
59
- "build": "scalar-build-esbuild",
60
- "lint:check": "scalar-lint-check",
61
- "lint:fix": "scalar-lint-fix",
57
+ "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
62
58
  "test": "vitest",
63
- "types:build": "scalar-types-build-vue",
64
- "types:check": "scalar-types-check-vue"
59
+ "types:check": "vue-tsc --noEmit"
65
60
  }
66
61
  }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useBindCx/cva.ts"],
4
- "sourcesContent": ["import { defineConfig } from 'cva'\nimport { extendTailwindMerge } from 'tailwind-merge'\n\n/**\n * Tailwind Merge Config\n *\n * By default tailwind merge only knows about the default tailwind classes\n * this is because it does not load in the tailwind config at runtime (perf reasons)\n * we must specify any custom classes if they are getting overwritten\n *\n * https://github.com/dcastil/tailwind-merge/blob/v3.4.0/docs/configuration.md#class-groups\n */\nconst tw = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': ['text-3xs', 'text-xxs'],\n 'font-weight': ['font-sidebar', 'font-sidebar-active'],\n },\n },\n})\n\n/**\n * CVA Config\n *\n * https://beta.cva.style/api-reference/#defineconfig\n */\nconst { cva, cx, compose } = defineConfig({\n hooks: {\n onComplete: (className) => tw(className),\n },\n})\n\nexport { cva, cx, compose, tw }\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,2BAA2B;AAWpC,MAAM,KAAK,oBAAoB;AAAA,EAC7B,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa,CAAC,YAAY,UAAU;AAAA,MACpC,eAAe,CAAC,gBAAgB,qBAAqB;AAAA,IACvD;AAAA,EACF;AACF,CAAC;AAOD,MAAM,EAAE,KAAK,IAAI,QAAQ,IAAI,aAAa;AAAA,EACxC,OAAO;AAAA,IACL,YAAY,CAAC,cAAc,GAAG,SAAS;AAAA,EACzC;AACF,CAAC;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useBindCx/index.ts"],
4
- "sourcesContent": ["export { compose, cva, cx, tw } from './cva'\nexport { useBindCx } from './useBindCx'\n"],
5
- "mappings": "AAAA,SAAS,SAAS,KAAK,IAAI,UAAU;AACrC,SAAS,iBAAiB;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useBindCx/useBindCx.ts"],
4
- "sourcesContent": ["import type { CXOptions } from 'cva'\nimport { type StyleValue, computed, useAttrs } from 'vue'\n\nimport { cx } from './cva'\n\n/** Utility type for class names */\ntype ClassValue = CXOptions[number]\n\n/**\n * Provides a wrapper around the `cx` function that merges the\n * component's class attribute with the provided classes and binds the\n * remaining attributes\n *\n * @see https://beta.cva.style/api-reference#cx\n *\n * @example\n * <script setup>\n * import { useBindCx, cva } from '@scalar/components'\n *\n * defineProps<{ active?: boolean }>()\n *\n * // Important: disable inheritance of attributes\n * defineOptions({ inheritAttrs: false })\n *\n * const { cx } = useBindCx()\n *\n * const variants = cva({\n * base: 'border rounded p-2 bg-b-1',\n * variants: { active: { true: 'bg-b-2' } },\n * })\n * </script>\n * <template>\n * <div v-bind=\"cx(variants({ active }))\">MockComponent</div>\n * </template>\n */\nexport function useBindCx() {\n const attrs = useAttrs()\n\n const destructured = computed<{\n class: ClassValue\n style: StyleValue\n rest: { [key: string]: unknown }\n }>(() => {\n const { class: className, style, ...rest } = attrs\n return { class: className || '', style: style as StyleValue, rest }\n })\n\n function bindCx(...args: CXOptions): {\n /** The merged class attribute */\n class: string\n /** The remaining attributes */\n [key: string]: any\n } {\n return {\n class: cx(...args, destructured.value.class),\n style: destructured.value.style,\n ...destructured.value.rest,\n }\n }\n\n function bindClassAndStyle(...args: CXOptions): {\n /** The merged class attribute */\n class: string\n style: StyleValue\n } {\n return { class: cx(...args, destructured.value.class), style: destructured.value.style }\n }\n\n return {\n /**\n * Provides a wrapper around the `cx` function that merges the\n * component's class attribute with the provided classes and binds the\n * remaining attributes\n *\n * @example\n * ```html\n * <script setup>\n * ...\n * const { cx } = useBindCx()\n * </script>\n * <template>\n * <div v-bind=\"cx(...)\">...</div>\n * </template>\n * ```\n */\n cx: bindCx,\n /**\n * Provides a wrapper around the `cx` function that merges the\n * component's class attribute with the provided classes and binds the\n * style attribute but **does not** bind any other attributes.\n *\n * Typically used in conjunction with `otherAttrs` to apply the stylistic\n * attributes to a styled wrapper element, but apply the remaining\n * attributes to an internal semantic element like an `<input>`.\n *\n * @example\n * ```html\n * <script setup>\n * ...\n * const { stylingAttrsCx, otherAttrs } = useBindCx()\n * </script>\n * <template>\n * <!-- Bind the class and style attributes to a wrapper element -->\n * <div v-bind=\"stylingAttrsCx(...)\">\n * ...\n * <!-- Bind the other attributes to a semantic internal element -->\n * <input v-bind=\"otherAttrs\" />\n * </div>\n * </template>\n * ```\n */\n stylingAttrsCx: bindClassAndStyle,\n /**\n * The remaining attributes that **are not** the class or style attributes\n * of the component.\n *\n * Typically used in conjunction with `stylingAttrsCx` to apply the stylistic\n * attributes to a styled wrapper element, but apply the remaining\n * attributes to an internal semantic element like an `<input>`.\n *\n * @example\n * ```html\n * <script setup>\n * ...\n * const { stylingAttrsCx, otherAttrs } = useBindCx()\n * </script>\n * <template>\n * <!-- Bind the class and style attributes to a wrapper element -->\n * <div v-bind=\"stylingAttrsCx(...)\">\n * ...\n * <!-- Bind the other attributes to a semantic internal element -->\n * <input v-bind=\"otherAttrs\" />\n * </div>\n * </template>\n */\n otherAttrs: computed(() => destructured.value.rest),\n }\n}\n"],
5
- "mappings": "AACA,SAA0B,UAAU,gBAAgB;AAEpD,SAAS,UAAU;AAgCZ,SAAS,YAAY;AAC1B,QAAM,QAAQ,SAAS;AAEvB,QAAM,eAAe,SAIlB,MAAM;AACP,UAAM,EAAE,OAAO,WAAW,OAAO,GAAG,KAAK,IAAI;AAC7C,WAAO,EAAE,OAAO,aAAa,IAAI,OAA4B,KAAK;AAAA,EACpE,CAAC;AAED,WAAS,UAAU,MAKjB;AACA,WAAO;AAAA,MACL,OAAO,GAAG,GAAG,MAAM,aAAa,MAAM,KAAK;AAAA,MAC3C,OAAO,aAAa,MAAM;AAAA,MAC1B,GAAG,aAAa,MAAM;AAAA,IACxB;AAAA,EACF;AAEA,WAAS,qBAAqB,MAI5B;AACA,WAAO,EAAE,OAAO,GAAG,GAAG,MAAM,aAAa,MAAM,KAAK,GAAG,OAAO,aAAa,MAAM,MAAM;AAAA,EACzF;AAEA,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBL,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA0BJ,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAwBhB,YAAY,SAAS,MAAM,aAAa,MAAM,IAAI;AAAA,EACpD;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useBreakpoints/constants.ts"],
4
- "sourcesContent": ["/**\n * Breakpoints for useBreakpoints hook\n *\n * Should match the tailwind breakpoints in \\@scalar/themes\n */\nexport const screens = {\n /** Mobile */\n xs: '(min-width: 400px)',\n /** Large Mobile */\n sm: '(min-width: 600px)',\n /** Tablet */\n md: '(min-width: 800px)',\n /** Desktop */\n lg: '(min-width: 1000px)',\n /** Ultrawide and larger */\n xl: '(min-width: 1200px)',\n /** Custom breakpoint for zoomed in screens (should trigger at about 200% zoom) */\n zoomed: '(max-width: 720px) and (max-height: 480px)',\n}\n"],
5
- "mappings": "AAKO,MAAM,UAAU;AAAA;AAAA,EAErB,IAAI;AAAA;AAAA,EAEJ,IAAI;AAAA;AAAA,EAEJ,IAAI;AAAA;AAAA,EAEJ,IAAI;AAAA;AAAA,EAEJ,IAAI;AAAA;AAAA,EAEJ,QAAQ;AACV;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useBreakpoints/index.ts"],
4
- "sourcesContent": ["export { screens } from './constants'\nexport { useBreakpoints } from './useBreakpoints'\n"],
5
- "mappings": "AAAA,SAAS,eAAe;AACxB,SAAS,sBAAsB;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useBreakpoints/useBreakpoints.ts"],
4
- "sourcesContent": ["import { useMediaQuery } from '@vueuse/core'\nimport { type Ref, computed, unref } from 'vue'\n\nimport { screens } from './constants'\n\ntype Screen = keyof typeof screens\n\n/**\n * Exposes Tailwind CSS breakpoints as reactive media queries\n *\n * **Warning:** This hook is not a replacement for Tailwind CSS breakpoints. Using breakpoints in Javascript can cause issues with Server Side Rendering (SSR) and the Tailwind CSS breakpoints should be used when possible.\n */\nexport function useBreakpoints() {\n const mediaQueries: Record<Screen, Ref<boolean>> = {\n xs: useMediaQuery(screens.xs),\n sm: useMediaQuery(screens.sm),\n md: useMediaQuery(screens.md),\n lg: useMediaQuery(screens.lg),\n xl: useMediaQuery(screens.xl),\n zoomed: useMediaQuery(screens.zoomed),\n }\n\n // We make the breakpoints a computed object so that we can use them in templates as `breakpoints.x` instead of `breakpoints.x.value`\n const breakpoints = computed(\n () =>\n Object.fromEntries(\n Object.entries(mediaQueries).map(([breakpoint, queryRef]) => [breakpoint, unref(queryRef)]),\n ) as Record<Screen, boolean>,\n )\n\n return {\n /** The screen sizes defined in the preset */\n screens,\n /** Reactive media queries for each of the screen sizes */\n mediaQueries,\n /** The breakpoints as reactive media queries */\n breakpoints,\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,qBAAqB;AAC9B,SAAmB,UAAU,aAAa;AAE1C,SAAS,eAAe;AASjB,SAAS,iBAAiB;AAC/B,QAAM,eAA6C;AAAA,IACjD,IAAI,cAAc,QAAQ,EAAE;AAAA,IAC5B,IAAI,cAAc,QAAQ,EAAE;AAAA,IAC5B,IAAI,cAAc,QAAQ,EAAE;AAAA,IAC5B,IAAI,cAAc,QAAQ,EAAE;AAAA,IAC5B,IAAI,cAAc,QAAQ,EAAE;AAAA,IAC5B,QAAQ,cAAc,QAAQ,MAAM;AAAA,EACtC;AAGA,QAAM,cAAc;AAAA,IAClB,MACE,OAAO;AAAA,MACL,OAAO,QAAQ,YAAY,EAAE,IAAI,CAAC,CAAC,YAAY,QAAQ,MAAM,CAAC,YAAY,MAAM,QAAQ,CAAC,CAAC;AAAA,IAC5F;AAAA,EACJ;AAEA,SAAO;AAAA;AAAA,IAEL;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,EACF;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useClipboard/index.ts"],
4
- "sourcesContent": ["export { useClipboard } from './useClipboard'\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useClipboard/useClipboard.ts"],
4
- "sourcesContent": ["import { useToasts } from '@scalar/use-toasts'\n\nimport type { UseClipboardOptions } from './types'\n\n/** Safely serialize a value to a string */\nconst serializeValue = (value: unknown) => {\n if (value === undefined) {\n return 'undefined'\n }\n if (typeof value === 'string') {\n return value\n }\n return JSON.stringify(value)\n}\n\n/**\n * A hook for interacting with the clipboard\n */\nexport function useClipboard(opts: UseClipboardOptions = {}) {\n const { notify = (m) => toast(m, 'info') } = opts\n const { toast } = useToasts()\n\n async function copyToClipboard(value: unknown) {\n try {\n const serialized = serializeValue(value)\n await navigator.clipboard.writeText(serialized)\n notify('Copied to the clipboard')\n } catch (e) {\n const error = e as Error\n console.error(error.message)\n notify('Failed to copy to clipboard')\n }\n }\n\n return { copyToClipboard }\n}\n"],
5
- "mappings": "AAAA,SAAS,iBAAiB;AAK1B,MAAM,iBAAiB,CAAC,UAAmB;AACzC,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,KAAK,UAAU,KAAK;AAC7B;AAKO,SAAS,aAAa,OAA4B,CAAC,GAAG;AAC3D,QAAM,EAAE,SAAS,CAAC,MAAM,MAAM,GAAG,MAAM,EAAE,IAAI;AAC7C,QAAM,EAAE,MAAM,IAAI,UAAU;AAE5B,iBAAe,gBAAgB,OAAgB;AAC7C,QAAI;AACF,YAAM,aAAa,eAAe,KAAK;AACvC,YAAM,UAAU,UAAU,UAAU,UAAU;AAC9C,aAAO,yBAAyB;AAAA,IAClC,SAAS,GAAG;AACV,YAAM,QAAQ;AACd,cAAQ,MAAM,MAAM,OAAO;AAC3B,aAAO,6BAA6B;AAAA,IACtC;AAAA,EACF;AAEA,SAAO,EAAE,gBAAgB;AAC3B;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useColorMode/index.ts"],
4
- "sourcesContent": ["export { useColorMode } from './useColorMode'\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/useColorMode/useColorMode.ts"],
4
- "sourcesContent": ["import { computed, onMounted, onUnmounted, ref, watch } from 'vue'\nimport { z } from 'zod'\n\nconst colorMode = ref<ColorMode>('dark')\n\nconst colorModeSchema = z.enum(['dark', 'light', 'system']).optional().catch(undefined)\n\n/** Possible color modes */\ntype ColorMode = 'light' | 'dark' | 'system'\n\n/** Specific dark/light mode */\ntype DarkLightMode = 'light' | 'dark'\n\n/**\n * A composable hook that provides color mode (dark/light) functionality.\n */\nexport function useColorMode(\n opts: {\n /** The initial color mode to use */\n initialColorMode?: ColorMode\n /** Override the color mode */\n overrideColorMode?: ColorMode\n } = {},\n) {\n const { initialColorMode = 'system', overrideColorMode } = opts\n\n /** Toggles the color mode between light and dark. */\n function toggleColorMode() {\n // Update state\n colorMode.value = darkLightMode.value === 'dark' ? 'light' : 'dark'\n\n // Store in local storage\n if (typeof window === 'undefined') {\n return\n }\n window?.localStorage?.setItem('colorMode', colorMode.value)\n }\n\n /** Sets the color mode to the specified value. */\n function setColorMode(value: ColorMode) {\n colorMode.value = value\n if (typeof window === 'undefined') {\n return\n }\n window?.localStorage?.setItem('colorMode', colorMode.value)\n }\n\n /** Gets the system mode preference. */\n function getSystemModePreference(): DarkLightMode {\n if (typeof window === 'undefined') {\n return 'light'\n }\n if (typeof window?.matchMedia !== 'function') {\n return 'dark'\n }\n\n return window?.matchMedia('(prefers-color-scheme: dark)')?.matches ? 'dark' : 'light'\n }\n\n /** Writable computed ref for dark/light mode with system preference applied */\n const darkLightMode = computed<DarkLightMode>({\n get: () => (colorMode.value === 'system' ? getSystemModePreference() : colorMode.value),\n set: setColorMode,\n })\n\n /** Writable computed ref for whether the current color mode is dark */\n const isDarkMode = computed<boolean>({\n get: () => darkLightMode.value === 'dark',\n set: (value) => setColorMode(value ? 'dark' : 'light'),\n })\n\n /** Applies the appropriate color mode class to the body. */\n function applyColorMode(mode: ColorMode): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return\n }\n\n const classMode = overrideColorMode ?? (mode === 'system' ? getSystemModePreference() : mode)\n\n if (classMode === 'dark') {\n document.body.classList.add('dark-mode')\n document.body.classList.remove('light-mode')\n } else {\n document.body.classList.add('light-mode')\n document.body.classList.remove('dark-mode')\n }\n }\n\n // Priority of initial values is: forceDarkModeState -> LocalStorage -> App Config -> initial / Fallback\n const savedColorMode = colorModeSchema.parse(\n typeof window !== 'undefined' ? window?.localStorage?.getItem('colorMode') : 'system',\n )\n colorMode.value = overrideColorMode ?? savedColorMode ?? initialColorMode\n\n // Watch for colorMode changes and update the body class\n watch(colorMode, applyColorMode, { immediate: true })\n\n const handleChange = () => colorMode.value === 'system' && applyColorMode('system')\n\n const mediaQuery = ref<MediaQueryList | null>(null)\n // Listen to system preference changes\n onMounted(() => {\n if (typeof window !== 'undefined' && typeof window?.matchMedia === 'function') {\n mediaQuery.value = window.matchMedia('(prefers-color-scheme: dark)')\n mediaQuery.value?.addEventListener('change', handleChange)\n }\n })\n\n onUnmounted(() => {\n mediaQuery.value?.removeEventListener('change', handleChange)\n })\n\n return {\n /** The current color mode (writable). */\n colorMode: computed({\n get: () => colorMode.value,\n set: setColorMode,\n }),\n /** The computed dark/light mode (writable). */\n darkLightMode,\n /** Whether the current color mode is dark (writable). */\n isDarkMode,\n /** Toggles the color mode between light and dark. */\n toggleColorMode,\n /** Sets the color mode to the specified value. */\n setColorMode,\n /** Gets the system mode preference. */\n getSystemModePreference,\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,UAAU,WAAW,aAAa,KAAK,aAAa;AAC7D,SAAS,SAAS;AAElB,MAAM,YAAY,IAAe,MAAM;AAEvC,MAAM,kBAAkB,EAAE,KAAK,CAAC,QAAQ,SAAS,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,MAAS;AAW/E,SAAS,aACd,OAKI,CAAC,GACL;AACA,QAAM,EAAE,mBAAmB,UAAU,kBAAkB,IAAI;AAG3D,WAAS,kBAAkB;AAEzB,cAAU,QAAQ,cAAc,UAAU,SAAS,UAAU;AAG7D,QAAI,OAAO,WAAW,aAAa;AACjC;AAAA,IACF;AACA,YAAQ,cAAc,QAAQ,aAAa,UAAU,KAAK;AAAA,EAC5D;AAGA,WAAS,aAAa,OAAkB;AACtC,cAAU,QAAQ;AAClB,QAAI,OAAO,WAAW,aAAa;AACjC;AAAA,IACF;AACA,YAAQ,cAAc,QAAQ,aAAa,UAAU,KAAK;AAAA,EAC5D;AAGA,WAAS,0BAAyC;AAChD,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO;AAAA,IACT;AACA,QAAI,OAAO,QAAQ,eAAe,YAAY;AAC5C,aAAO;AAAA,IACT;AAEA,WAAO,QAAQ,WAAW,8BAA8B,GAAG,UAAU,SAAS;AAAA,EAChF;AAGA,QAAM,gBAAgB,SAAwB;AAAA,IAC5C,KAAK,MAAO,UAAU,UAAU,WAAW,wBAAwB,IAAI,UAAU;AAAA,IACjF,KAAK;AAAA,EACP,CAAC;AAGD,QAAM,aAAa,SAAkB;AAAA,IACnC,KAAK,MAAM,cAAc,UAAU;AAAA,IACnC,KAAK,CAAC,UAAU,aAAa,QAAQ,SAAS,OAAO;AAAA,EACvD,CAAC;AAGD,WAAS,eAAe,MAAuB;AAC7C,QAAI,OAAO,aAAa,eAAe,OAAO,WAAW,aAAa;AACpE;AAAA,IACF;AAEA,UAAM,YAAY,sBAAsB,SAAS,WAAW,wBAAwB,IAAI;AAExF,QAAI,cAAc,QAAQ;AACxB,eAAS,KAAK,UAAU,IAAI,WAAW;AACvC,eAAS,KAAK,UAAU,OAAO,YAAY;AAAA,IAC7C,OAAO;AACL,eAAS,KAAK,UAAU,IAAI,YAAY;AACxC,eAAS,KAAK,UAAU,OAAO,WAAW;AAAA,IAC5C;AAAA,EACF;AAGA,QAAM,iBAAiB,gBAAgB;AAAA,IACrC,OAAO,WAAW,cAAc,QAAQ,cAAc,QAAQ,WAAW,IAAI;AAAA,EAC/E;AACA,YAAU,QAAQ,qBAAqB,kBAAkB;AAGzD,QAAM,WAAW,gBAAgB,EAAE,WAAW,KAAK,CAAC;AAEpD,QAAM,eAAe,MAAM,UAAU,UAAU,YAAY,eAAe,QAAQ;AAElF,QAAM,aAAa,IAA2B,IAAI;AAElD,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,eAAe,OAAO,QAAQ,eAAe,YAAY;AAC7E,iBAAW,QAAQ,OAAO,WAAW,8BAA8B;AACnE,iBAAW,OAAO,iBAAiB,UAAU,YAAY;AAAA,IAC3D;AAAA,EACF,CAAC;AAED,cAAY,MAAM;AAChB,eAAW,OAAO,oBAAoB,UAAU,YAAY;AAAA,EAC9D,CAAC;AAED,SAAO;AAAA;AAAA,IAEL,WAAW,SAAS;AAAA,MAClB,KAAK,MAAM,UAAU;AAAA,MACrB,KAAK;AAAA,IACP,CAAC;AAAA;AAAA,IAED;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,EACF;AACF;",
6
- "names": []
7
- }