stoop 0.3.0 → 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.
Files changed (65) hide show
  1. package/README.md +125 -0
  2. package/dist/api/core-api.d.ts +34 -0
  3. package/dist/api/styled.d.ts +0 -1
  4. package/dist/api/theme-provider.d.ts +41 -0
  5. package/dist/constants.d.ts +11 -1
  6. package/dist/core/compiler.d.ts +11 -0
  7. package/dist/core/theme-manager.d.ts +34 -3
  8. package/dist/create-stoop-internal.d.ts +30 -0
  9. package/dist/create-stoop-ssr.d.ts +10 -0
  10. package/dist/create-stoop-ssr.js +16 -0
  11. package/dist/create-stoop.d.ts +32 -1
  12. package/dist/create-stoop.js +16 -147
  13. package/dist/inject.d.ts +113 -0
  14. package/dist/types/index.d.ts +147 -12
  15. package/dist/types/react-polymorphic-types.d.ts +13 -2
  16. package/dist/utils/auto-preload.d.ts +45 -0
  17. package/dist/utils/helpers.d.ts +64 -0
  18. package/dist/utils/storage.d.ts +148 -0
  19. package/dist/utils/{string.d.ts → theme-utils.d.ts} +20 -3
  20. package/dist/utils/theme.d.ts +14 -2
  21. package/package.json +44 -17
  22. package/dist/api/create-theme.d.ts +0 -13
  23. package/dist/api/create-theme.js +0 -43
  24. package/dist/api/css.d.ts +0 -16
  25. package/dist/api/css.js +0 -20
  26. package/dist/api/global-css.js +0 -89
  27. package/dist/api/keyframes.d.ts +0 -16
  28. package/dist/api/keyframes.js +0 -95
  29. package/dist/api/provider.d.ts +0 -19
  30. package/dist/api/provider.js +0 -109
  31. package/dist/api/styled.js +0 -170
  32. package/dist/api/use-theme.d.ts +0 -13
  33. package/dist/api/use-theme.js +0 -21
  34. package/dist/constants.js +0 -144
  35. package/dist/core/cache.js +0 -68
  36. package/dist/core/compiler.js +0 -198
  37. package/dist/core/theme-manager.js +0 -97
  38. package/dist/core/variants.js +0 -32
  39. package/dist/create-stoop-server.d.ts +0 -33
  40. package/dist/create-stoop-server.js +0 -130
  41. package/dist/index.d.ts +0 -6
  42. package/dist/index.js +0 -5
  43. package/dist/inject/browser.d.ts +0 -58
  44. package/dist/inject/browser.js +0 -149
  45. package/dist/inject/dedup.d.ts +0 -29
  46. package/dist/inject/dedup.js +0 -38
  47. package/dist/inject/index.d.ts +0 -40
  48. package/dist/inject/index.js +0 -75
  49. package/dist/inject/ssr.d.ts +0 -27
  50. package/dist/inject/ssr.js +0 -46
  51. package/dist/ssr.d.ts +0 -21
  52. package/dist/ssr.js +0 -19
  53. package/dist/types/index.js +0 -5
  54. package/dist/utils/environment.d.ts +0 -6
  55. package/dist/utils/environment.js +0 -12
  56. package/dist/utils/string.js +0 -253
  57. package/dist/utils/theme-map.d.ts +0 -22
  58. package/dist/utils/theme-map.js +0 -97
  59. package/dist/utils/theme-validation.d.ts +0 -13
  60. package/dist/utils/theme-validation.js +0 -36
  61. package/dist/utils/theme.js +0 -279
  62. package/dist/utils/type-guards.d.ts +0 -26
  63. package/dist/utils/type-guards.js +0 -38
  64. package/dist/utils/utilities.d.ts +0 -14
  65. package/dist/utils/utilities.js +0 -43
@@ -1,19 +0,0 @@
1
- /**
2
- * Theme Provider component.
3
- * Manages theme state, localStorage persistence, and centralized theme variable updates.
4
- */
5
- import { type ComponentType, type Context } from "react";
6
- import type { ProviderProps, Theme, ThemeContextValue, ThemeManagementContextValue } from "../types";
7
- /**
8
- * Creates a Provider component for theme management.
9
- *
10
- * @param themes - Map of theme names to theme objects
11
- * @param defaultTheme - Default theme object
12
- * @param prefix - Optional prefix for CSS variable scoping
13
- * @returns Provider component, theme context, and theme management context
14
- */
15
- export declare function createProvider(themes: Record<string, Theme>, defaultTheme: Theme, prefix?: string): {
16
- Provider: ComponentType<ProviderProps>;
17
- ThemeContext: Context<ThemeContextValue | null>;
18
- ThemeManagementContext: Context<ThemeManagementContextValue | null>;
19
- };
@@ -1,109 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- /**
4
- * Theme Provider component.
5
- * Manages theme state, localStorage persistence, and centralized theme variable updates.
6
- */
7
- import { createContext, useCallback, useLayoutEffect, useMemo, useState, } from "react";
8
- import { updateThemeVariables } from "../core/theme-manager";
9
- import { isBrowser } from "../utils/environment";
10
- /**
11
- * Creates a Provider component for theme management.
12
- *
13
- * @param themes - Map of theme names to theme objects
14
- * @param defaultTheme - Default theme object
15
- * @param prefix - Optional prefix for CSS variable scoping
16
- * @returns Provider component, theme context, and theme management context
17
- */
18
- export function createProvider(themes, defaultTheme, prefix = "stoop") {
19
- const ThemeContext = createContext(null);
20
- const ThemeManagementContext = createContext(null);
21
- const availableThemeNames = Object.keys(themes);
22
- const firstThemeName = availableThemeNames[0] || "default";
23
- function Provider({ attribute = "data-theme", children, defaultTheme: defaultThemeProp, storageKey = "stoop-theme", }) {
24
- // SSR-safe initialization: always start with default, then hydrate from localStorage
25
- const [themeName, setThemeNameState] = useState(() => {
26
- // During SSR, always return the default theme
27
- if (!isBrowser()) {
28
- return defaultThemeProp || firstThemeName;
29
- }
30
- // On client, try to read from localStorage
31
- try {
32
- const stored = localStorage.getItem(storageKey);
33
- if (stored && themes[stored]) {
34
- return stored;
35
- }
36
- }
37
- catch {
38
- // localStorage access failed (e.g., in private browsing mode)
39
- }
40
- return defaultThemeProp || firstThemeName;
41
- });
42
- // Hydrate from localStorage after mount to prevent hydration mismatch
43
- useLayoutEffect(() => {
44
- if (!isBrowser()) {
45
- return;
46
- }
47
- try {
48
- const stored = localStorage.getItem(storageKey);
49
- if (stored && themes[stored] && stored !== themeName) {
50
- setThemeNameState(stored);
51
- }
52
- }
53
- catch {
54
- // localStorage access failed
55
- }
56
- }, [storageKey, themeName]);
57
- const currentTheme = useMemo(() => {
58
- return themes[themeName] || themes[defaultThemeProp || firstThemeName] || defaultTheme;
59
- }, [themeName, defaultThemeProp, firstThemeName, themes]);
60
- useLayoutEffect(() => {
61
- if (currentTheme) {
62
- updateThemeVariables(currentTheme, prefix);
63
- }
64
- }, [currentTheme, prefix]);
65
- useLayoutEffect(() => {
66
- if (isBrowser() && attribute) {
67
- document.documentElement.setAttribute(attribute, themeName);
68
- }
69
- }, [themeName, attribute]);
70
- const setTheme = useCallback((newThemeName) => {
71
- if (themes[newThemeName]) {
72
- setThemeNameState(newThemeName);
73
- try {
74
- localStorage.setItem(storageKey, newThemeName);
75
- }
76
- catch {
77
- // localStorage access failed (e.g., in private browsing mode)
78
- }
79
- }
80
- else if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
81
- // eslint-disable-next-line no-console
82
- console.warn(`[Stoop] Theme "${newThemeName}" not found. Available themes: ${availableThemeNames.join(", ")}`);
83
- }
84
- }, [storageKey, themes, availableThemeNames]);
85
- const themeContextValue = useMemo(() => ({
86
- theme: currentTheme,
87
- themeName,
88
- }), [currentTheme, themeName]);
89
- const toggleTheme = useCallback(() => {
90
- const currentIndex = availableThemeNames.indexOf(themeName);
91
- const nextIndex = (currentIndex + 1) % availableThemeNames.length;
92
- const newTheme = availableThemeNames[nextIndex];
93
- setTheme(newTheme);
94
- }, [themeName, setTheme]);
95
- const managementContextValue = useMemo(() => ({
96
- availableThemes: availableThemeNames,
97
- setTheme,
98
- theme: currentTheme,
99
- themeName,
100
- toggleTheme,
101
- }), [currentTheme, themeName, setTheme, toggleTheme]);
102
- return (_jsx(ThemeContext.Provider, { value: themeContextValue, children: _jsx(ThemeManagementContext.Provider, { value: managementContextValue, children: children }) }));
103
- }
104
- return {
105
- Provider,
106
- ThemeContext,
107
- ThemeManagementContext,
108
- };
109
- }
@@ -1,170 +0,0 @@
1
- "use client";
2
- /**
3
- * Styled component API.
4
- * Creates polymorphic styled components with variant support, theme awareness,
5
- * and CSS prop merging. Supports component targeting via selector references.
6
- */
7
- import { useMemo, forwardRef, createElement, useContext, createContext, } from "react";
8
- import { EMPTY_CSS, STOOP_COMPONENT_SYMBOL } from "../constants";
9
- import { compileCSS } from "../core/compiler";
10
- import { applyVariants } from "../core/variants";
11
- import { hash, sanitizeClassName } from "../utils/string";
12
- let defaultThemeContext = null;
13
- function getDefaultThemeContext() {
14
- if (!defaultThemeContext) {
15
- defaultThemeContext = createContext(null);
16
- }
17
- return defaultThemeContext;
18
- }
19
- /**
20
- * Creates a styled component reference for selector targeting.
21
- *
22
- * @param className - Class name to reference
23
- * @returns StyledComponentRef for use in CSS selectors
24
- */
25
- export function createStyledComponentRef(className) {
26
- const ref = {
27
- __isStoopStyled: true,
28
- __stoopClassName: className,
29
- [STOOP_COMPONENT_SYMBOL]: className,
30
- toString: () => `__STOOP_COMPONENT_${className}`,
31
- };
32
- return ref;
33
- }
34
- /**
35
- * Type guard for styled component references.
36
- *
37
- * @param value - Value to check
38
- * @returns True if value is a styled component reference
39
- */
40
- function isStyledComponent(value) {
41
- return (typeof value === "object" &&
42
- value !== null &&
43
- "__isStoopStyled" in value &&
44
- value.__isStoopStyled === true);
45
- }
46
- /**
47
- * Separates component props into variant props and element props.
48
- * Variant props are used for style variants, element props are passed to the DOM element.
49
- *
50
- * @param props - All component props
51
- * @param variants - Variant configuration
52
- * @returns Object with separated elementProps and variantProps
53
- */
54
- function extractVariantProps(props, variants) {
55
- if (!variants) {
56
- return { elementProps: props, variantProps: {} };
57
- }
58
- const variantKeys = new Set(Object.keys(variants));
59
- const variantProps = {};
60
- const elementProps = {};
61
- for (const key in props) {
62
- if (variantKeys.has(key)) {
63
- variantProps[key] = props[key];
64
- }
65
- else {
66
- elementProps[key] = props[key];
67
- }
68
- }
69
- return { elementProps, variantProps };
70
- }
71
- /**
72
- * Creates a styled component factory function.
73
- * Supports polymorphic components, variants, theme awareness, and CSS prop merging.
74
- *
75
- * @param defaultTheme - Default theme for token resolution
76
- * @param prefix - Optional prefix for generated class names
77
- * @param media - Optional media query breakpoints
78
- * @param utils - Optional utility functions
79
- * @param themeMap - Optional theme scale mappings
80
- * @param themeContext - React context for theme values (instance-specific)
81
- * @returns Styled component factory function
82
- */
83
- export function createStyledFunction(defaultTheme, prefix = "stoop", media, utils, themeMap, themeContext) {
84
- return function styled(defaultElement, baseStylesOrVariants, variantsParam) {
85
- let actualBaseStyles = (baseStylesOrVariants || EMPTY_CSS);
86
- let actualVariants = variantsParam;
87
- if (baseStylesOrVariants &&
88
- "variants" in baseStylesOrVariants &&
89
- typeof baseStylesOrVariants.variants === "object") {
90
- actualVariants = baseStylesOrVariants.variants;
91
- const { compoundVariants: __, variants: _, ...rest } = baseStylesOrVariants;
92
- actualBaseStyles = rest;
93
- }
94
- let baseElementClassName;
95
- if (typeof defaultElement !== "string" && isStyledComponent(defaultElement)) {
96
- baseElementClassName = defaultElement.__stoopClassName;
97
- }
98
- const StyledComponent = forwardRef(function StyledComponent(propsWithBase, ref) {
99
- const { as, className, css: cssStyles, ...restProps } = propsWithBase;
100
- const element = (as || defaultElement);
101
- const cssObject = useMemo(() => cssStyles && typeof cssStyles === "object" && cssStyles !== null
102
- ? cssStyles
103
- : EMPTY_CSS, [cssStyles]);
104
- const { elementProps, variantProps } = extractVariantProps(restProps, actualVariants);
105
- const contextValue = useContext(themeContext || getDefaultThemeContext());
106
- const currentTheme = contextValue?.theme || defaultTheme;
107
- const currentMedia = currentTheme.media ? { ...media, ...currentTheme.media } : media;
108
- const variantKey = useMemo(() => {
109
- if (!actualVariants) {
110
- return "";
111
- }
112
- const variantEntries = Object.entries(variantProps);
113
- if (variantEntries.length === 0) {
114
- return "";
115
- }
116
- return variantEntries
117
- .sort(([a], [b]) => a.localeCompare(b))
118
- .map(([key, value]) => `${key}:${String(value)}`)
119
- .join("|");
120
- }, [variantProps]);
121
- const finalStyles = useMemo(() => {
122
- let componentStyles = actualBaseStyles;
123
- if (actualVariants && variantKey) {
124
- componentStyles = applyVariants(actualVariants, variantProps, actualBaseStyles);
125
- }
126
- if (cssObject !== EMPTY_CSS) {
127
- componentStyles = Object.assign({}, componentStyles, cssObject);
128
- }
129
- return componentStyles;
130
- }, [variantKey, cssObject, actualBaseStyles, actualVariants, variantProps]);
131
- const finalClassName = useMemo(() => {
132
- const classNames = [];
133
- if (baseElementClassName) {
134
- classNames.push(baseElementClassName);
135
- }
136
- const mergedClass = compileCSS(finalStyles, currentTheme, prefix, currentMedia, utils, themeMap);
137
- if (mergedClass) {
138
- classNames.push(mergedClass);
139
- }
140
- if (className) {
141
- const classNameStr = typeof className === "string" ? className : String(className);
142
- const sanitizedClassName = sanitizeClassName(classNameStr);
143
- if (sanitizedClassName) {
144
- classNames.push(sanitizedClassName);
145
- }
146
- }
147
- return classNames.length > 0 ? classNames.join(" ") : undefined;
148
- }, [
149
- finalStyles,
150
- className,
151
- baseElementClassName,
152
- currentTheme,
153
- prefix,
154
- currentMedia,
155
- utils,
156
- themeMap,
157
- ]);
158
- return createElement(element, {
159
- ...elementProps,
160
- className: finalClassName,
161
- ref,
162
- });
163
- });
164
- const selectorHash = hash(JSON.stringify(actualBaseStyles));
165
- const selectorClassName = `${prefix}-${selectorHash}`;
166
- const componentWithSelector = StyledComponent;
167
- componentWithSelector.selector = createStyledComponentRef(selectorClassName);
168
- return componentWithSelector;
169
- };
170
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * Theme management hook.
3
- * Provides access to theme state and theme switching functions.
4
- */
5
- import { type Context } from "react";
6
- import type { ThemeManagementContextValue } from "../types";
7
- /**
8
- * Creates a useTheme hook for a specific theme management context.
9
- *
10
- * @param ThemeManagementContext - React context for theme management
11
- * @returns Hook function that returns theme management context value
12
- */
13
- export declare function createUseThemeHook(ThemeManagementContext: Context<ThemeManagementContextValue | null>): () => ThemeManagementContextValue;
@@ -1,21 +0,0 @@
1
- "use client";
2
- /**
3
- * Theme management hook.
4
- * Provides access to theme state and theme switching functions.
5
- */
6
- import { useContext } from "react";
7
- /**
8
- * Creates a useTheme hook for a specific theme management context.
9
- *
10
- * @param ThemeManagementContext - React context for theme management
11
- * @returns Hook function that returns theme management context value
12
- */
13
- export function createUseThemeHook(ThemeManagementContext) {
14
- return function useTheme() {
15
- const context = useContext(ThemeManagementContext);
16
- if (!context) {
17
- throw new Error("useTheme must be used within a Provider");
18
- }
19
- return context;
20
- };
21
- }
package/dist/constants.js DELETED
@@ -1,144 +0,0 @@
1
- /**
2
- * Shared constants used throughout the library.
3
- * Includes cache size limits and nesting depth limits.
4
- */
5
- export const EMPTY_CSS = Object.freeze({});
6
- export const MAX_CSS_CACHE_SIZE = 10000;
7
- export const MAX_CLASS_NAME_CACHE_SIZE = 5000;
8
- export const MAX_CSS_NESTING_DEPTH = 10;
9
- /**
10
- * Approved theme scales - only these scales are allowed in theme objects.
11
- */
12
- export const APPROVED_THEME_SCALES = [
13
- "colors",
14
- "opacities",
15
- "space",
16
- "radii",
17
- "sizes",
18
- "fonts",
19
- "fontWeights",
20
- "fontSizes",
21
- "lineHeights",
22
- "letterSpacings",
23
- "shadows",
24
- "zIndices",
25
- "transitions",
26
- ];
27
- /**
28
- * Default themeMap mapping CSS properties to theme scales.
29
- * Covers 150+ common CSS properties for zero-config experience.
30
- * Missing properties gracefully fallback to pattern-based auto-detection.
31
- */
32
- export const DEFAULT_THEME_MAP = {
33
- accentColor: "colors",
34
- animation: "transitions",
35
- animationDelay: "transitions",
36
- animationDuration: "transitions",
37
- animationTimingFunction: "transitions",
38
- backdropFilter: "shadows",
39
- background: "colors",
40
- backgroundColor: "colors",
41
- blockSize: "sizes",
42
- border: "colors",
43
- borderBlockColor: "colors",
44
- borderBlockEndColor: "colors",
45
- borderBlockStartColor: "colors",
46
- borderBottomColor: "colors",
47
- borderBottomLeftRadius: "radii",
48
- borderBottomRightRadius: "radii",
49
- borderColor: "colors",
50
- borderEndEndRadius: "radii",
51
- borderEndStartRadius: "radii",
52
- borderInlineColor: "colors",
53
- borderInlineEndColor: "colors",
54
- borderInlineStartColor: "colors",
55
- borderLeftColor: "colors",
56
- borderRadius: "radii",
57
- borderRightColor: "colors",
58
- borderStartEndRadius: "radii",
59
- borderStartStartRadius: "radii",
60
- borderTopColor: "colors",
61
- borderTopLeftRadius: "radii",
62
- borderTopRightRadius: "radii",
63
- bottom: "space",
64
- boxShadow: "shadows",
65
- caretColor: "colors",
66
- color: "colors",
67
- columnGap: "space",
68
- columnRuleColor: "colors",
69
- fill: "colors",
70
- filter: "shadows",
71
- flexBasis: "sizes",
72
- floodColor: "colors",
73
- font: "fontSizes",
74
- fontFamily: "fonts",
75
- fontSize: "fontSizes",
76
- fontWeight: "fontWeights",
77
- gap: "space",
78
- gridColumnGap: "space",
79
- gridGap: "space",
80
- gridRowGap: "space",
81
- height: "sizes",
82
- inlineSize: "sizes",
83
- inset: "space",
84
- insetBlock: "space",
85
- insetBlockEnd: "space",
86
- insetBlockStart: "space",
87
- insetInline: "space",
88
- insetInlineEnd: "space",
89
- insetInlineStart: "space",
90
- left: "space",
91
- letterSpacing: "letterSpacings",
92
- lightingColor: "colors",
93
- lineHeight: "lineHeights",
94
- margin: "space",
95
- marginBlock: "space",
96
- marginBlockEnd: "space",
97
- marginBlockStart: "space",
98
- marginBottom: "space",
99
- marginInline: "space",
100
- marginInlineEnd: "space",
101
- marginInlineStart: "space",
102
- marginLeft: "space",
103
- marginRight: "space",
104
- marginTop: "space",
105
- maxBlockSize: "sizes",
106
- maxHeight: "sizes",
107
- maxInlineSize: "sizes",
108
- maxWidth: "sizes",
109
- minBlockSize: "sizes",
110
- minHeight: "sizes",
111
- minInlineSize: "sizes",
112
- minWidth: "sizes",
113
- opacity: "opacities",
114
- outline: "colors",
115
- outlineColor: "colors",
116
- padding: "space",
117
- paddingBlock: "space",
118
- paddingBlockEnd: "space",
119
- paddingBlockStart: "space",
120
- paddingBottom: "space",
121
- paddingInline: "space",
122
- paddingInlineEnd: "space",
123
- paddingInlineStart: "space",
124
- paddingLeft: "space",
125
- paddingRight: "space",
126
- paddingTop: "space",
127
- right: "space",
128
- rowGap: "space",
129
- size: "sizes",
130
- stopColor: "colors",
131
- stroke: "colors",
132
- textDecorationColor: "colors",
133
- textEmphasisColor: "colors",
134
- textShadow: "shadows",
135
- top: "space",
136
- transition: "transitions",
137
- transitionDelay: "transitions",
138
- transitionDuration: "transitions",
139
- transitionProperty: "transitions",
140
- transitionTimingFunction: "transitions",
141
- width: "sizes",
142
- zIndex: "zIndices",
143
- };
144
- export const STOOP_COMPONENT_SYMBOL = Symbol.for("stoop.component");
@@ -1,68 +0,0 @@
1
- /**
2
- * CSS compilation caching system.
3
- * Tracks compiled CSS strings and class names to prevent duplicate work.
4
- * Implements LRU (Least Recently Used) eviction when cache size limits are exceeded.
5
- */
6
- import { MAX_CLASS_NAME_CACHE_SIZE, MAX_CSS_CACHE_SIZE } from "../constants";
7
- /**
8
- * LRU Cache implementation for class names and CSS strings.
9
- * Automatically evicts least recently used entries when size limit is exceeded.
10
- */
11
- export class LRUCache extends Map {
12
- maxSize;
13
- constructor(maxSize) {
14
- super();
15
- this.maxSize = maxSize;
16
- }
17
- get(key) {
18
- const value = super.get(key);
19
- if (value !== undefined) {
20
- super.delete(key);
21
- super.set(key, value);
22
- }
23
- return value;
24
- }
25
- set(key, value) {
26
- if (super.has(key)) {
27
- super.delete(key);
28
- }
29
- else if (this.size >= this.maxSize) {
30
- const firstKey = this.keys().next().value;
31
- if (firstKey !== undefined) {
32
- super.delete(firstKey);
33
- }
34
- }
35
- super.set(key, value);
36
- return this;
37
- }
38
- }
39
- export const classNameCache = new LRUCache(MAX_CLASS_NAME_CACHE_SIZE);
40
- export const cssStringCache = new LRUCache(MAX_CSS_CACHE_SIZE);
41
- // Separate cache for tracking injected CSS strings (used by browser injection)
42
- const injectedStylesCache = new Set();
43
- /**
44
- * Checks if a CSS string has been injected.
45
- * Uses a Set for O(1) lookup.
46
- *
47
- * @param css - CSS string to check
48
- * @returns True if CSS has been injected
49
- */
50
- export function isCachedStyle(css) {
51
- return injectedStylesCache.has(css);
52
- }
53
- /**
54
- * Marks a CSS string as injected.
55
- *
56
- * @param css - CSS string to cache
57
- */
58
- export function markStyleAsCached(css) {
59
- injectedStylesCache.add(css);
60
- }
61
- /**
62
- * Clears all cached styles.
63
- */
64
- export function clearStyleCache() {
65
- classNameCache.clear();
66
- cssStringCache.clear();
67
- injectedStylesCache.clear();
68
- }