@aspect-ops/exon-ui 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/components/ActionSheet/ActionSheet.svelte +270 -0
  2. package/dist/components/ActionSheet/ActionSheet.svelte.d.ts +12 -0
  3. package/dist/components/ActionSheet/ActionSheetItem.svelte +151 -0
  4. package/dist/components/ActionSheet/ActionSheetItem.svelte.d.ts +10 -0
  5. package/dist/components/ActionSheet/index.d.ts +3 -0
  6. package/dist/components/ActionSheet/index.js +2 -0
  7. package/dist/components/Alert/Alert.svelte +165 -0
  8. package/dist/components/Alert/Alert.svelte.d.ts +11 -0
  9. package/dist/components/Alert/index.d.ts +1 -0
  10. package/dist/components/Alert/index.js +1 -0
  11. package/dist/components/AspectRatio/AspectRatio.svelte +42 -0
  12. package/dist/components/AspectRatio/AspectRatio.svelte.d.ts +9 -0
  13. package/dist/components/AspectRatio/index.d.ts +1 -0
  14. package/dist/components/AspectRatio/index.js +1 -0
  15. package/dist/components/Avatar/Avatar.svelte +147 -0
  16. package/dist/components/Avatar/Avatar.svelte.d.ts +12 -0
  17. package/dist/components/Avatar/AvatarGroup.svelte +153 -0
  18. package/dist/components/Avatar/AvatarGroup.svelte.d.ts +12 -0
  19. package/dist/components/Avatar/index.d.ts +2 -0
  20. package/dist/components/Avatar/index.js +2 -0
  21. package/dist/components/BottomSheet/BottomSheet.svelte +230 -0
  22. package/dist/components/BottomSheet/BottomSheet.svelte.d.ts +7 -0
  23. package/dist/components/BottomSheet/BottomSheetBody.svelte +20 -0
  24. package/dist/components/BottomSheet/BottomSheetBody.svelte.d.ts +7 -0
  25. package/dist/components/BottomSheet/BottomSheetHeader.svelte +27 -0
  26. package/dist/components/BottomSheet/BottomSheetHeader.svelte.d.ts +7 -0
  27. package/dist/components/BottomSheet/index.d.ts +3 -0
  28. package/dist/components/BottomSheet/index.js +3 -0
  29. package/dist/components/Box/Box.svelte +41 -0
  30. package/dist/components/Box/Box.svelte.d.ts +7 -0
  31. package/dist/components/Box/index.d.ts +1 -0
  32. package/dist/components/Box/index.js +1 -0
  33. package/dist/components/Card/Card.svelte +95 -0
  34. package/dist/components/Card/Card.svelte.d.ts +10 -0
  35. package/dist/components/Card/CardBody.svelte +32 -0
  36. package/dist/components/Card/CardBody.svelte.d.ts +7 -0
  37. package/dist/components/Card/CardFooter.svelte +34 -0
  38. package/dist/components/Card/CardFooter.svelte.d.ts +7 -0
  39. package/dist/components/Card/CardHeader.svelte +67 -0
  40. package/dist/components/Card/CardHeader.svelte.d.ts +9 -0
  41. package/dist/components/Card/index.d.ts +4 -0
  42. package/dist/components/Card/index.js +4 -0
  43. package/dist/components/Center/Center.svelte +28 -0
  44. package/dist/components/Center/Center.svelte.d.ts +8 -0
  45. package/dist/components/Center/index.d.ts +1 -0
  46. package/dist/components/Center/index.js +1 -0
  47. package/dist/components/Container/Container.svelte +58 -0
  48. package/dist/components/Container/Container.svelte.d.ts +10 -0
  49. package/dist/components/Container/index.d.ts +1 -0
  50. package/dist/components/Container/index.js +1 -0
  51. package/dist/components/Divider/Divider.svelte +38 -0
  52. package/dist/components/Divider/Divider.svelte.d.ts +9 -0
  53. package/dist/components/Divider/index.d.ts +1 -0
  54. package/dist/components/Divider/index.js +1 -0
  55. package/dist/components/EmptyState/EmptyState.svelte +164 -0
  56. package/dist/components/EmptyState/EmptyState.svelte.d.ts +12 -0
  57. package/dist/components/EmptyState/index.d.ts +1 -0
  58. package/dist/components/EmptyState/index.js +1 -0
  59. package/dist/components/FAB/FAB.svelte +242 -0
  60. package/dist/components/FAB/FAB.svelte.d.ts +9 -0
  61. package/dist/components/FAB/FABGroup.svelte +449 -0
  62. package/dist/components/FAB/FABGroup.svelte.d.ts +9 -0
  63. package/dist/components/FAB/index.d.ts +3 -0
  64. package/dist/components/FAB/index.js +2 -0
  65. package/dist/components/Grid/Grid.svelte +136 -0
  66. package/dist/components/Grid/Grid.svelte.d.ts +12 -0
  67. package/dist/components/Grid/GridItem.svelte +21 -0
  68. package/dist/components/Grid/GridItem.svelte.d.ts +7 -0
  69. package/dist/components/Grid/index.d.ts +2 -0
  70. package/dist/components/Grid/index.js +2 -0
  71. package/dist/components/List/List.svelte +42 -0
  72. package/dist/components/List/List.svelte.d.ts +18 -0
  73. package/dist/components/List/ListItem.svelte +139 -0
  74. package/dist/components/List/ListItem.svelte.d.ts +36 -0
  75. package/dist/components/List/index.d.ts +2 -0
  76. package/dist/components/List/index.js +2 -0
  77. package/dist/components/Modal/Modal.svelte +204 -0
  78. package/dist/components/Modal/Modal.svelte.d.ts +7 -0
  79. package/dist/components/Modal/ModalBody.svelte +50 -0
  80. package/dist/components/Modal/ModalBody.svelte.d.ts +7 -0
  81. package/dist/components/Modal/ModalFooter.svelte +37 -0
  82. package/dist/components/Modal/ModalFooter.svelte.d.ts +7 -0
  83. package/dist/components/Modal/ModalHeader.svelte +73 -0
  84. package/dist/components/Modal/ModalHeader.svelte.d.ts +7 -0
  85. package/dist/components/Modal/index.d.ts +4 -0
  86. package/dist/components/Modal/index.js +4 -0
  87. package/dist/components/Popover/Popover.svelte +14 -0
  88. package/dist/components/Popover/Popover.svelte.d.ts +7 -0
  89. package/dist/components/Popover/PopoverContent.svelte +63 -0
  90. package/dist/components/Popover/PopoverContent.svelte.d.ts +7 -0
  91. package/dist/components/Popover/PopoverTrigger.svelte +14 -0
  92. package/dist/components/Popover/PopoverTrigger.svelte.d.ts +7 -0
  93. package/dist/components/Popover/index.d.ts +3 -0
  94. package/dist/components/Popover/index.js +3 -0
  95. package/dist/components/Progress/ProgressBar.svelte +86 -0
  96. package/dist/components/Progress/ProgressBar.svelte.d.ts +11 -0
  97. package/dist/components/Progress/ProgressCircle.svelte +134 -0
  98. package/dist/components/Progress/ProgressCircle.svelte.d.ts +12 -0
  99. package/dist/components/Progress/Spinner.svelte +68 -0
  100. package/dist/components/Progress/Spinner.svelte.d.ts +8 -0
  101. package/dist/components/Progress/index.d.ts +3 -0
  102. package/dist/components/Progress/index.js +3 -0
  103. package/dist/components/PullToRefresh/PullToRefresh.svelte +304 -0
  104. package/dist/components/PullToRefresh/PullToRefresh.svelte.d.ts +20 -0
  105. package/dist/components/PullToRefresh/index.d.ts +1 -0
  106. package/dist/components/PullToRefresh/index.js +1 -0
  107. package/dist/components/SafeArea/SafeArea.svelte +33 -0
  108. package/dist/components/SafeArea/SafeArea.svelte.d.ts +7 -0
  109. package/dist/components/Select/Select.svelte +55 -12
  110. package/dist/components/Skeleton/Skeleton.svelte +59 -0
  111. package/dist/components/Skeleton/Skeleton.svelte.d.ts +10 -0
  112. package/dist/components/Skeleton/index.d.ts +1 -0
  113. package/dist/components/Skeleton/index.js +1 -0
  114. package/dist/components/Spacer/Spacer.svelte +56 -0
  115. package/dist/components/Spacer/Spacer.svelte.d.ts +6 -0
  116. package/dist/components/Spacer/index.d.ts +1 -0
  117. package/dist/components/Spacer/index.js +1 -0
  118. package/dist/components/Stack/Stack.svelte +117 -0
  119. package/dist/components/Stack/Stack.svelte.d.ts +13 -0
  120. package/dist/components/Stack/index.d.ts +1 -0
  121. package/dist/components/Stack/index.js +1 -0
  122. package/dist/components/SwipeActions/SwipeAction.svelte +43 -0
  123. package/dist/components/SwipeActions/SwipeAction.svelte.d.ts +8 -0
  124. package/dist/components/SwipeActions/SwipeActions.svelte +193 -0
  125. package/dist/components/SwipeActions/SwipeActions.svelte.d.ts +9 -0
  126. package/dist/components/SwipeActions/index.d.ts +2 -0
  127. package/dist/components/SwipeActions/index.js +2 -0
  128. package/dist/components/Switch/Switch.svelte +29 -9
  129. package/dist/components/Table/Table.svelte +175 -0
  130. package/dist/components/Table/Table.svelte.d.ts +38 -0
  131. package/dist/components/Table/TableBody.svelte +26 -0
  132. package/dist/components/Table/TableBody.svelte.d.ts +13 -0
  133. package/dist/components/Table/TableCell.svelte +85 -0
  134. package/dist/components/Table/TableCell.svelte.d.ts +28 -0
  135. package/dist/components/Table/TableHead.svelte +36 -0
  136. package/dist/components/Table/TableHead.svelte.d.ts +13 -0
  137. package/dist/components/Table/TableHeader.svelte +217 -0
  138. package/dist/components/Table/TableHeader.svelte.d.ts +32 -0
  139. package/dist/components/Table/TableRow.svelte +92 -0
  140. package/dist/components/Table/TableRow.svelte.d.ts +28 -0
  141. package/dist/components/Table/index.d.ts +6 -0
  142. package/dist/components/Table/index.js +6 -0
  143. package/dist/components/Tag/Tag.svelte +189 -0
  144. package/dist/components/Tag/Tag.svelte.d.ts +13 -0
  145. package/dist/components/Tag/index.d.ts +1 -0
  146. package/dist/components/Tag/index.js +1 -0
  147. package/dist/components/Toast/Toast.svelte +241 -0
  148. package/dist/components/Toast/Toast.svelte.d.ts +18 -0
  149. package/dist/components/Toast/ToastContainer.svelte +110 -0
  150. package/dist/components/Toast/ToastContainer.svelte.d.ts +8 -0
  151. package/dist/components/Toast/index.d.ts +3 -0
  152. package/dist/components/Toast/index.js +3 -0
  153. package/dist/components/Toast/toast.d.ts +13 -0
  154. package/dist/components/Toast/toast.js +55 -0
  155. package/dist/components/Tooltip/Tooltip.svelte +71 -0
  156. package/dist/components/Tooltip/Tooltip.svelte.d.ts +7 -0
  157. package/dist/components/Tooltip/index.d.ts +2 -0
  158. package/dist/components/Tooltip/index.js +1 -0
  159. package/dist/index.d.ts +29 -1
  160. package/dist/index.js +32 -0
  161. package/dist/styles/tokens.css +5 -0
  162. package/dist/types/data-display.d.ts +93 -0
  163. package/dist/types/data-display.js +1 -0
  164. package/dist/types/feedback.d.ts +92 -0
  165. package/dist/types/feedback.js +1 -0
  166. package/dist/types/index.d.ts +4 -0
  167. package/dist/types/layout.d.ts +57 -0
  168. package/dist/types/layout.js +1 -0
  169. package/dist/types/mobile.d.ts +91 -0
  170. package/dist/types/mobile.js +1 -0
  171. package/dist/utils/gestures.d.ts +219 -0
  172. package/dist/utils/gestures.js +492 -0
  173. package/dist/utils/haptics.d.ts +89 -0
  174. package/dist/utils/haptics.js +198 -0
  175. package/dist/utils/platform.d.ts +47 -0
  176. package/dist/utils/platform.js +156 -0
  177. package/package.json +1 -1
@@ -0,0 +1,242 @@
1
+ <script lang="ts">
2
+ import type { FABProps, FABSize, FABPosition } from '../../types/index.js';
3
+
4
+ interface Props extends FABProps {
5
+ onclick?: (e: MouseEvent) => void;
6
+ children?: import('svelte').Snippet;
7
+ label?: import('svelte').Snippet;
8
+ }
9
+
10
+ let {
11
+ size = 'md',
12
+ position = 'bottom-right',
13
+ extended = false,
14
+ disabled = false,
15
+ class: className = '',
16
+ onclick,
17
+ children,
18
+ label
19
+ }: Props = $props();
20
+
21
+ // Size mappings: sm=44px, md=56px, lg=72px (F20 compliance)
22
+ const sizeMap: Record<FABSize, string> = {
23
+ sm: '44px',
24
+ md: '56px',
25
+ lg: '72px'
26
+ };
27
+
28
+ const fabSize = $derived(sizeMap[size]);
29
+ </script>
30
+
31
+ <button
32
+ type="button"
33
+ class="fab fab--{size} fab--{position} {extended ? 'fab--extended' : ''} {className}"
34
+ class:fab--disabled={disabled}
35
+ {disabled}
36
+ aria-disabled={disabled}
37
+ style="--fab-size: {fabSize};"
38
+ {onclick}
39
+ >
40
+ <span class="fab__icon">
41
+ {#if children}
42
+ {@render children()}
43
+ {/if}
44
+ </span>
45
+ {#if extended && label}
46
+ <span class="fab__label">
47
+ {@render label()}
48
+ </span>
49
+ {/if}
50
+ </button>
51
+
52
+ <style>
53
+ .fab {
54
+ position: fixed;
55
+ z-index: 50;
56
+ display: inline-flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ gap: var(--space-sm, 0.5rem);
60
+ width: var(--fab-size, 56px);
61
+ height: var(--fab-size, 56px);
62
+ padding: 0;
63
+ margin: 0;
64
+ border: none;
65
+ border-radius: var(--radius-full, 9999px);
66
+ background: var(--color-primary, #3b82f6);
67
+ color: var(--color-text-inverse, #ffffff);
68
+ font-family: inherit;
69
+ font-size: var(--text-base, 1rem);
70
+ font-weight: 600;
71
+ cursor: pointer;
72
+ box-shadow:
73
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
74
+ 0 2px 4px -2px rgba(0, 0, 0, 0.1);
75
+ transition: all var(--transition-fast, 150ms ease);
76
+ -webkit-tap-highlight-color: transparent;
77
+ }
78
+
79
+ /* Size variants - all maintain F20 minimum touch target */
80
+ .fab--sm {
81
+ width: 44px;
82
+ height: 44px;
83
+ font-size: var(--text-sm, 0.875rem);
84
+ }
85
+
86
+ .fab--md {
87
+ width: 56px;
88
+ height: 56px;
89
+ font-size: var(--text-base, 1rem);
90
+ }
91
+
92
+ .fab--lg {
93
+ width: 72px;
94
+ height: 72px;
95
+ font-size: var(--text-lg, 1.125rem);
96
+ }
97
+
98
+ /* Extended variant */
99
+ .fab--extended {
100
+ width: auto;
101
+ min-width: var(--fab-size, 56px);
102
+ padding: 0 var(--space-lg, 1.5rem);
103
+ border-radius: var(--radius-xl, 1rem);
104
+ }
105
+
106
+ .fab--extended.fab--sm {
107
+ padding: 0 var(--space-md, 1rem);
108
+ min-height: 44px;
109
+ height: auto;
110
+ }
111
+
112
+ .fab--extended.fab--md {
113
+ padding: 0 var(--space-lg, 1.5rem);
114
+ min-height: 56px;
115
+ height: auto;
116
+ }
117
+
118
+ .fab--extended.fab--lg {
119
+ padding: 0 var(--space-xl, 2rem);
120
+ min-height: 72px;
121
+ height: auto;
122
+ }
123
+
124
+ /* Position variants with safe area insets (F21) */
125
+ .fab--bottom-right {
126
+ bottom: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-bottom, 0px));
127
+ right: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-right, 0px));
128
+ }
129
+
130
+ .fab--bottom-left {
131
+ bottom: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-bottom, 0px));
132
+ left: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-left, 0px));
133
+ }
134
+
135
+ .fab--bottom-center {
136
+ bottom: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-bottom, 0px));
137
+ left: 50%;
138
+ transform: translateX(-50%);
139
+ }
140
+
141
+ .fab--top-right {
142
+ top: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-top, 0px));
143
+ right: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-right, 0px));
144
+ }
145
+
146
+ .fab--top-left {
147
+ top: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-top, 0px));
148
+ left: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-left, 0px));
149
+ }
150
+
151
+ /* Hover effects */
152
+ .fab:hover:not(:disabled) {
153
+ background: var(--color-primary-hover, #2563eb);
154
+ box-shadow:
155
+ 0 10px 15px -3px rgba(0, 0, 0, 0.1),
156
+ 0 4px 6px -4px rgba(0, 0, 0, 0.1);
157
+ transform: scale(1.05);
158
+ }
159
+
160
+ .fab--bottom-center:hover:not(:disabled) {
161
+ transform: translateX(-50%) scale(1.05);
162
+ }
163
+
164
+ /* Active/pressed state */
165
+ .fab:active:not(:disabled) {
166
+ background: var(--color-primary-active, #1d4ed8);
167
+ box-shadow:
168
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
169
+ 0 2px 4px -2px rgba(0, 0, 0, 0.1);
170
+ transform: scale(0.98);
171
+ }
172
+
173
+ .fab--bottom-center:active:not(:disabled) {
174
+ transform: translateX(-50%) scale(0.98);
175
+ }
176
+
177
+ /* Focus state */
178
+ .fab:focus-visible {
179
+ outline: 2px solid var(--color-primary, #3b82f6);
180
+ outline-offset: 2px;
181
+ }
182
+
183
+ /* Disabled state */
184
+ .fab--disabled,
185
+ .fab:disabled {
186
+ opacity: 0.5;
187
+ cursor: not-allowed;
188
+ pointer-events: none;
189
+ }
190
+
191
+ /* Icon container */
192
+ .fab__icon {
193
+ display: flex;
194
+ align-items: center;
195
+ justify-content: center;
196
+ flex-shrink: 0;
197
+ }
198
+
199
+ .fab--sm .fab__icon {
200
+ font-size: 1.25rem;
201
+ }
202
+
203
+ .fab--md .fab__icon {
204
+ font-size: 1.5rem;
205
+ }
206
+
207
+ .fab--lg .fab__icon {
208
+ font-size: 2rem;
209
+ }
210
+
211
+ /* Label for extended FAB */
212
+ .fab__label {
213
+ white-space: nowrap;
214
+ }
215
+
216
+ /* Platform-specific styling (F22) */
217
+ :global([data-platform='android']) .fab {
218
+ box-shadow:
219
+ 0 6px 10px 0 rgba(0, 0, 0, 0.14),
220
+ 0 1px 18px 0 rgba(0, 0, 0, 0.12),
221
+ 0 3px 5px -1px rgba(0, 0, 0, 0.2);
222
+ }
223
+
224
+ :global([data-platform='android']) .fab:hover:not(:disabled) {
225
+ box-shadow:
226
+ 0 12px 17px 2px rgba(0, 0, 0, 0.14),
227
+ 0 5px 22px 4px rgba(0, 0, 0, 0.12),
228
+ 0 7px 8px -4px rgba(0, 0, 0, 0.2);
229
+ }
230
+
231
+ :global([data-platform='ios']) .fab {
232
+ box-shadow:
233
+ 0 2px 8px rgba(0, 0, 0, 0.15),
234
+ 0 1px 3px rgba(0, 0, 0, 0.1);
235
+ }
236
+
237
+ :global([data-platform='ios']) .fab:hover:not(:disabled) {
238
+ box-shadow:
239
+ 0 4px 16px rgba(0, 0, 0, 0.2),
240
+ 0 2px 6px rgba(0, 0, 0, 0.1);
241
+ }
242
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { FABProps } from '../../types/index.js';
2
+ interface Props extends FABProps {
3
+ onclick?: (e: MouseEvent) => void;
4
+ children?: import('svelte').Snippet;
5
+ label?: import('svelte').Snippet;
6
+ }
7
+ declare const FAB: import("svelte").Component<Props, {}, "">;
8
+ type FAB = ReturnType<typeof FAB>;
9
+ export default FAB;
@@ -0,0 +1,449 @@
1
+ <script lang="ts">
2
+ import type { FABGroupProps, FABAction, FABPosition } from '../../types/index.js';
3
+
4
+ interface Props extends FABGroupProps {
5
+ children?: import('svelte').Snippet;
6
+ closeIconSlot?: import('svelte').Snippet;
7
+ iconSlot?: import('svelte').Snippet;
8
+ }
9
+
10
+ let {
11
+ actions = [],
12
+ icon = '+',
13
+ closeIcon = '\u00D7',
14
+ position = 'bottom-right',
15
+ direction = 'up',
16
+ class: className = '',
17
+ children,
18
+ closeIconSlot,
19
+ iconSlot
20
+ }: Props = $props();
21
+
22
+ let isOpen = $state(false);
23
+
24
+ function toggle() {
25
+ isOpen = !isOpen;
26
+ }
27
+
28
+ function handleAction(action: FABAction) {
29
+ if (action.onAction) {
30
+ action.onAction();
31
+ }
32
+ isOpen = false;
33
+ }
34
+
35
+ function handleBackdropClick() {
36
+ isOpen = false;
37
+ }
38
+
39
+ function handleKeydown(event: KeyboardEvent) {
40
+ if (event.key === 'Escape' && isOpen) {
41
+ isOpen = false;
42
+ }
43
+ }
44
+
45
+ // Derive transform direction for action items
46
+ const getActionTransform = $derived((index: number) => {
47
+ const spacing = 60; // px spacing between items
48
+ const offset = (index + 1) * spacing;
49
+
50
+ switch (direction) {
51
+ case 'up':
52
+ return `translateY(-${offset}px)`;
53
+ case 'down':
54
+ return `translateY(${offset}px)`;
55
+ case 'left':
56
+ return `translateX(-${offset}px)`;
57
+ case 'right':
58
+ return `translateX(${offset}px)`;
59
+ default:
60
+ return `translateY(-${offset}px)`;
61
+ }
62
+ });
63
+ </script>
64
+
65
+ <svelte:window onkeydown={handleKeydown} />
66
+
67
+ <!-- Backdrop -->
68
+ {#if isOpen}
69
+ <button
70
+ type="button"
71
+ class="fab-group__backdrop"
72
+ onclick={handleBackdropClick}
73
+ aria-label="Close speed dial menu"
74
+ ></button>
75
+ {/if}
76
+
77
+ <div
78
+ class="fab-group fab-group--{position} fab-group--{direction} {className}"
79
+ class:fab-group--open={isOpen}
80
+ >
81
+ <!-- Action items -->
82
+ <div class="fab-group__actions" role="menu" aria-label="Speed dial actions">
83
+ {#each actions as action, index}
84
+ <button
85
+ type="button"
86
+ class="fab-group__action"
87
+ class:fab-group__action--visible={isOpen}
88
+ style="--action-index: {index}; --action-transform: {getActionTransform(index)};"
89
+ onclick={() => handleAction(action)}
90
+ role="menuitem"
91
+ aria-label={action.label}
92
+ tabindex={isOpen ? 0 : -1}
93
+ >
94
+ <span class="fab-group__action-icon">{action.icon}</span>
95
+ <span class="fab-group__action-label">{action.label}</span>
96
+ </button>
97
+ {/each}
98
+ </div>
99
+
100
+ <!-- Main FAB trigger -->
101
+ <button
102
+ type="button"
103
+ class="fab-group__trigger"
104
+ class:fab-group__trigger--open={isOpen}
105
+ onclick={toggle}
106
+ aria-expanded={isOpen}
107
+ aria-haspopup="menu"
108
+ aria-label={isOpen ? 'Close menu' : 'Open menu'}
109
+ >
110
+ <span class="fab-group__trigger-icon fab-group__trigger-icon--default">
111
+ {#if iconSlot}
112
+ {@render iconSlot()}
113
+ {:else if children}
114
+ {@render children()}
115
+ {:else}
116
+ {icon}
117
+ {/if}
118
+ </span>
119
+ <span class="fab-group__trigger-icon fab-group__trigger-icon--close">
120
+ {#if closeIconSlot}
121
+ {@render closeIconSlot()}
122
+ {:else}
123
+ {closeIcon}
124
+ {/if}
125
+ </span>
126
+ </button>
127
+ </div>
128
+
129
+ <style>
130
+ /* Backdrop */
131
+ .fab-group__backdrop {
132
+ position: fixed;
133
+ inset: 0;
134
+ z-index: 49;
135
+ background: rgba(0, 0, 0, 0.3);
136
+ border: none;
137
+ cursor: pointer;
138
+ animation: fadeIn var(--transition-fast, 150ms ease) forwards;
139
+ }
140
+
141
+ @keyframes fadeIn {
142
+ from {
143
+ opacity: 0;
144
+ }
145
+ to {
146
+ opacity: 1;
147
+ }
148
+ }
149
+
150
+ /* Container */
151
+ .fab-group {
152
+ position: fixed;
153
+ z-index: 50;
154
+ display: flex;
155
+ flex-direction: column;
156
+ align-items: center;
157
+ }
158
+
159
+ /* Position variants with safe area insets (F21) */
160
+ .fab-group--bottom-right {
161
+ bottom: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-bottom, 0px));
162
+ right: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-right, 0px));
163
+ }
164
+
165
+ .fab-group--bottom-left {
166
+ bottom: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-bottom, 0px));
167
+ left: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-left, 0px));
168
+ }
169
+
170
+ .fab-group--bottom-center {
171
+ bottom: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-bottom, 0px));
172
+ left: 50%;
173
+ transform: translateX(-50%);
174
+ }
175
+
176
+ .fab-group--top-right {
177
+ top: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-top, 0px));
178
+ right: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-right, 0px));
179
+ }
180
+
181
+ .fab-group--top-left {
182
+ top: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-top, 0px));
183
+ left: calc(var(--space-lg, 1.5rem) + env(safe-area-inset-left, 0px));
184
+ }
185
+
186
+ /* Direction variants */
187
+ .fab-group--up {
188
+ flex-direction: column-reverse;
189
+ }
190
+
191
+ .fab-group--down {
192
+ flex-direction: column;
193
+ }
194
+
195
+ .fab-group--left {
196
+ flex-direction: row-reverse;
197
+ }
198
+
199
+ .fab-group--right {
200
+ flex-direction: row;
201
+ }
202
+
203
+ /* Main trigger button */
204
+ .fab-group__trigger {
205
+ position: relative;
206
+ display: flex;
207
+ align-items: center;
208
+ justify-content: center;
209
+ width: 56px;
210
+ height: 56px;
211
+ padding: 0;
212
+ margin: 0;
213
+ border: none;
214
+ border-radius: var(--radius-full, 9999px);
215
+ background: var(--color-primary, #3b82f6);
216
+ color: var(--color-text-inverse, #ffffff);
217
+ font-family: inherit;
218
+ font-size: 1.5rem;
219
+ font-weight: 600;
220
+ cursor: pointer;
221
+ box-shadow:
222
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
223
+ 0 2px 4px -2px rgba(0, 0, 0, 0.1);
224
+ transition: all var(--transition-fast, 150ms ease);
225
+ -webkit-tap-highlight-color: transparent;
226
+ /* Touch target minimum (F20) */
227
+ min-width: var(--touch-target-min, 44px);
228
+ min-height: var(--touch-target-min, 44px);
229
+ }
230
+
231
+ .fab-group__trigger:hover {
232
+ background: var(--color-primary-hover, #2563eb);
233
+ box-shadow:
234
+ 0 10px 15px -3px rgba(0, 0, 0, 0.1),
235
+ 0 4px 6px -4px rgba(0, 0, 0, 0.1);
236
+ }
237
+
238
+ .fab-group__trigger:active {
239
+ background: var(--color-primary-active, #1d4ed8);
240
+ }
241
+
242
+ .fab-group__trigger:focus-visible {
243
+ outline: 2px solid var(--color-primary, #3b82f6);
244
+ outline-offset: 2px;
245
+ }
246
+
247
+ /* Rotation when open */
248
+ .fab-group__trigger--open {
249
+ background: var(--color-secondary, #6b7280);
250
+ }
251
+
252
+ .fab-group__trigger--open:hover {
253
+ background: var(--color-secondary-hover, #4b5563);
254
+ }
255
+
256
+ /* Icon transitions */
257
+ .fab-group__trigger-icon {
258
+ position: absolute;
259
+ display: flex;
260
+ align-items: center;
261
+ justify-content: center;
262
+ transition: all var(--transition-normal, 200ms ease);
263
+ }
264
+
265
+ .fab-group__trigger-icon--default {
266
+ opacity: 1;
267
+ transform: rotate(0deg);
268
+ }
269
+
270
+ .fab-group__trigger-icon--close {
271
+ opacity: 0;
272
+ transform: rotate(-90deg);
273
+ }
274
+
275
+ .fab-group__trigger--open .fab-group__trigger-icon--default {
276
+ opacity: 0;
277
+ transform: rotate(90deg);
278
+ }
279
+
280
+ .fab-group__trigger--open .fab-group__trigger-icon--close {
281
+ opacity: 1;
282
+ transform: rotate(0deg);
283
+ }
284
+
285
+ /* Actions container */
286
+ .fab-group__actions {
287
+ position: absolute;
288
+ display: flex;
289
+ flex-direction: column;
290
+ align-items: center;
291
+ gap: var(--space-sm, 0.5rem);
292
+ pointer-events: none;
293
+ }
294
+
295
+ .fab-group--open .fab-group__actions {
296
+ pointer-events: auto;
297
+ }
298
+
299
+ .fab-group--up .fab-group__actions {
300
+ bottom: 100%;
301
+ flex-direction: column-reverse;
302
+ }
303
+
304
+ .fab-group--down .fab-group__actions {
305
+ top: 100%;
306
+ flex-direction: column;
307
+ }
308
+
309
+ .fab-group--left .fab-group__actions {
310
+ right: 100%;
311
+ flex-direction: row-reverse;
312
+ }
313
+
314
+ .fab-group--right .fab-group__actions {
315
+ left: 100%;
316
+ flex-direction: row;
317
+ }
318
+
319
+ /* Action item */
320
+ .fab-group__action {
321
+ position: absolute;
322
+ display: flex;
323
+ align-items: center;
324
+ gap: var(--space-sm, 0.5rem);
325
+ width: 44px;
326
+ height: 44px;
327
+ padding: 0;
328
+ margin: 0;
329
+ border: none;
330
+ border-radius: var(--radius-full, 9999px);
331
+ background: var(--color-bg, #ffffff);
332
+ color: var(--color-text, #1f2937);
333
+ font-family: inherit;
334
+ font-size: var(--text-sm, 0.875rem);
335
+ cursor: pointer;
336
+ box-shadow:
337
+ 0 2px 4px -1px rgba(0, 0, 0, 0.1),
338
+ 0 1px 2px -1px rgba(0, 0, 0, 0.1);
339
+ transition: all var(--transition-fast, 150ms ease);
340
+ -webkit-tap-highlight-color: transparent;
341
+ /* Touch target minimum (F20) */
342
+ min-width: var(--touch-target-min, 44px);
343
+ min-height: var(--touch-target-min, 44px);
344
+ /* Initial hidden state */
345
+ opacity: 0;
346
+ transform: scale(0.3);
347
+ }
348
+
349
+ .fab-group__action--visible {
350
+ opacity: 1;
351
+ transform: var(--action-transform) scale(1);
352
+ transition-delay: calc(var(--action-index) * 50ms);
353
+ }
354
+
355
+ .fab-group__action:hover {
356
+ background: var(--color-bg-muted, #f3f4f6);
357
+ box-shadow:
358
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
359
+ 0 2px 4px -2px rgba(0, 0, 0, 0.1);
360
+ }
361
+
362
+ .fab-group__action:active {
363
+ background: var(--color-border, #e5e7eb);
364
+ }
365
+
366
+ .fab-group__action:focus-visible {
367
+ outline: 2px solid var(--color-primary, #3b82f6);
368
+ outline-offset: 2px;
369
+ }
370
+
371
+ /* Action icon */
372
+ .fab-group__action-icon {
373
+ display: flex;
374
+ align-items: center;
375
+ justify-content: center;
376
+ font-size: 1.25rem;
377
+ }
378
+
379
+ /* Action label - tooltip style */
380
+ .fab-group__action-label {
381
+ position: absolute;
382
+ white-space: nowrap;
383
+ padding: var(--space-xs, 0.25rem) var(--space-sm, 0.5rem);
384
+ background: var(--color-bg-inverse, #1f2937);
385
+ color: var(--color-text-inverse, #ffffff);
386
+ font-size: var(--text-xs, 0.75rem);
387
+ font-weight: 500;
388
+ border-radius: var(--radius-sm, 0.25rem);
389
+ opacity: 0;
390
+ pointer-events: none;
391
+ transition: opacity var(--transition-fast, 150ms ease);
392
+ }
393
+
394
+ /* Label positioning based on direction */
395
+ .fab-group--up .fab-group__action-label,
396
+ .fab-group--down .fab-group__action-label {
397
+ right: calc(100% + var(--space-sm, 0.5rem));
398
+ }
399
+
400
+ .fab-group--left .fab-group__action-label,
401
+ .fab-group--right .fab-group__action-label {
402
+ bottom: calc(100% + var(--space-xs, 0.25rem));
403
+ }
404
+
405
+ .fab-group--bottom-left .fab-group__action-label,
406
+ .fab-group--top-left .fab-group__action-label {
407
+ right: auto;
408
+ left: calc(100% + var(--space-sm, 0.5rem));
409
+ }
410
+
411
+ .fab-group__action:hover .fab-group__action-label,
412
+ .fab-group__action:focus-visible .fab-group__action-label {
413
+ opacity: 1;
414
+ }
415
+
416
+ /* Platform-specific styling (F22) */
417
+ :global([data-platform='android']) .fab-group__trigger {
418
+ box-shadow:
419
+ 0 6px 10px 0 rgba(0, 0, 0, 0.14),
420
+ 0 1px 18px 0 rgba(0, 0, 0, 0.12),
421
+ 0 3px 5px -1px rgba(0, 0, 0, 0.2);
422
+ }
423
+
424
+ :global([data-platform='android']) .fab-group__trigger:hover {
425
+ box-shadow:
426
+ 0 12px 17px 2px rgba(0, 0, 0, 0.14),
427
+ 0 5px 22px 4px rgba(0, 0, 0, 0.12),
428
+ 0 7px 8px -4px rgba(0, 0, 0, 0.2);
429
+ }
430
+
431
+ :global([data-platform='android']) .fab-group__action {
432
+ box-shadow:
433
+ 0 3px 5px -1px rgba(0, 0, 0, 0.2),
434
+ 0 6px 10px 0 rgba(0, 0, 0, 0.14),
435
+ 0 1px 18px 0 rgba(0, 0, 0, 0.12);
436
+ }
437
+
438
+ :global([data-platform='ios']) .fab-group__trigger {
439
+ box-shadow:
440
+ 0 2px 8px rgba(0, 0, 0, 0.15),
441
+ 0 1px 3px rgba(0, 0, 0, 0.1);
442
+ }
443
+
444
+ :global([data-platform='ios']) .fab-group__action {
445
+ box-shadow:
446
+ 0 1px 4px rgba(0, 0, 0, 0.1),
447
+ 0 0.5px 2px rgba(0, 0, 0, 0.08);
448
+ }
449
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { FABGroupProps } from '../../types/index.js';
2
+ interface Props extends FABGroupProps {
3
+ children?: import('svelte').Snippet;
4
+ closeIconSlot?: import('svelte').Snippet;
5
+ iconSlot?: import('svelte').Snippet;
6
+ }
7
+ declare const FABGroup: import("svelte").Component<Props, {}, "">;
8
+ type FABGroup = ReturnType<typeof FABGroup>;
9
+ export default FABGroup;
@@ -0,0 +1,3 @@
1
+ export { default as FAB } from './FAB.svelte';
2
+ export { default as FABGroup } from './FABGroup.svelte';
3
+ export type { FABProps, FABSize, FABPosition, FABAction, FABGroupProps } from '../../types/index.js';
@@ -0,0 +1,2 @@
1
+ export { default as FAB } from './FAB.svelte';
2
+ export { default as FABGroup } from './FABGroup.svelte';