@umbra.ui/core 0.1.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.
Files changed (272) hide show
  1. package/dist/components/controls/Dropdown/types.d.ts +5 -0
  2. package/dist/components/controls/Dropdown/types.d.ts.map +1 -0
  3. package/dist/components/controls/Dropdown/types.js +1 -0
  4. package/dist/components/controls/SegmentedControl/types.d.ts +6 -0
  5. package/dist/components/controls/SegmentedControl/types.d.ts.map +1 -0
  6. package/dist/components/controls/SegmentedControl/types.js +1 -0
  7. package/dist/components/dialogs/Alert/types.d.ts +7 -0
  8. package/dist/components/dialogs/Alert/types.d.ts.map +1 -0
  9. package/dist/components/dialogs/Alert/types.js +1 -0
  10. package/dist/components/dialogs/Toast/types.d.ts +34 -0
  11. package/dist/components/dialogs/Toast/types.d.ts.map +1 -0
  12. package/dist/components/dialogs/Toast/types.js +10 -0
  13. package/dist/components/dialogs/Toast/useToast.d.ts +36 -0
  14. package/dist/components/dialogs/Toast/useToast.d.ts.map +1 -0
  15. package/dist/components/dialogs/Toast/useToast.js +90 -0
  16. package/dist/components/indicators/Tooltip/tooltip.d.ts +3 -0
  17. package/dist/components/indicators/Tooltip/tooltip.d.ts.map +1 -0
  18. package/dist/components/indicators/Tooltip/tooltip.js +33 -0
  19. package/dist/components/indicators/Tooltip/types.d.ts +14 -0
  20. package/dist/components/indicators/Tooltip/types.d.ts.map +1 -0
  21. package/dist/components/indicators/Tooltip/types.js +1 -0
  22. package/dist/components/indicators/Tooltip/useTooltip.d.ts +18 -0
  23. package/dist/components/indicators/Tooltip/useTooltip.d.ts.map +1 -0
  24. package/dist/components/indicators/Tooltip/useTooltip.js +57 -0
  25. package/dist/components/inputs/Tags/tag-bar-styles.d.ts +14 -0
  26. package/dist/components/inputs/Tags/tag-bar-styles.d.ts.map +1 -0
  27. package/dist/components/inputs/Tags/tag-bar-styles.js +313 -0
  28. package/dist/components/inputs/Tags/types.d.ts +93 -0
  29. package/dist/components/inputs/Tags/types.d.ts.map +1 -0
  30. package/dist/components/inputs/Tags/types.js +216 -0
  31. package/dist/components/inputs/search/types.d.ts +9 -0
  32. package/dist/components/inputs/search/types.d.ts.map +1 -0
  33. package/dist/components/inputs/search/types.js +1 -0
  34. package/dist/components/navigation/adaptive/types.d.ts +16 -0
  35. package/dist/components/navigation/adaptive/types.d.ts.map +1 -0
  36. package/dist/components/navigation/adaptive/types.js +1 -0
  37. package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts +27 -0
  38. package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts.map +1 -0
  39. package/dist/components/navigation/adaptive/useAdaptiveLayout.js +40 -0
  40. package/dist/components/navigation/adaptive/useBreakpoints.d.ts +6 -0
  41. package/dist/components/navigation/adaptive/useBreakpoints.d.ts.map +1 -0
  42. package/dist/components/navigation/adaptive/useBreakpoints.js +37 -0
  43. package/dist/components/navigation/adaptive/useContainerMonitor.d.ts +93 -0
  44. package/dist/components/navigation/adaptive/useContainerMonitor.d.ts.map +1 -0
  45. package/dist/components/navigation/adaptive/useContainerMonitor.js +145 -0
  46. package/dist/components/navigation/adaptive/useViewAnimation.d.ts +31 -0
  47. package/dist/components/navigation/adaptive/useViewAnimation.d.ts.map +1 -0
  48. package/dist/components/navigation/adaptive/useViewAnimation.js +591 -0
  49. package/dist/components/navigation/adaptive/useViewResize.d.ts +52 -0
  50. package/dist/components/navigation/adaptive/useViewResize.d.ts.map +1 -0
  51. package/dist/components/navigation/adaptive/useViewResize.js +146 -0
  52. package/dist/components/navigation/navstack/useNavigationStack.d.ts +25 -0
  53. package/dist/components/navigation/navstack/useNavigationStack.d.ts.map +1 -0
  54. package/dist/components/navigation/navstack/useNavigationStack.js +133 -0
  55. package/dist/components/navigation/slideover/useSlideoverController.d.ts +20 -0
  56. package/dist/components/navigation/slideover/useSlideoverController.d.ts.map +1 -0
  57. package/dist/components/navigation/slideover/useSlideoverController.js +267 -0
  58. package/dist/components/navigation/splitview/useSplitViewController.d.ts +20 -0
  59. package/dist/components/navigation/splitview/useSplitViewController.d.ts.map +1 -0
  60. package/dist/components/navigation/splitview/useSplitViewController.js +325 -0
  61. package/dist/components/navigation/tabcontroller/types.d.ts +21 -0
  62. package/dist/components/navigation/tabcontroller/types.d.ts.map +1 -0
  63. package/dist/components/navigation/tabcontroller/types.js +1 -0
  64. package/dist/components/navigation/tabcontroller/useTabController.d.ts +5 -0
  65. package/dist/components/navigation/tabcontroller/useTabController.d.ts.map +1 -0
  66. package/dist/components/navigation/tabcontroller/useTabController.js +10 -0
  67. package/dist/components/navigation/types.d.ts +8 -0
  68. package/dist/components/navigation/types.d.ts.map +1 -0
  69. package/dist/components/navigation/types.js +1 -0
  70. package/dist/components/pickers/CollectionPicker/types.d.ts +11 -0
  71. package/dist/components/pickers/CollectionPicker/types.d.ts.map +1 -0
  72. package/dist/components/pickers/CollectionPicker/types.js +1 -0
  73. package/dist/components/pickers/ColorPicker/colors.d.ts +13 -0
  74. package/dist/components/pickers/ColorPicker/colors.d.ts.map +1 -0
  75. package/dist/components/pickers/ColorPicker/colors.js +266 -0
  76. package/dist/components/pickers/FilePicker/types.d.ts +10 -0
  77. package/dist/components/pickers/FilePicker/types.d.ts.map +1 -0
  78. package/dist/components/pickers/FilePicker/types.js +1 -0
  79. package/dist/index.d.ts +91 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +196 -0
  82. package/dist/theme.d.ts +73 -0
  83. package/dist/theme.d.ts.map +1 -0
  84. package/dist/theme.js +279 -0
  85. package/dist/themes/blank.d.ts +7 -0
  86. package/dist/themes/blank.d.ts.map +1 -0
  87. package/dist/themes/blank.js +543 -0
  88. package/dist/themes/crimson-dark.d.ts +4 -0
  89. package/dist/themes/crimson-dark.d.ts.map +1 -0
  90. package/dist/themes/crimson-dark.js +552 -0
  91. package/dist/themes/cyan-light.d.ts +4 -0
  92. package/dist/themes/cyan-light.d.ts.map +1 -0
  93. package/dist/themes/cyan-light.js +552 -0
  94. package/dist/themes/dark.d.ts +4 -0
  95. package/dist/themes/dark.d.ts.map +1 -0
  96. package/dist/themes/dark.js +551 -0
  97. package/dist/themes/gold-dark.d.ts +4 -0
  98. package/dist/themes/gold-dark.d.ts.map +1 -0
  99. package/dist/themes/gold-dark.js +552 -0
  100. package/dist/themes/grass-dark.d.ts +4 -0
  101. package/dist/themes/grass-dark.d.ts.map +1 -0
  102. package/dist/themes/grass-dark.js +552 -0
  103. package/dist/themes/indigo.d.ts +4 -0
  104. package/dist/themes/indigo.d.ts.map +1 -0
  105. package/dist/themes/indigo.js +552 -0
  106. package/dist/themes/light.d.ts +4 -0
  107. package/dist/themes/light.d.ts.map +1 -0
  108. package/dist/themes/light.js +551 -0
  109. package/dist/themes/orange-dark.d.ts +4 -0
  110. package/dist/themes/orange-dark.d.ts.map +1 -0
  111. package/dist/themes/orange-dark.js +551 -0
  112. package/dist/themes/orange-light.d.ts +4 -0
  113. package/dist/themes/orange-light.d.ts.map +1 -0
  114. package/dist/themes/orange-light.js +551 -0
  115. package/package.json +62 -0
  116. package/src/components/controls/Button/Button.vue +417 -0
  117. package/src/components/controls/Button/README.md +348 -0
  118. package/src/components/controls/Button/theme.css +200 -0
  119. package/src/components/controls/Checkbox/Checkbox.vue +164 -0
  120. package/src/components/controls/Checkbox/README.md +441 -0
  121. package/src/components/controls/Checkbox/theme.css +36 -0
  122. package/src/components/controls/Dropdown/Dropdown.vue +476 -0
  123. package/src/components/controls/Dropdown/README.md +370 -0
  124. package/src/components/controls/Dropdown/theme.css +50 -0
  125. package/src/components/controls/Dropdown/types.ts +6 -0
  126. package/src/components/controls/IconButton/IconButton.vue +267 -0
  127. package/src/components/controls/IconButton/README.md +502 -0
  128. package/src/components/controls/IconButton/theme.css +89 -0
  129. package/src/components/controls/Radio/README.md +591 -0
  130. package/src/components/controls/Radio/Radio.vue +89 -0
  131. package/src/components/controls/Radio/theme.css +14 -0
  132. package/src/components/controls/RangeSlider/README.md +608 -0
  133. package/src/components/controls/RangeSlider/RangeSlider.vue +535 -0
  134. package/src/components/controls/RangeSlider/theme.css +80 -0
  135. package/src/components/controls/SegmentedControl/README.md +587 -0
  136. package/src/components/controls/SegmentedControl/SegmentedControl.vue +284 -0
  137. package/src/components/controls/SegmentedControl/theme.css +60 -0
  138. package/src/components/controls/SegmentedControl/types.ts +5 -0
  139. package/src/components/controls/Slider/README.md +627 -0
  140. package/src/components/controls/Slider/Slider.vue +260 -0
  141. package/src/components/controls/Slider/theme.css +74 -0
  142. package/src/components/controls/Stepper/README.md +601 -0
  143. package/src/components/controls/Stepper/Stepper.vue +103 -0
  144. package/src/components/controls/Stepper/theme.css +53 -0
  145. package/src/components/controls/Switch/README.md +667 -0
  146. package/src/components/controls/Switch/Switch.vue +127 -0
  147. package/src/components/controls/Switch/theme.css +42 -0
  148. package/src/components/dialogs/Alert/Alert.vue +218 -0
  149. package/src/components/dialogs/Alert/README.md +450 -0
  150. package/src/components/dialogs/Alert/theme.css +44 -0
  151. package/src/components/dialogs/Alert/types.ts +11 -0
  152. package/src/components/dialogs/Toast/README.md +522 -0
  153. package/src/components/dialogs/Toast/Toast.vue +296 -0
  154. package/src/components/dialogs/Toast/ToastContainer.vue +330 -0
  155. package/src/components/dialogs/Toast/theme.css +44 -0
  156. package/src/components/dialogs/Toast/types.ts +46 -0
  157. package/src/components/dialogs/Toast/useToast.ts +127 -0
  158. package/src/components/indicators/ProgressBar/ProgressBar.vue +98 -0
  159. package/src/components/indicators/ProgressBar/README.md +744 -0
  160. package/src/components/indicators/ProgressBar/theme.css +36 -0
  161. package/src/components/indicators/Tooltip/README.md +723 -0
  162. package/src/components/indicators/Tooltip/TooltipProvider.vue +142 -0
  163. package/src/components/indicators/Tooltip/theme.css +18 -0
  164. package/src/components/indicators/Tooltip/tooltip.ts +48 -0
  165. package/src/components/indicators/Tooltip/types.ts +15 -0
  166. package/src/components/indicators/Tooltip/useTooltip.ts +71 -0
  167. package/src/components/inputs/AutogrowTextView/AutogrowTextView.vue +110 -0
  168. package/src/components/inputs/AutogrowTextView/README.md +643 -0
  169. package/src/components/inputs/AutogrowTextView/theme.css +28 -0
  170. package/src/components/inputs/InputCard/InputCard.vue +600 -0
  171. package/src/components/inputs/InputCard/README.md +636 -0
  172. package/src/components/inputs/InputEmail/InputEmail.vue +698 -0
  173. package/src/components/inputs/InputEmail/README.md +764 -0
  174. package/src/components/inputs/InputNumber/InputNumber.vue +300 -0
  175. package/src/components/inputs/InputNumber/README.md +749 -0
  176. package/src/components/inputs/InputPhone/InputPhone.vue +645 -0
  177. package/src/components/inputs/InputPhone/README.md +636 -0
  178. package/src/components/inputs/InputSecure/InputSecure.vue +646 -0
  179. package/src/components/inputs/InputSecure/README.md +771 -0
  180. package/src/components/inputs/InputText/InputText.vue +225 -0
  181. package/src/components/inputs/InputText/README.md +844 -0
  182. package/src/components/inputs/OTP/OTP.vue +349 -0
  183. package/src/components/inputs/OTP/README.md +736 -0
  184. package/src/components/inputs/OTP/theme.css +50 -0
  185. package/src/components/inputs/StringCapture/README.md +718 -0
  186. package/src/components/inputs/StringCapture/StringCapture.vue +315 -0
  187. package/src/components/inputs/StringCapture/theme.css +86 -0
  188. package/src/components/inputs/Tags/README.md +897 -0
  189. package/src/components/inputs/Tags/TagBar.vue +793 -0
  190. package/src/components/inputs/Tags/TagCreation.vue +219 -0
  191. package/src/components/inputs/Tags/TagPicker.vue +380 -0
  192. package/src/components/inputs/Tags/tag-bar-styles.ts +354 -0
  193. package/src/components/inputs/Tags/theme.css +121 -0
  194. package/src/components/inputs/Tags/types.ts +346 -0
  195. package/src/components/inputs/search/README.md +759 -0
  196. package/src/components/inputs/search/SearchBar.vue +394 -0
  197. package/src/components/inputs/search/SearchResults.vue +310 -0
  198. package/src/components/inputs/search/theme.css +187 -0
  199. package/src/components/inputs/search/types.ts +8 -0
  200. package/src/components/inputs/theme.css +102 -0
  201. package/src/components/menus/ActionMenu/ActionMenu.vue +383 -0
  202. package/src/components/menus/ActionMenu/README.md +825 -0
  203. package/src/components/menus/ActionMenu/theme.css +93 -0
  204. package/src/components/models/Popover/Popover.vue +551 -0
  205. package/src/components/models/Popover/README.md +885 -0
  206. package/src/components/models/Popover/theme.css +52 -0
  207. package/src/components/models/Sheet/README.md +1159 -0
  208. package/src/components/models/Sheet/Sheet.vue +465 -0
  209. package/src/components/models/Sheet/theme.css +72 -0
  210. package/src/components/models/Sidebar/README.md +1228 -0
  211. package/src/components/models/Sidebar/Sidebar.vue +480 -0
  212. package/src/components/models/Sidebar/theme.css +90 -0
  213. package/src/components/navigation/adaptive/AdaptiveLayout.vue +779 -0
  214. package/src/components/navigation/adaptive/AdaptiveLayoutBreadcrumbs.vue +192 -0
  215. package/src/components/navigation/adaptive/AdaptiveLayoutMenuButton.vue +149 -0
  216. package/src/components/navigation/adaptive/README.md +768 -0
  217. package/src/components/navigation/adaptive/types.ts +19 -0
  218. package/src/components/navigation/adaptive/useAdaptiveLayout.ts +89 -0
  219. package/src/components/navigation/adaptive/useBreakpoints.ts +41 -0
  220. package/src/components/navigation/adaptive/useContainerMonitor.ts +214 -0
  221. package/src/components/navigation/adaptive/useViewAnimation.ts +721 -0
  222. package/src/components/navigation/adaptive/useViewResize.ts +211 -0
  223. package/src/components/navigation/navstack/NavigationStack.vue +180 -0
  224. package/src/components/navigation/navstack/README.md +994 -0
  225. package/src/components/navigation/navstack/useNavigationStack.ts +164 -0
  226. package/src/components/navigation/slideover/README.md +1275 -0
  227. package/src/components/navigation/slideover/SlideoverController.vue +287 -0
  228. package/src/components/navigation/slideover/useSlideoverController.ts +320 -0
  229. package/src/components/navigation/splitview/README.md +1115 -0
  230. package/src/components/navigation/splitview/SplitViewController.vue +176 -0
  231. package/src/components/navigation/splitview/useSplitViewController.ts +388 -0
  232. package/src/components/navigation/tabcontroller/README.md +919 -0
  233. package/src/components/navigation/tabcontroller/TabController.vue +307 -0
  234. package/src/components/navigation/tabcontroller/TabItem.vue +57 -0
  235. package/src/components/navigation/tabcontroller/types.ts +24 -0
  236. package/src/components/navigation/tabcontroller/useTabController.ts +18 -0
  237. package/src/components/navigation/theme.css +91 -0
  238. package/src/components/navigation/types.ts +7 -0
  239. package/src/components/pickers/CollectionPicker/CollectionPicker.vue +398 -0
  240. package/src/components/pickers/CollectionPicker/README.md +1115 -0
  241. package/src/components/pickers/CollectionPicker/theme.css +14 -0
  242. package/src/components/pickers/CollectionPicker/types.ts +11 -0
  243. package/src/components/pickers/ColorPicker/ColorPicker.vue +376 -0
  244. package/src/components/pickers/ColorPicker/README.md +1439 -0
  245. package/src/components/pickers/ColorPicker/colors.ts +299 -0
  246. package/src/components/pickers/ColorPicker/theme.css +32 -0
  247. package/src/components/pickers/DatePicker/DatePicker.vue +660 -0
  248. package/src/components/pickers/DatePicker/README.md +1195 -0
  249. package/src/components/pickers/DatePicker/theme.css +22 -0
  250. package/src/components/pickers/FilePicker/FilePicker.vue +534 -0
  251. package/src/components/pickers/FilePicker/README.md +1542 -0
  252. package/src/components/pickers/FilePicker/theme.css +48 -0
  253. package/src/components/pickers/FilePicker/types.ts +10 -0
  254. package/src/components/pickers/IconPicker/IconPicker.vue +327 -0
  255. package/src/components/pickers/IconPicker/README.md +1161 -0
  256. package/src/components/pickers/IconPicker/theme.css +28 -0
  257. package/src/components/pickers/theme.css +82 -0
  258. package/src/components/views/MarkdownViewer/MarkdownViewer.vue +442 -0
  259. package/src/components/views/MarkdownViewer/README.md +833 -0
  260. package/src/components/views/MarkdownViewer/theme.css +130 -0
  261. package/src/index.ts +263 -0
  262. package/src/theme.ts +378 -0
  263. package/src/themes/crimson-dark.ts +556 -0
  264. package/src/themes/cyan-light.ts +556 -0
  265. package/src/themes/dark.ts +557 -0
  266. package/src/themes/gold-dark.ts +556 -0
  267. package/src/themes/grass-dark.ts +556 -0
  268. package/src/themes/indigo.ts +556 -0
  269. package/src/themes/light.ts +557 -0
  270. package/src/themes/orange-dark.ts +557 -0
  271. package/src/themes/orange-light.ts +557 -0
  272. package/src/vue.d.ts +45 -0
@@ -0,0 +1,1159 @@
1
+ # Sheet
2
+
3
+ A flexible and animated sheet component built with Vue 3 Composition API and TypeScript. The Sheet component provides a powerful interface for displaying modal content with smooth slide animations, customizable positioning, and comprehensive backdrop options.
4
+
5
+ ## Installation/Import
6
+
7
+ ```typescript
8
+ import { Sheet } from "@umbra-ui/core";
9
+ import type { SheetProps } from "@umbra-ui/core";
10
+ ```
11
+
12
+ **Dependencies:**
13
+
14
+ - Vue 3.x
15
+ - gsap (for animations)
16
+
17
+ ## Basic Usage
18
+
19
+ ```vue
20
+ <script setup lang="ts">
21
+ import { ref } from "vue";
22
+ import { Sheet, Button } from "@umbra-ui/core";
23
+
24
+ const isSheetOpen = ref(false);
25
+
26
+ const handleOpen = () => {
27
+ console.log("Sheet opened");
28
+ };
29
+
30
+ const handleClose = () => {
31
+ console.log("Sheet closed");
32
+ };
33
+
34
+ const handleBackdropClick = () => {
35
+ console.log("Backdrop clicked");
36
+ };
37
+ </script>
38
+
39
+ <template>
40
+ <div>
41
+ <Button @click="isSheetOpen = true">Open Sheet</Button>
42
+
43
+ <Sheet
44
+ v-model="isSheetOpen"
45
+ side="bottom"
46
+ :dismiss-on-backdrop="true"
47
+ @open="handleOpen"
48
+ @close="handleClose"
49
+ @backdrop-click="handleBackdropClick"
50
+ >
51
+ <div class="sheet-content">
52
+ <h2>Sheet Title</h2>
53
+ <p>This is the sheet content. It can contain any HTML elements.</p>
54
+ <Button @click="isSheetOpen = false">Close</Button>
55
+ </div>
56
+ </Sheet>
57
+ </div>
58
+ </template>
59
+
60
+ <style>
61
+ .sheet-content {
62
+ padding: 2rem;
63
+ min-height: 200px;
64
+ }
65
+ </style>
66
+ ```
67
+
68
+ ## Props
69
+
70
+ | Prop Name | Type | Required | Default | Description |
71
+ | ------------------- | ---------------------------------------- | -------- | --------------- | ---------------------------------------------- |
72
+ | `modelValue` | `boolean` | Yes | - | Controls the open/closed state of the sheet |
73
+ | `side` | `"top" \| "bottom" \| "left" \| "right"` | No | `"bottom"` | The side from which the sheet slides in |
74
+ | `dismissOnBackdrop` | `boolean` | No | `true` | Whether clicking the backdrop closes the sheet |
75
+ | `width` | `string` | No | `"90vw"` | Width of the sheet |
76
+ | `height` | `string` | No | `"50vh"` | Height of the sheet |
77
+ | `maxWidth` | `string` | No | `"540px"` | Maximum width of the sheet |
78
+ | `maxHeight` | `string` | No | `"fit-content"` | Maximum height of the sheet |
79
+ | `animationDuration` | `number` | No | `0.5` | Animation duration in seconds |
80
+ | `animationType` | `"slide" \| "ghost"` | No | `"slide"` | Animation type: slide or ghost |
81
+ | `backdropStyle` | `"blur" \| "dim"` | No | `"blur"` | Backdrop style: blur or dim |
82
+ | `zIndex` | `number` | No | `1000` | Z-index for the sheet |
83
+ | `teleportTo` | `string \| HTMLElement` | No | `"body"` | Teleport target element |
84
+
85
+ ## Events
86
+
87
+ | Event Name | Payload Type | Description |
88
+ | ------------------- | ------------ | ------------------------------------------- |
89
+ | `update:modelValue` | `boolean` | Emitted when the sheet open state changes |
90
+ | `backdrop-click` | `void` | Emitted when the backdrop is clicked |
91
+ | `open` | `void` | Emitted when the sheet opens |
92
+ | `close` | `void` | Emitted when the sheet closes |
93
+ | `after-enter` | `void` | Emitted after the open animation completes |
94
+ | `after-leave` | `void` | Emitted after the close animation completes |
95
+
96
+ ## Slots
97
+
98
+ | Slot Name | Description |
99
+ | --------- | -------------------------------------- |
100
+ | `default` | The content displayed inside the sheet |
101
+
102
+ ## Exposed Methods/Refs
103
+
104
+ The Sheet component exposes the following methods and properties via template refs:
105
+
106
+ | Method/Property | Type | Description |
107
+ | --------------- | -------------- | -------------------------------------- |
108
+ | `open` | `() => void` | Opens the sheet programmatically |
109
+ | `close` | `() => void` | Closes the sheet programmatically |
110
+ | `isVisible` | `Ref<boolean>` | Reactive reference to visibility state |
111
+ | `isAnimating` | `Ref<boolean>` | Reactive reference to animation state |
112
+
113
+ ### Example Usage
114
+
115
+ ```vue
116
+ <script setup lang="ts">
117
+ import { ref } from "vue";
118
+ import { Sheet } from "@umbra-ui/core";
119
+
120
+ const sheetRef = ref<InstanceType<typeof Sheet> | null>(null);
121
+
122
+ const openSheet = () => {
123
+ sheetRef.value?.open();
124
+ };
125
+
126
+ const closeSheet = () => {
127
+ sheetRef.value?.close();
128
+ };
129
+ </script>
130
+
131
+ <template>
132
+ <Sheet ref="sheetRef" :model-value="false">
133
+ <div class="content">
134
+ <p>Sheet content</p>
135
+ <button @click="closeSheet">Close</button>
136
+ </div>
137
+ </Sheet>
138
+ </template>
139
+ ```
140
+
141
+ ## Animation Types
142
+
143
+ ### Slide Animation
144
+
145
+ - **Default animation type**
146
+ - Sheet slides in from the specified side
147
+ - Uses smooth easing with GPU acceleration
148
+ - Best for modal dialogs and forms
149
+
150
+ ### Ghost Animation
151
+
152
+ - Sheet fades in with scale effect
153
+ - More subtle appearance
154
+ - Good for notifications and overlays
155
+ - Uses opacity and scale transforms
156
+
157
+ ## Backdrop Styles
158
+
159
+ ### Blur Backdrop
160
+
161
+ - **Default backdrop style**
162
+ - Semi-transparent with blur effect
163
+ - Modern, iOS-like appearance
164
+ - Uses `backdrop-filter: blur(10px)`
165
+
166
+ ### Dim Backdrop
167
+
168
+ - Simple semi-transparent overlay
169
+ - No blur effect
170
+ - More traditional modal appearance
171
+ - Better performance on older devices
172
+
173
+ ## CSS Customization
174
+
175
+ The Sheet component uses CSS custom properties for theming and customization:
176
+
177
+ ### Light Theme Variables
178
+
179
+ ```css
180
+ /* Sheet colors */
181
+ --sheet-bg: #ffffff;
182
+ --sheet-shadow: rgba(0, 0, 0, 0.1);
183
+ --sheet-inset-shadow: rgba(255, 255, 255, 0.8);
184
+
185
+ /* Sheet backdrop colors */
186
+ --sheet-backdrop-blur-bg: rgba(0, 0, 0, 0.3);
187
+ --sheet-backdrop-dim-bg: rgba(0, 0, 0, 0.7);
188
+
189
+ /* Sheet scrollbar colors */
190
+ --sheet-scrollbar-thumb: rgba(0, 0, 0, 0.2);
191
+ --sheet-scrollbar-thumb-hover: rgba(0, 0, 0, 0.3);
192
+ ```
193
+
194
+ ### Dark Theme Variables
195
+
196
+ ```css
197
+ /* Sheet colors */
198
+ --sheet-bg: #111111;
199
+ --sheet-shadow: rgba(0, 0, 0, 0.21);
200
+ --sheet-inset-shadow: rgba(255, 255, 255, 0.1);
201
+
202
+ /* Sheet backdrop colors */
203
+ --sheet-backdrop-blur-bg: rgba(0, 0, 0, 0.3);
204
+ --sheet-backdrop-dim-bg: rgba(0, 0, 0, 0.85);
205
+
206
+ /* Sheet scrollbar colors */
207
+ --sheet-scrollbar-thumb: rgba(255, 255, 255, 0.2);
208
+ --sheet-scrollbar-thumb-hover: rgba(255, 255, 255, 0.3);
209
+ ```
210
+
211
+ ## Key Features
212
+
213
+ ### Smart Positioning
214
+
215
+ - **Four Directions**: Slide in from top, bottom, left, or right
216
+ - **Responsive Sizing**: Configurable width, height, and max dimensions
217
+ - **Viewport Awareness**: Automatically respects viewport boundaries
218
+ - **Safe Area Support**: Handles mobile device safe areas
219
+
220
+ ### Animation System
221
+
222
+ - **GSAP Animations**: Smooth, performant animations using GSAP
223
+ - **Two Animation Types**: Slide and ghost animations
224
+ - **GPU Acceleration**: Hardware-accelerated transforms
225
+ - **Customizable Duration**: Configurable animation timing
226
+
227
+ ### User Experience
228
+
229
+ - **Backdrop Interaction**: Click backdrop to dismiss (configurable)
230
+ - **Keyboard Support**: Escape key closes sheet
231
+ - **Body Scroll Lock**: Prevents background scrolling when open
232
+ - **Teleport Support**: Renders outside component tree
233
+
234
+ ### Visual Features
235
+
236
+ - **Backdrop Styles**: Blur or dim backdrop options
237
+ - **Custom Scrollbars**: Styled scrollbars for better UX
238
+ - **Shadow Effects**: Subtle shadows and inset highlights
239
+ - **Border Radius**: Rounded corners for modern appearance
240
+
241
+ ## Examples
242
+
243
+ ### Basic Sheet
244
+
245
+ ```vue
246
+ <script setup lang="ts">
247
+ import { ref } from "vue";
248
+ import { Sheet, Button } from "@umbra-ui/core";
249
+
250
+ const isOpen = ref(false);
251
+
252
+ const handleOpen = () => {
253
+ console.log("Sheet opened");
254
+ };
255
+
256
+ const handleClose = () => {
257
+ console.log("Sheet closed");
258
+ };
259
+ </script>
260
+
261
+ <template>
262
+ <div class="basic-sheet">
263
+ <h3>Basic Sheet</h3>
264
+
265
+ <Button @click="isOpen = true">Open Sheet</Button>
266
+
267
+ <Sheet
268
+ v-model="isOpen"
269
+ side="bottom"
270
+ :dismiss-on-backdrop="true"
271
+ @open="handleOpen"
272
+ @close="handleClose"
273
+ >
274
+ <div class="sheet-content">
275
+ <h2>Sheet Title</h2>
276
+ <p>This is a basic sheet with default settings.</p>
277
+ <p>
278
+ It slides in from the bottom and can be dismissed by clicking the
279
+ backdrop.
280
+ </p>
281
+ <div class="actions">
282
+ <Button @click="isOpen = false">Close</Button>
283
+ </div>
284
+ </div>
285
+ </Sheet>
286
+
287
+ <p class="status">Sheet is {{ isOpen ? "open" : "closed" }}</p>
288
+ </div>
289
+ </template>
290
+
291
+ <style module>
292
+ .basic-sheet {
293
+ padding: 2rem;
294
+ border: 1px solid #e0e0e0;
295
+ border-radius: 0.5rem;
296
+ max-width: 400px;
297
+ }
298
+
299
+ .sheet-content {
300
+ padding: 2rem;
301
+ min-height: 200px;
302
+ }
303
+
304
+ .sheet-content h2 {
305
+ margin: 0 0 1rem 0;
306
+ color: #333;
307
+ }
308
+
309
+ .sheet-content p {
310
+ margin: 0 0 1rem 0;
311
+ color: #666;
312
+ line-height: 1.5;
313
+ }
314
+
315
+ .actions {
316
+ display: flex;
317
+ gap: 0.75rem;
318
+ justify-content: flex-end;
319
+ margin-top: 1.5rem;
320
+ }
321
+
322
+ .status {
323
+ margin-top: 1rem;
324
+ color: #666;
325
+ font-size: 0.875rem;
326
+ }
327
+ </style>
328
+ ```
329
+
330
+ ### Different Sides
331
+
332
+ ```vue
333
+ <script setup lang="ts">
334
+ import { ref } from "vue";
335
+ import { Sheet, Button } from "@umbra-ui/core";
336
+
337
+ const sides = ["top", "bottom", "left", "right"];
338
+ const openSheets = ref<Record<string, boolean>>({});
339
+
340
+ const toggleSheet = (side: string) => {
341
+ openSheets.value[side] = !openSheets.value[side];
342
+ };
343
+ </script>
344
+
345
+ <template>
346
+ <div class="sides-demo">
347
+ <h3>Sheet Sides</h3>
348
+ <p>Click the buttons to see different slide directions:</p>
349
+
350
+ <div class="sides-grid">
351
+ <div v-for="side in sides" :key="side" class="side-item">
352
+ <Button @click="toggleSheet(side)" size="small">
353
+ {{ side }}
354
+ </Button>
355
+
356
+ <Sheet
357
+ v-model="openSheets[side]"
358
+ :side="side"
359
+ :dismiss-on-backdrop="true"
360
+ >
361
+ <div class="side-content">
362
+ <h4>{{ side }} Sheet</h4>
363
+ <p>This sheet slides in from the {{ side }}.</p>
364
+ <Button @click="openSheets[side] = false" size="small">
365
+ Close
366
+ </Button>
367
+ </div>
368
+ </Sheet>
369
+ </div>
370
+ </div>
371
+ </div>
372
+ </template>
373
+
374
+ <style module>
375
+ .sides-demo {
376
+ padding: 2rem;
377
+ border: 1px solid #e0e0e0;
378
+ border-radius: 0.5rem;
379
+ max-width: 600px;
380
+ }
381
+
382
+ .sides-grid {
383
+ display: grid;
384
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
385
+ gap: 1rem;
386
+ margin-top: 1rem;
387
+ }
388
+
389
+ .side-item {
390
+ display: flex;
391
+ justify-content: center;
392
+ align-items: center;
393
+ min-height: 60px;
394
+ }
395
+
396
+ .side-content {
397
+ padding: 1.5rem;
398
+ min-height: 150px;
399
+ text-align: center;
400
+ }
401
+
402
+ .side-content h4 {
403
+ margin: 0 0 1rem 0;
404
+ color: #333;
405
+ text-transform: capitalize;
406
+ }
407
+
408
+ .side-content p {
409
+ margin: 0 0 1rem 0;
410
+ color: #666;
411
+ }
412
+ </style>
413
+ ```
414
+
415
+ ### Ghost Animation
416
+
417
+ ```vue
418
+ <script setup lang="ts">
419
+ import { ref } from "vue";
420
+ import { Sheet, Button } from "@umbra-ui/core";
421
+
422
+ const isGhostOpen = ref(false);
423
+ </script>
424
+
425
+ <template>
426
+ <div class="ghost-sheet">
427
+ <h3>Ghost Animation</h3>
428
+ <p>This sheet uses the ghost animation type with scale and fade effects:</p>
429
+
430
+ <Button @click="isGhostOpen = true">Open Ghost Sheet</Button>
431
+
432
+ <Sheet
433
+ v-model="isGhostOpen"
434
+ side="bottom"
435
+ animation-type="ghost"
436
+ :animation-duration="0.4"
437
+ :dismiss-on-backdrop="true"
438
+ >
439
+ <div class="ghost-content">
440
+ <h2>Ghost Sheet</h2>
441
+ <p>This sheet uses the ghost animation type.</p>
442
+ <p>It fades in with a scale effect instead of sliding.</p>
443
+ <div class="features">
444
+ <h4>Features:</h4>
445
+ <ul>
446
+ <li>Scale + opacity animation</li>
447
+ <li>Faster animation duration</li>
448
+ <li>Subtle appearance</li>
449
+ <li>Good for notifications</li>
450
+ </ul>
451
+ </div>
452
+ <div class="actions">
453
+ <Button @click="isGhostOpen = false">Close</Button>
454
+ </div>
455
+ </div>
456
+ </Sheet>
457
+ </div>
458
+ </template>
459
+
460
+ <style module>
461
+ .ghost-sheet {
462
+ padding: 2rem;
463
+ border: 1px solid #e0e0e0;
464
+ border-radius: 0.5rem;
465
+ max-width: 400px;
466
+ }
467
+
468
+ .ghost-content {
469
+ padding: 2rem;
470
+ min-height: 300px;
471
+ }
472
+
473
+ .ghost-content h2 {
474
+ margin: 0 0 1rem 0;
475
+ color: #333;
476
+ }
477
+
478
+ .ghost-content p {
479
+ margin: 0 0 1rem 0;
480
+ color: #666;
481
+ line-height: 1.5;
482
+ }
483
+
484
+ .features {
485
+ margin: 1.5rem 0;
486
+ padding: 1rem;
487
+ background-color: #f8f9fa;
488
+ border-radius: 0.25rem;
489
+ }
490
+
491
+ .features h4 {
492
+ margin: 0 0 0.5rem 0;
493
+ color: #333;
494
+ }
495
+
496
+ .features ul {
497
+ margin: 0;
498
+ padding-left: 1.25rem;
499
+ color: #666;
500
+ }
501
+
502
+ .features li {
503
+ margin-bottom: 0.25rem;
504
+ }
505
+
506
+ .actions {
507
+ display: flex;
508
+ gap: 0.75rem;
509
+ justify-content: flex-end;
510
+ margin-top: 1.5rem;
511
+ }
512
+ </style>
513
+ ```
514
+
515
+ ### Form Sheet
516
+
517
+ ```vue
518
+ <script setup lang="ts">
519
+ import { ref } from "vue";
520
+ import { Sheet, Button } from "@umbra-ui/core";
521
+
522
+ const isFormOpen = ref(false);
523
+ const formData = ref({
524
+ name: "",
525
+ email: "",
526
+ message: "",
527
+ });
528
+
529
+ const handleSubmit = () => {
530
+ console.log("Form submitted:", formData.value);
531
+ isFormOpen.value = false;
532
+ // Reset form
533
+ formData.value = { name: "", email: "", message: "" };
534
+ };
535
+
536
+ const handleCancel = () => {
537
+ isFormOpen.value = false;
538
+ // Reset form
539
+ formData.value = { name: "", email: "", message: "" };
540
+ };
541
+ </script>
542
+
543
+ <template>
544
+ <div class="form-sheet">
545
+ <h3>Form Sheet</h3>
546
+
547
+ <Button @click="isFormOpen = true">Contact Us</Button>
548
+
549
+ <Sheet
550
+ v-model="isFormOpen"
551
+ side="bottom"
552
+ :dismiss-on-backdrop="false"
553
+ height="80vh"
554
+ max-height="600px"
555
+ >
556
+ <div class="form-content">
557
+ <div class="form-header">
558
+ <h2>Contact Form</h2>
559
+ <button @click="handleCancel" class="close-btn">×</button>
560
+ </div>
561
+
562
+ <form @submit.prevent="handleSubmit" class="form">
563
+ <div class="form-group">
564
+ <label for="name">Name</label>
565
+ <input
566
+ id="name"
567
+ v-model="formData.name"
568
+ type="text"
569
+ required
570
+ placeholder="Your name"
571
+ />
572
+ </div>
573
+
574
+ <div class="form-group">
575
+ <label for="email">Email</label>
576
+ <input
577
+ id="email"
578
+ v-model="formData.email"
579
+ type="email"
580
+ required
581
+ placeholder="your@email.com"
582
+ />
583
+ </div>
584
+
585
+ <div class="form-group">
586
+ <label for="message">Message</label>
587
+ <textarea
588
+ id="message"
589
+ v-model="formData.message"
590
+ required
591
+ placeholder="Your message..."
592
+ rows="4"
593
+ ></textarea>
594
+ </div>
595
+
596
+ <div class="form-actions">
597
+ <Button type="button" @click="handleCancel" variant="secondary">
598
+ Cancel
599
+ </Button>
600
+ <Button type="submit">Send Message</Button>
601
+ </div>
602
+ </form>
603
+ </div>
604
+ </Sheet>
605
+ </div>
606
+ </template>
607
+
608
+ <style module>
609
+ .form-sheet {
610
+ padding: 2rem;
611
+ border: 1px solid #e0e0e0;
612
+ border-radius: 0.5rem;
613
+ max-width: 400px;
614
+ }
615
+
616
+ .form-content {
617
+ height: 100%;
618
+ display: flex;
619
+ flex-direction: column;
620
+ }
621
+
622
+ .form-header {
623
+ display: flex;
624
+ justify-content: space-between;
625
+ align-items: center;
626
+ padding: 1.5rem 2rem 1rem;
627
+ border-bottom: 1px solid #e0e0e0;
628
+ }
629
+
630
+ .form-header h2 {
631
+ margin: 0;
632
+ color: #333;
633
+ }
634
+
635
+ .close-btn {
636
+ background: none;
637
+ border: none;
638
+ font-size: 1.5rem;
639
+ cursor: pointer;
640
+ padding: 0;
641
+ width: 32px;
642
+ height: 32px;
643
+ display: flex;
644
+ align-items: center;
645
+ justify-content: center;
646
+ border-radius: 50%;
647
+ color: #666;
648
+ transition: background-color 0.2s;
649
+ }
650
+
651
+ .close-btn:hover {
652
+ background-color: #f0f0f0;
653
+ }
654
+
655
+ .form {
656
+ flex: 1;
657
+ padding: 2rem;
658
+ overflow-y: auto;
659
+ }
660
+
661
+ .form-group {
662
+ margin-bottom: 1.5rem;
663
+ }
664
+
665
+ .form-group label {
666
+ display: block;
667
+ margin-bottom: 0.5rem;
668
+ font-weight: 500;
669
+ color: #333;
670
+ }
671
+
672
+ .form-group input,
673
+ .form-group textarea {
674
+ width: 100%;
675
+ padding: 0.75rem;
676
+ border: 1px solid #ddd;
677
+ border-radius: 0.25rem;
678
+ font-size: 1rem;
679
+ font-family: inherit;
680
+ box-sizing: border-box;
681
+ }
682
+
683
+ .form-group input:focus,
684
+ .form-group textarea:focus {
685
+ outline: none;
686
+ border-color: #007bff;
687
+ box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
688
+ }
689
+
690
+ .form-actions {
691
+ display: flex;
692
+ gap: 0.75rem;
693
+ justify-content: flex-end;
694
+ margin-top: 2rem;
695
+ padding-top: 1rem;
696
+ border-top: 1px solid #e0e0e0;
697
+ }
698
+ </style>
699
+ ```
700
+
701
+ ### Custom Styled Sheet
702
+
703
+ ```vue
704
+ <script setup lang="ts">
705
+ import { ref } from "vue";
706
+ import { Sheet, Button } from "@umbra-ui/core";
707
+
708
+ const isCustomOpen = ref(false);
709
+ </script>
710
+
711
+ <template>
712
+ <div class="custom-sheet">
713
+ <h3>Custom Styled Sheet</h3>
714
+
715
+ <Button @click="isCustomOpen = true" class="custom-trigger">
716
+ Open Custom Sheet
717
+ </Button>
718
+
719
+ <Sheet
720
+ v-model="isCustomOpen"
721
+ side="right"
722
+ :animation-duration="0.6"
723
+ backdrop-style="dim"
724
+ width="400px"
725
+ height="100vh"
726
+ max-width="400px"
727
+ >
728
+ <div class="custom-content">
729
+ <div class="custom-header">
730
+ <h2>Custom Sheet</h2>
731
+ <p>This sheet has custom styling and positioning.</p>
732
+ </div>
733
+
734
+ <div class="custom-body">
735
+ <div class="feature-list">
736
+ <div class="feature-item">
737
+ <div class="feature-icon">🎨</div>
738
+ <div class="feature-text">
739
+ <h4>Custom Colors</h4>
740
+ <p>Gradient backgrounds and custom styling</p>
741
+ </div>
742
+ </div>
743
+
744
+ <div class="feature-item">
745
+ <div class="feature-icon">⚡</div>
746
+ <div class="feature-text">
747
+ <h4>Right Side</h4>
748
+ <p>Slides in from the right side</p>
749
+ </div>
750
+ </div>
751
+
752
+ <div class="feature-item">
753
+ <div class="feature-icon">🔧</div>
754
+ <div class="feature-text">
755
+ <h4>Custom Size</h4>
756
+ <p>Fixed width and full height</p>
757
+ </div>
758
+ </div>
759
+ </div>
760
+ </div>
761
+
762
+ <div class="custom-footer">
763
+ <Button @click="isCustomOpen = false" class="custom-close">
764
+ Close
765
+ </Button>
766
+ </div>
767
+ </div>
768
+ </Sheet>
769
+ </div>
770
+ </template>
771
+
772
+ <style module>
773
+ .custom-sheet {
774
+ padding: 2rem;
775
+ border: 1px solid #e0e0e0;
776
+ border-radius: 0.5rem;
777
+ max-width: 400px;
778
+ }
779
+
780
+ .custom-trigger {
781
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
782
+ color: white;
783
+ border: none;
784
+ padding: 0.75rem 1.5rem;
785
+ border-radius: 0.5rem;
786
+ font-weight: 600;
787
+ transition: transform 0.2s;
788
+ }
789
+
790
+ .custom-trigger:hover {
791
+ transform: translateY(-2px);
792
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
793
+ }
794
+
795
+ .custom-content {
796
+ height: 100%;
797
+ display: flex;
798
+ flex-direction: column;
799
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
800
+ color: white;
801
+ }
802
+
803
+ .custom-header {
804
+ padding: 2rem;
805
+ text-align: center;
806
+ background: rgba(255, 255, 255, 0.1);
807
+ backdrop-filter: blur(10px);
808
+ }
809
+
810
+ .custom-header h2 {
811
+ margin: 0 0 0.5rem 0;
812
+ font-size: 1.5rem;
813
+ }
814
+
815
+ .custom-header p {
816
+ margin: 0;
817
+ opacity: 0.9;
818
+ }
819
+
820
+ .custom-body {
821
+ flex: 1;
822
+ padding: 2rem;
823
+ overflow-y: auto;
824
+ }
825
+
826
+ .feature-list {
827
+ display: flex;
828
+ flex-direction: column;
829
+ gap: 1.5rem;
830
+ }
831
+
832
+ .feature-item {
833
+ display: flex;
834
+ align-items: flex-start;
835
+ gap: 1rem;
836
+ padding: 1rem;
837
+ background: rgba(255, 255, 255, 0.1);
838
+ border-radius: 0.5rem;
839
+ backdrop-filter: blur(5px);
840
+ }
841
+
842
+ .feature-icon {
843
+ font-size: 1.5rem;
844
+ width: 2rem;
845
+ text-align: center;
846
+ }
847
+
848
+ .feature-text h4 {
849
+ margin: 0 0 0.25rem 0;
850
+ font-size: 1rem;
851
+ }
852
+
853
+ .feature-text p {
854
+ margin: 0;
855
+ font-size: 0.875rem;
856
+ opacity: 0.8;
857
+ }
858
+
859
+ .custom-footer {
860
+ padding: 2rem;
861
+ background: rgba(255, 255, 255, 0.1);
862
+ backdrop-filter: blur(10px);
863
+ display: flex;
864
+ justify-content: center;
865
+ }
866
+
867
+ .custom-close {
868
+ background: rgba(255, 255, 255, 0.2);
869
+ color: white;
870
+ border: 1px solid rgba(255, 255, 255, 0.3);
871
+ padding: 0.75rem 2rem;
872
+ border-radius: 0.5rem;
873
+ font-weight: 600;
874
+ transition: all 0.2s;
875
+ }
876
+
877
+ .custom-close:hover {
878
+ background: rgba(255, 255, 255, 0.3);
879
+ transform: translateY(-1px);
880
+ }
881
+
882
+ /* Override sheet CSS variables */
883
+ :global(.custom-sheet) {
884
+ --sheet-bg: transparent;
885
+ --sheet-shadow: none;
886
+ --sheet-inset-shadow: none;
887
+ --sheet-backdrop-dim-bg: rgba(0, 0, 0, 0.8);
888
+ }
889
+ </style>
890
+ ```
891
+
892
+ ### Settings Panel
893
+
894
+ ```vue
895
+ <script setup lang="ts">
896
+ import { ref } from "vue";
897
+ import { Sheet, Button } from "@umbra-ui/core";
898
+
899
+ const isSettingsOpen = ref(false);
900
+ const settings = ref({
901
+ notifications: true,
902
+ darkMode: false,
903
+ autoSave: true,
904
+ language: "en",
905
+ });
906
+
907
+ const handleSave = () => {
908
+ console.log("Settings saved:", settings.value);
909
+ isSettingsOpen.value = false;
910
+ };
911
+ </script>
912
+
913
+ <template>
914
+ <div class="settings-sheet">
915
+ <h3>Settings Panel</h3>
916
+
917
+ <Button @click="isSettingsOpen = true">Open Settings</Button>
918
+
919
+ <Sheet
920
+ v-model="isSettingsOpen"
921
+ side="right"
922
+ width="350px"
923
+ height="100vh"
924
+ max-width="350px"
925
+ :dismiss-on-backdrop="false"
926
+ >
927
+ <div class="settings-content">
928
+ <div class="settings-header">
929
+ <h2>Settings</h2>
930
+ <button @click="isSettingsOpen = false" class="close-btn">×</button>
931
+ </div>
932
+
933
+ <div class="settings-body">
934
+ <div class="setting-group">
935
+ <h3>Preferences</h3>
936
+
937
+ <div class="setting-item">
938
+ <div class="setting-info">
939
+ <h4>Notifications</h4>
940
+ <p>Receive push notifications</p>
941
+ </div>
942
+ <label class="toggle">
943
+ <input v-model="settings.notifications" type="checkbox" />
944
+ <span class="slider"></span>
945
+ </label>
946
+ </div>
947
+
948
+ <div class="setting-item">
949
+ <div class="setting-info">
950
+ <h4>Dark Mode</h4>
951
+ <p>Use dark theme</p>
952
+ </div>
953
+ <label class="toggle">
954
+ <input v-model="settings.darkMode" type="checkbox" />
955
+ <span class="slider"></span>
956
+ </label>
957
+ </div>
958
+
959
+ <div class="setting-item">
960
+ <div class="setting-info">
961
+ <h4>Auto Save</h4>
962
+ <p>Automatically save changes</p>
963
+ </div>
964
+ <label class="toggle">
965
+ <input v-model="settings.autoSave" type="checkbox" />
966
+ <span class="slider"></span>
967
+ </label>
968
+ </div>
969
+ </div>
970
+
971
+ <div class="setting-group">
972
+ <h3>Language</h3>
973
+
974
+ <div class="setting-item">
975
+ <div class="setting-info">
976
+ <h4>Language</h4>
977
+ <p>Select your preferred language</p>
978
+ </div>
979
+ <select v-model="settings.language" class="select">
980
+ <option value="en">English</option>
981
+ <option value="es">Spanish</option>
982
+ <option value="fr">French</option>
983
+ <option value="de">German</option>
984
+ </select>
985
+ </div>
986
+ </div>
987
+ </div>
988
+
989
+ <div class="settings-footer">
990
+ <Button @click="isSettingsOpen = false" variant="secondary">
991
+ Cancel
992
+ </Button>
993
+ <Button @click="handleSave">Save Changes</Button>
994
+ </div>
995
+ </div>
996
+ </Sheet>
997
+ </div>
998
+ </template>
999
+
1000
+ <style module>
1001
+ .settings-sheet {
1002
+ padding: 2rem;
1003
+ border: 1px solid #e0e0e0;
1004
+ border-radius: 0.5rem;
1005
+ max-width: 400px;
1006
+ }
1007
+
1008
+ .settings-content {
1009
+ height: 100%;
1010
+ display: flex;
1011
+ flex-direction: column;
1012
+ }
1013
+
1014
+ .settings-header {
1015
+ display: flex;
1016
+ justify-content: space-between;
1017
+ align-items: center;
1018
+ padding: 1.5rem 2rem 1rem;
1019
+ border-bottom: 1px solid #e0e0e0;
1020
+ }
1021
+
1022
+ .settings-header h2 {
1023
+ margin: 0;
1024
+ color: #333;
1025
+ }
1026
+
1027
+ .close-btn {
1028
+ background: none;
1029
+ border: none;
1030
+ font-size: 1.5rem;
1031
+ cursor: pointer;
1032
+ padding: 0;
1033
+ width: 32px;
1034
+ height: 32px;
1035
+ display: flex;
1036
+ align-items: center;
1037
+ justify-content: center;
1038
+ border-radius: 50%;
1039
+ color: #666;
1040
+ transition: background-color 0.2s;
1041
+ }
1042
+
1043
+ .close-btn:hover {
1044
+ background-color: #f0f0f0;
1045
+ }
1046
+
1047
+ .settings-body {
1048
+ flex: 1;
1049
+ padding: 2rem;
1050
+ overflow-y: auto;
1051
+ }
1052
+
1053
+ .setting-group {
1054
+ margin-bottom: 2rem;
1055
+ }
1056
+
1057
+ .setting-group h3 {
1058
+ margin: 0 0 1rem 0;
1059
+ color: #333;
1060
+ font-size: 1.125rem;
1061
+ }
1062
+
1063
+ .setting-item {
1064
+ display: flex;
1065
+ justify-content: space-between;
1066
+ align-items: center;
1067
+ padding: 1rem 0;
1068
+ border-bottom: 1px solid #f0f0f0;
1069
+ }
1070
+
1071
+ .setting-info h4 {
1072
+ margin: 0 0 0.25rem 0;
1073
+ color: #333;
1074
+ font-size: 1rem;
1075
+ }
1076
+
1077
+ .setting-info p {
1078
+ margin: 0;
1079
+ color: #666;
1080
+ font-size: 0.875rem;
1081
+ }
1082
+
1083
+ .toggle {
1084
+ position: relative;
1085
+ display: inline-block;
1086
+ width: 50px;
1087
+ height: 24px;
1088
+ }
1089
+
1090
+ .toggle input {
1091
+ opacity: 0;
1092
+ width: 0;
1093
+ height: 0;
1094
+ }
1095
+
1096
+ .slider {
1097
+ position: absolute;
1098
+ cursor: pointer;
1099
+ top: 0;
1100
+ left: 0;
1101
+ right: 0;
1102
+ bottom: 0;
1103
+ background-color: #ccc;
1104
+ transition: 0.2s;
1105
+ border-radius: 24px;
1106
+ }
1107
+
1108
+ .slider:before {
1109
+ position: absolute;
1110
+ content: "";
1111
+ height: 18px;
1112
+ width: 18px;
1113
+ left: 3px;
1114
+ bottom: 3px;
1115
+ background-color: white;
1116
+ transition: 0.2s;
1117
+ border-radius: 50%;
1118
+ }
1119
+
1120
+ input:checked + .slider {
1121
+ background-color: #007bff;
1122
+ }
1123
+
1124
+ input:checked + .slider:before {
1125
+ transform: translateX(26px);
1126
+ }
1127
+
1128
+ .select {
1129
+ padding: 0.5rem;
1130
+ border: 1px solid #ddd;
1131
+ border-radius: 0.25rem;
1132
+ background-color: white;
1133
+ color: #333;
1134
+ }
1135
+
1136
+ .settings-footer {
1137
+ display: flex;
1138
+ gap: 0.75rem;
1139
+ justify-content: flex-end;
1140
+ padding: 1.5rem 2rem;
1141
+ border-top: 1px solid #e0e0e0;
1142
+ }
1143
+ </style>
1144
+ ```
1145
+
1146
+ ## Technical Notes
1147
+
1148
+ - Sheet provides a comprehensive modal system with smooth animations and flexible positioning
1149
+ - GSAP animations ensure smooth, performant transitions with hardware acceleration
1150
+ - Teleport usage ensures proper z-index layering and positioning outside component tree
1151
+ - Body scroll locking prevents background scrolling when sheet is open
1152
+ - Safe area support handles mobile device notches and home indicators
1153
+ - Custom scrollbar styling provides better visual consistency
1154
+ - Backdrop blur effects create modern, iOS-like appearance
1155
+ - Keyboard navigation includes Escape key support for accessibility
1156
+ - TypeScript interfaces ensure type safety for all props and events
1157
+ - CSS custom properties enable easy theming and customization
1158
+ - Responsive design adapts to different screen sizes and orientations
1159
+ - Animation cleanup prevents memory leaks and ensures smooth performance