@luciodale/swipe-bar 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,298 @@
1
+ # SwipeBar
2
+
3
+ <div align="center">
4
+ <img src="https://raw.githubusercontent.com/luciodale/swipe-bar/main/packages/docs/public/logo.svg" alt="SwipeBar Logo" width="200" height="200" />
5
+ </div>
6
+
7
+ <div align="center">
8
+
9
+ [📖 Documentation](#) • [🎮 Live Demo](#) • [📦 NPM Package](https://www.npmjs.com/package/@luciodale/swipe-bar)
10
+
11
+ </div>
12
+
13
+ ## A native swipe bar experience
14
+
15
+ SwipeBar provides an intuitive, native-app-like experience for mobile and desktop sidebars. Swipe from the edge to open, drag to close, and enjoy smooth animations with full customization control.
16
+
17
+ ## Features
18
+
19
+ - 📦 **Lightweight** - zero dependencies
20
+ - 📱 **Native Mobile Gestures** - Swipe from screen edges just like native apps
21
+ - 🖱️ **Desktop Support** - Works seamlessly with mouse interactions
22
+ - 🎨 **Fully Customizable** - Complete control over styling, animations, and behavior
23
+ - 🎯 **Smart Positioning** - Automatically adapts between absolute and relative positioning
24
+ - 🎭 **Custom Toggles** - Use built-in toggle icons or provide your own components
25
+ - ⚡ **Performant** - Relies on transform and opacity properties
26
+ - 🎚️ **Configurable Thresholds** - Fine-tune edge activation and drag sensitivity
27
+ - 🌓 **Overlay Support** - Optional backdrop overlay with customizable colors
28
+ - 📏 **Responsive** - Media query support for different screen sizes
29
+ - 🔧 **Programmatic Control** - Open and close sidebars from anywhere in your app
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install @luciodale/swipe-bar
35
+ # or
36
+ yarn add @luciodale/swipe-bar
37
+ # or
38
+ bun add @luciodale/swipe-bar
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ### 1. Install
44
+
45
+ ```bash
46
+ npm install @luciodale/swipe-bar
47
+ ```
48
+
49
+ ### 2. Add the Provider
50
+
51
+ Wrap your app with `SwipeBarProvider`:
52
+
53
+ ```tsx
54
+ import { SwipeBarProvider } from "@luciodale/swipe-bar";
55
+
56
+ function App() {
57
+ return (
58
+ <SwipeBarProvider>
59
+ {/* Your app content */}
60
+ </SwipeBarProvider>
61
+ );
62
+ }
63
+ ```
64
+
65
+ ### 3. Add Left Sidebar
66
+
67
+ ```tsx
68
+ import { SwipeBarLeft } from "@luciodale/swipe-bar";
69
+
70
+ <SwipeBarLeft className="bg-blue-500 ...">
71
+ <nav>Your sidebar content</nav>
72
+ </SwipeBarLeft>
73
+ ```
74
+
75
+ ### 4. Add Right Sidebar
76
+
77
+ ```tsx
78
+ import { SwipeBarRight } from "@luciodale/swipe-bar";
79
+
80
+ <SwipeBarRight className="bg-blue-500 ...">
81
+ <div>Settings panel</div>
82
+ </SwipeBarRight>
83
+ ```
84
+
85
+ ### 5. Programmatic Control
86
+
87
+ Use the context hook to control sidebars from anywhere:
88
+
89
+ ```tsx
90
+ import { useSwipeBarContext } from "@luciodale/swipe-bar";
91
+
92
+ function MyComponent() {
93
+ const { openSidebar, closeSidebar, isLeftOpen, isRightOpen } = useSwipeBarContext();
94
+
95
+ return (
96
+ <button onClick={() => openSidebar("left")}>
97
+ Open Left Sidebar
98
+ </button>
99
+ );
100
+ }
101
+ ```
102
+
103
+ ## Props & Configuration
104
+
105
+ ### Provider Props
106
+
107
+ Configure global defaults for all sidebars:
108
+
109
+ ```tsx
110
+ <SwipeBarProvider
111
+ sidebarWidthPx={320}
112
+ transitionMs={200}
113
+ edgeActivationWidthPx={40}
114
+ dragActivationDeltaPx={20}
115
+ showOverlay={true}
116
+ closeSidebarOnOverlayClick={true}
117
+ isAbsolute={false}
118
+ overlayBackgroundColor="rgba(0, 0, 0, 0.5)"
119
+ toggleIconColor="white"
120
+ toggleIconSizePx={40}
121
+ toggleIconEdgeDistancePx={40}
122
+ showToggle={true}
123
+ mediaQueryWidth={640}
124
+ >
125
+ {children}
126
+ </SwipeBarProvider>
127
+ ```
128
+
129
+ ### Sidebar Props
130
+
131
+ Both `SwipeBarLeft` and `SwipeBarRight` accept the same props, which override provider defaults:
132
+
133
+ | Prop | Type | Default | Description |
134
+ |------|------|---------|-------------|
135
+ | `className` | `string` | - | CSS classes for the sidebar container |
136
+ | `ToggleComponent` | `ReactNode` | - | Custom toggle button component |
137
+ | `sidebarWidthPx` | `number` | `320` | Width of the sidebar in pixels |
138
+ | `transitionMs` | `number` | `200` | Animation duration in milliseconds |
139
+ | `edgeActivationWidthPx` | `number` | `40` | Touch zone width from screen edge to activate swipe |
140
+ | `dragActivationDeltaPx` | `number` | `20` | Minimum drag distance to activate sidebar |
141
+ | `showOverlay` | `boolean` | `true` | Show backdrop overlay when sidebar is open |
142
+ | `closeSidebarOnOverlayClick` | `boolean` | `true` | Close sidebar when clicking overlay |
143
+ | `isAbsolute` | `boolean` | `false` | Use absolute positioning (overlay mode) |
144
+ | `overlayBackgroundColor` | `string` | `"rgba(0, 0, 0, 0.5)"` | Overlay background color |
145
+ | `toggleIconColor` | `string` | `"white"` | Color of the built-in toggle icon |
146
+ | `toggleIconSizePx` | `number` | `40` | Size of the toggle icon |
147
+ | `toggleIconEdgeDistancePx` | `number` | `40` | Distance of toggle from screen edge |
148
+ | `showToggle` | `boolean` | `true` | Show the toggle button |
149
+ | `mediaQueryWidth` | `number` | `640` | Max screen width for swipe gestures (in pixels) |
150
+
151
+ ### Context API
152
+
153
+ ```tsx
154
+ const {
155
+ isLeftOpen, // boolean - is left sidebar open
156
+ isRightOpen, // boolean - is right sidebar open
157
+ openSidebar, // (side: "left" | "right") => void
158
+ closeSidebar, // (side: "left" | "right") => void
159
+ globalOptions, // current global options
160
+ setGlobalOptions, // update global options
161
+ } = useSwipeBarContext();
162
+ ```
163
+
164
+ ## Key Concepts
165
+
166
+ ### isAbsolute Mode
167
+
168
+ By default, sidebars push content to the side. Set `isAbsolute={true}` to make sidebars overlay on top of content instead:
169
+
170
+ ```tsx
171
+ <SwipeBarLeft isAbsolute={true}>
172
+ {/* This sidebar will overlay content */}
173
+ </SwipeBarLeft>
174
+ ```
175
+
176
+ **Note:** On mobile (below `mediaQueryWidth`), sidebars automatically switch to absolute positioning for a better mobile experience.
177
+
178
+ ### Media Query Width
179
+
180
+ Control when swipe gestures are enabled based on screen size:
181
+
182
+ ```tsx
183
+ <SwipeBarProvider mediaQueryWidth={640}>
184
+ {/* Swipe gestures only work on screens ≤640px wide */}
185
+ </SwipeBarProvider>
186
+ ```
187
+
188
+ This is useful if you want swipe interactions only on mobile/tablet devices.
189
+
190
+ ### Toggle Button Behavior
191
+
192
+ The built-in toggle button automatically hides when:
193
+ - The sidebar is open AND `closeSidebarOnOverlayClick` is `true`
194
+ - The overlay is visible to handle closing instead
195
+
196
+ ### Custom Toggles
197
+
198
+ Replace the default toggle with your own component:
199
+
200
+ ```tsx
201
+ <SwipeBarLeft
202
+ ToggleComponent={
203
+ <button className="my-custom-toggle">
204
+
205
+ </button>
206
+ }
207
+ >
208
+ {/* content */}
209
+ </SwipeBarLeft>
210
+ ```
211
+
212
+ ## Examples
213
+
214
+ ### Basic Sidebar
215
+
216
+ ```tsx
217
+ import { SwipeBarProvider, SwipeBarLeft } from "@luciodale/swipe-bar";
218
+
219
+ function App() {
220
+ return (
221
+ <SwipeBarProvider>
222
+ <SwipeBarLeft className="bg-gray-800 text-white p-4">
223
+ <h2>Navigation</h2>
224
+ <nav>
225
+ <a href="/">Home</a>
226
+ <a href="/about">About</a>
227
+ <a href="/contact">Contact</a>
228
+ </nav>
229
+ </SwipeBarLeft>
230
+
231
+ <main>
232
+ {/* Your main content */}
233
+ </main>
234
+ </SwipeBarProvider>
235
+ );
236
+ }
237
+ ```
238
+
239
+ ### Glassmorphism Sidebar
240
+
241
+ ```tsx
242
+ <SwipeBarLeft
243
+ className="bg-white/10 backdrop-blur-2xl border-r border-white/20"
244
+ overlayBackgroundColor="rgba(0, 0, 0, 0.3)"
245
+ >
246
+ {/* Glass effect sidebar content */}
247
+ </SwipeBarLeft>
248
+ ```
249
+
250
+ ### Full-Width Mobile Sidebar
251
+
252
+ ```tsx
253
+ <SwipeBarLeft
254
+ sidebarWidthPx={window.innerWidth}
255
+ isAbsolute={true}
256
+ >
257
+ {/* Full screen mobile menu */}
258
+ </SwipeBarLeft>
259
+ ```
260
+
261
+ ### Programmatic Control
262
+
263
+ ```tsx
264
+ function Header() {
265
+ const { openSidebar } = useSwipeBarContext();
266
+
267
+ return (
268
+ <header>
269
+ <button onClick={() => openSidebar("left")}>Menu</button>
270
+ <h1>My App</h1>
271
+ <button onClick={() => openSidebar("right")}>Settings</button>
272
+ </header>
273
+ );
274
+ }
275
+ ```
276
+
277
+ ## Browser Support
278
+
279
+ - Chrome/Edge (latest)
280
+ - Firefox (latest)
281
+ - Safari (latest)
282
+ - Mobile Safari (iOS 12+)
283
+ - Chrome Android (latest)
284
+
285
+ Touch events and smooth animations are supported across all modern browsers.
286
+
287
+ ## Contributing
288
+
289
+ Contributions are welcome! Feel free to:
290
+
291
+ - Report bugs
292
+ - Suggest new features
293
+ - Submit pull requests
294
+ - Improve documentation
295
+
296
+ ## License
297
+
298
+ MIT
@@ -0,0 +1,29 @@
1
+ import { ReactNode } from 'react';
2
+ import { TSidebarSide, TSwipeBarOptions } from './swipeSidebarShared';
3
+
4
+ type TLockedSidebar = TSidebarSide | null;
5
+ type TSwipeSidebarContext = {
6
+ lockedSidebar: TLockedSidebar;
7
+ setLockedSidebar: (side: TLockedSidebar) => void;
8
+ leftSidebarRef: React.RefObject<HTMLDivElement | null>;
9
+ rightSidebarRef: React.RefObject<HTMLDivElement | null>;
10
+ isLeftOpen: boolean;
11
+ isRightOpen: boolean;
12
+ openSidebar: (side: TSidebarSide) => void;
13
+ closeSidebar: (side: TSidebarSide) => void;
14
+ dragSidebar: (side: TSidebarSide, translateX: number | null) => void;
15
+ globalOptions: Required<TSwipeBarOptions>;
16
+ setGlobalOptions: (options: Partial<Required<TSwipeBarOptions>>) => void;
17
+ leftSidebarOptions: TSwipeBarOptions;
18
+ rightSidebarOptions: TSwipeBarOptions;
19
+ setLeftSidebarOptions: (options: TSwipeBarOptions) => void;
20
+ setRightSidebarOptions: (options: TSwipeBarOptions) => void;
21
+ leftToggleRef: React.RefObject<HTMLDivElement | null>;
22
+ rightToggleRef: React.RefObject<HTMLDivElement | null>;
23
+ };
24
+ export declare const SwipeSidebarContext: import('react').Context<TSwipeSidebarContext | null>;
25
+ export declare const SwipeBarProvider: ({ children, sidebarWidthPx, transitionMs, edgeActivationWidthPx, dragActivationDeltaPx, showOverlay, closeSidebarOnOverlayClick, isAbsolute, overlayBackgroundColor, toggleIconColor, toggleIconSizePx, toggleIconEdgeDistancePx, showToggle, mediaQueryWidth, }: {
26
+ children: ReactNode;
27
+ } & TSwipeBarOptions) => import("react/jsx-runtime").JSX.Element;
28
+ export {};
29
+ //# sourceMappingURL=SwipeBarProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwipeBarProvider.d.ts","sourceRoot":"","sources":["../src/SwipeBarProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AACf,OAAO,EAWL,KAAK,YAAY,EAGjB,KAAK,gBAAgB,EAKtB,MAAM,sBAAsB,CAAC;AAE9B,KAAK,cAAc,GAAG,YAAY,GAAG,IAAI,CAAC;AAE1C,KAAK,oBAAoB,GAAG;IAC1B,aAAa,EAAE,cAAc,CAAC;IAC9B,gBAAgB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACjD,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACvD,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACxD,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAC3C,WAAW,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACrE,aAAa,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAC1C,gBAAgB,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,KAAK,IAAI,CAAC;IACzE,kBAAkB,EAAE,gBAAgB,CAAC;IACrC,mBAAmB,EAAE,gBAAgB,CAAC;IACtC,qBAAqB,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC3D,sBAAsB,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5D,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACtD,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACxD,CAAC;AAEF,eAAO,MAAM,mBAAmB,sDAE/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,kQAe9B;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,GAAG,gBAAgB,4CA6G5C,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ import { TSwipeBarOptions } from './swipeSidebarShared';
3
+
4
+ type ToggleProps = {
5
+ showToggle?: boolean;
6
+ ToggleComponent?: ReactNode;
7
+ options: Required<TSwipeBarOptions>;
8
+ };
9
+ export declare function ToggleLeft({ options, showToggle, ToggleComponent, }: ToggleProps): import("react/jsx-runtime").JSX.Element | null;
10
+ export {};
11
+ //# sourceMappingURL=ToggleLeft.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleLeft.d.ts","sourceRoot":"","sources":["../src/ToggleLeft.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,sBAAsB,CAAC;AAG9B,KAAK,WAAW,GAAG;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;CACrC,CAAC;AAEF,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,UAAiB,EACjB,eAAe,GAChB,EAAE,WAAW,kDAsCb"}
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ import { TSwipeBarOptions } from './swipeSidebarShared';
3
+
4
+ type ToggleProps = {
5
+ showToggle?: boolean;
6
+ ToggleComponent?: ReactNode;
7
+ options: Required<TSwipeBarOptions>;
8
+ };
9
+ export declare function ToggleRight({ options, showToggle, ToggleComponent, }: ToggleProps): import("react/jsx-runtime").JSX.Element | null;
10
+ export {};
11
+ //# sourceMappingURL=ToggleRight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleRight.d.ts","sourceRoot":"","sources":["../src/ToggleRight.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,sBAAsB,CAAC;AAG9B,KAAK,WAAW,GAAG;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;CACrC,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,UAAiB,EACjB,eAAe,GAChB,EAAE,WAAW,kDAwCb"}
@@ -0,0 +1,10 @@
1
+ type TOverlay = {
2
+ isCollapsed: boolean;
3
+ setCollapsed: () => void;
4
+ closeSidebarOnClick?: boolean;
5
+ overlayBackgroundColor?: string;
6
+ transitionMs?: number;
7
+ };
8
+ export declare function Overlay({ isCollapsed, setCollapsed, closeSidebarOnClick, transitionMs, overlayBackgroundColor, }: TOverlay): import("react/jsx-runtime").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=Overlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Overlay.d.ts","sourceRoot":"","sources":["../../src/components/Overlay.tsx"],"names":[],"mappings":"AAEA,KAAK,QAAQ,GAAG;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,OAAO,CAAC,EACtB,WAAW,EACX,YAAY,EACZ,mBAA0B,EAC1B,YAAY,EACZ,sBAAsB,GACvB,EAAE,QAAQ,2CAmBV"}
@@ -0,0 +1,4 @@
1
+ import { TSwipeSidebar } from '../swipeSidebarShared';
2
+
3
+ export declare function SwipeBarLeft({ className, children, ToggleComponent, ...currentOptions }: TSwipeSidebar): import("react/jsx-runtime").JSX.Element;
4
+ //# sourceMappingURL=SwipeBarLeft.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwipeBarLeft.d.ts","sourceRoot":"","sources":["../../src/components/SwipeBarLeft.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,aAAa,EAInB,MAAM,uBAAuB,CAAC;AAM/B,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,QAAQ,EACR,eAAe,EACf,GAAG,cAAc,EAClB,EAAE,aAAa,2CA0Cf"}
@@ -0,0 +1,4 @@
1
+ import { TSwipeSidebar } from '../swipeSidebarShared';
2
+
3
+ export declare function SwipeBarRight({ className, children, ToggleComponent, ...currentOptions }: TSwipeSidebar): import("react/jsx-runtime").JSX.Element;
4
+ //# sourceMappingURL=SwipeBarRight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwipeBarRight.d.ts","sourceRoot":"","sources":["../../src/components/SwipeBarRight.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,aAAa,EAInB,MAAM,uBAAuB,CAAC;AAM/B,wBAAgB,aAAa,CAAC,EAC5B,SAAS,EACT,QAAQ,EACR,eAAe,EACf,GAAG,cAAc,EAClB,EAAE,aAAa,2CA0Cf"}
@@ -0,0 +1,5 @@
1
+ export declare function ToggleIcon({ size, color }: {
2
+ size: number;
3
+ color: string;
4
+ }): import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=ToggleIcon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleIcon.d.ts","sourceRoot":"","sources":["../../src/components/ToggleIcon.tsx"],"names":[],"mappings":"AAGA,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,2CAqD1E"}
@@ -0,0 +1,9 @@
1
+ export { Overlay } from './components/Overlay';
2
+ export { SwipeBarLeft } from './components/SwipeBarLeft';
3
+ export { SwipeBarRight } from './components/SwipeBarRight';
4
+ export { SwipeBarProvider } from './SwipeBarProvider';
5
+ export { ToggleLeft } from './ToggleLeft';
6
+ export { ToggleRight } from './ToggleRight';
7
+ export { useMediaQuery } from './useMediaQuery';
8
+ export { useSwipeBarContext } from './useSwipeBarContext';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}