fluentui-svelte 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 (283) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -0
  3. package/dist/components/auto-suggest-box/auto-suggest-box.d.ts +2 -0
  4. package/dist/components/auto-suggest-box/auto-suggest-box.js +2 -0
  5. package/dist/components/auto-suggest-box/auto-suggest-box.svelte +457 -0
  6. package/dist/components/auto-suggest-box/auto-suggest-box.svelte.d.ts +4 -0
  7. package/dist/components/auto-suggest-box/docs/llms.md +73 -0
  8. package/dist/components/auto-suggest-box/option.svelte +82 -0
  9. package/dist/components/auto-suggest-box/option.svelte.d.ts +4 -0
  10. package/dist/components/auto-suggest-box/types.d.ts +140 -0
  11. package/dist/components/auto-suggest-box/types.js +1 -0
  12. package/dist/components/avatar/avatar.svelte +269 -0
  13. package/dist/components/avatar/avatar.svelte.d.ts +20 -0
  14. package/dist/components/avatar/docs/llms.md +92 -0
  15. package/dist/components/avatar/type.d.ts +63 -0
  16. package/dist/components/avatar/type.js +1 -0
  17. package/dist/components/badge/badge-icon.svelte +103 -0
  18. package/dist/components/badge/badge-icon.svelte.d.ts +25 -0
  19. package/dist/components/badge/badge.svelte +163 -0
  20. package/dist/components/badge/badge.svelte.d.ts +20 -0
  21. package/dist/components/badge/docs/llms.md +133 -0
  22. package/dist/components/badge/types.d.ts +70 -0
  23. package/dist/components/badge/types.js +1 -0
  24. package/dist/components/badge/utils.svelte.d.ts +16 -0
  25. package/dist/components/badge/utils.svelte.js +35 -0
  26. package/dist/components/button/button.svelte +203 -0
  27. package/dist/components/button/button.svelte.d.ts +38 -0
  28. package/dist/components/button/docs/llms.md +102 -0
  29. package/dist/components/button/split-button.svelte +66 -0
  30. package/dist/components/button/split-button.svelte.d.ts +4 -0
  31. package/dist/components/button/types.d.ts +84 -0
  32. package/dist/components/button/types.js +1 -0
  33. package/dist/components/calendar-date-picker/calendar-date-picker.svelte +119 -0
  34. package/dist/components/calendar-date-picker/calendar-date-picker.svelte.d.ts +4 -0
  35. package/dist/components/calendar-date-picker/docs/llms.md +33 -0
  36. package/dist/components/calendar-date-picker/types.d.ts +36 -0
  37. package/dist/components/calendar-date-picker/types.js +1 -0
  38. package/dist/components/calendar-view/calendar-view-controls.svelte +115 -0
  39. package/dist/components/calendar-view/calendar-view-controls.svelte.d.ts +3 -0
  40. package/dist/components/calendar-view/calendar-view-days.svelte +210 -0
  41. package/dist/components/calendar-view/calendar-view-days.svelte.d.ts +3 -0
  42. package/dist/components/calendar-view/calendar-view-grid.d.ts +38 -0
  43. package/dist/components/calendar-view/calendar-view-grid.js +140 -0
  44. package/dist/components/calendar-view/calendar-view-header.svelte +66 -0
  45. package/dist/components/calendar-view/calendar-view-header.svelte.d.ts +18 -0
  46. package/dist/components/calendar-view/calendar-view-item.svelte +181 -0
  47. package/dist/components/calendar-view/calendar-view-item.svelte.d.ts +4 -0
  48. package/dist/components/calendar-view/calendar-view-months.svelte +165 -0
  49. package/dist/components/calendar-view/calendar-view-months.svelte.d.ts +3 -0
  50. package/dist/components/calendar-view/calendar-view-years.svelte +161 -0
  51. package/dist/components/calendar-view/calendar-view-years.svelte.d.ts +3 -0
  52. package/dist/components/calendar-view/calendar-view.svelte +451 -0
  53. package/dist/components/calendar-view/calendar-view.svelte.d.ts +9 -0
  54. package/dist/components/calendar-view/calendar-view.svelte.js +196 -0
  55. package/dist/components/calendar-view/docs/llms.md +121 -0
  56. package/dist/components/calendar-view/index.d.ts +1 -0
  57. package/dist/components/calendar-view/index.js +1 -0
  58. package/dist/components/calendar-view/types.d.ts +174 -0
  59. package/dist/components/calendar-view/types.js +1 -0
  60. package/dist/components/checkbox/checkbox.svelte +171 -0
  61. package/dist/components/checkbox/checkbox.svelte.d.ts +40 -0
  62. package/dist/components/checkbox/docs/llms.md +78 -0
  63. package/dist/components/checkbox/types.d.ts +50 -0
  64. package/dist/components/checkbox/types.js +1 -0
  65. package/dist/components/date-picker/date-picker.svelte +381 -0
  66. package/dist/components/date-picker/date-picker.svelte.d.ts +4 -0
  67. package/dist/components/date-picker/docs/llms.md +52 -0
  68. package/dist/components/date-picker/index.d.ts +1 -0
  69. package/dist/components/date-picker/index.js +1 -0
  70. package/dist/components/date-picker/types.d.ts +74 -0
  71. package/dist/components/date-picker/types.js +1 -0
  72. package/dist/components/dialog/dialog-actions.svelte +37 -0
  73. package/dist/components/dialog/dialog-actions.svelte.d.ts +4 -0
  74. package/dist/components/dialog/dialog-content.svelte +17 -0
  75. package/dist/components/dialog/dialog-content.svelte.d.ts +4 -0
  76. package/dist/components/dialog/dialog-surface.svelte +95 -0
  77. package/dist/components/dialog/dialog-surface.svelte.d.ts +4 -0
  78. package/dist/components/dialog/dialog-title.svelte +33 -0
  79. package/dist/components/dialog/dialog-title.svelte.d.ts +25 -0
  80. package/dist/components/dialog/dialog-trigger.svelte +23 -0
  81. package/dist/components/dialog/dialog-trigger.svelte.d.ts +4 -0
  82. package/dist/components/dialog/dialog.svelte +64 -0
  83. package/dist/components/dialog/dialog.svelte.d.ts +7 -0
  84. package/dist/components/dialog/dialog.svelte.js +2 -0
  85. package/dist/components/dialog/docs/llms.md +131 -0
  86. package/dist/components/dialog/types.d.ts +92 -0
  87. package/dist/components/dialog/types.js +1 -0
  88. package/dist/components/divider/divider.svelte +120 -0
  89. package/dist/components/divider/divider.svelte.d.ts +39 -0
  90. package/dist/components/divider/docs/llms.md +83 -0
  91. package/dist/components/divider/types.d.ts +32 -0
  92. package/dist/components/divider/types.js +1 -0
  93. package/dist/components/dropdown/docs/llms.md +70 -0
  94. package/dist/components/dropdown/dropdown-context.d.ts +2 -0
  95. package/dist/components/dropdown/dropdown-context.js +2 -0
  96. package/dist/components/dropdown/dropdown-option.svelte +31 -0
  97. package/dist/components/dropdown/dropdown-option.svelte.d.ts +4 -0
  98. package/dist/components/dropdown/dropdown.svelte +309 -0
  99. package/dist/components/dropdown/dropdown.svelte.d.ts +4 -0
  100. package/dist/components/dropdown/types.d.ts +82 -0
  101. package/dist/components/dropdown/types.js +1 -0
  102. package/dist/components/dropdown-select/docs/llms.md +72 -0
  103. package/dist/components/dropdown-select/dropdown-select-option.svelte +87 -0
  104. package/dist/components/dropdown-select/dropdown-select-option.svelte.d.ts +4 -0
  105. package/dist/components/dropdown-select/dropdown-select.svelte +165 -0
  106. package/dist/components/dropdown-select/dropdown-select.svelte.d.ts +4 -0
  107. package/dist/components/dropdown-select/dropdown-select.svelte.js +48 -0
  108. package/dist/components/dropdown-select/index.d.ts +2 -0
  109. package/dist/components/dropdown-select/index.js +2 -0
  110. package/dist/components/dropdown-select/types.d.ts +46 -0
  111. package/dist/components/dropdown-select/types.js +1 -0
  112. package/dist/components/expander/docs/llms.md +88 -0
  113. package/dist/components/expander/expander.svelte +249 -0
  114. package/dist/components/expander/expander.svelte.d.ts +21 -0
  115. package/dist/components/expander/types.d.ts +47 -0
  116. package/dist/components/expander/types.js +1 -0
  117. package/dist/components/flyout/docs/llms.md +31 -0
  118. package/dist/components/flyout/flyout.svelte +148 -0
  119. package/dist/components/flyout/flyout.svelte.d.ts +19 -0
  120. package/dist/components/flyout/types.d.ts +36 -0
  121. package/dist/components/flyout/types.js +1 -0
  122. package/dist/components/hyperlink/docs/llms.md +33 -0
  123. package/dist/components/hyperlink/hyperlink.svelte +66 -0
  124. package/dist/components/hyperlink/hyperlink.svelte.d.ts +16 -0
  125. package/dist/components/hyperlink/types.d.ts +14 -0
  126. package/dist/components/hyperlink/types.js +1 -0
  127. package/dist/components/info-bar/docs/llms.md +81 -0
  128. package/dist/components/info-bar/info-bar.svelte +140 -0
  129. package/dist/components/info-bar/info-bar.svelte.d.ts +19 -0
  130. package/dist/components/info-bar/types.d.ts +27 -0
  131. package/dist/components/info-bar/types.js +1 -0
  132. package/dist/components/label/docs/llms.md +67 -0
  133. package/dist/components/label/label.svelte +95 -0
  134. package/dist/components/label/label.svelte.d.ts +4 -0
  135. package/dist/components/label/types.d.ts +32 -0
  136. package/dist/components/label/types.js +1 -0
  137. package/dist/components/list-view/docs/llms.md +110 -0
  138. package/dist/components/list-view/list-view-item.svelte +168 -0
  139. package/dist/components/list-view/list-view-item.svelte.d.ts +25 -0
  140. package/dist/components/list-view/list-view.svelte +137 -0
  141. package/dist/components/list-view/list-view.svelte.d.ts +25 -0
  142. package/dist/components/list-view/types.d.ts +95 -0
  143. package/dist/components/list-view/types.js +1 -0
  144. package/dist/components/list-view/utils.d.ts +6 -0
  145. package/dist/components/list-view/utils.js +12 -0
  146. package/dist/components/menu/context-menu-trigger.svelte +84 -0
  147. package/dist/components/menu/context-menu-trigger.svelte.d.ts +9 -0
  148. package/dist/components/menu/docs/llms.md +169 -0
  149. package/dist/components/menu/menu-divider.svelte +9 -0
  150. package/dist/components/menu/menu-divider.svelte.d.ts +26 -0
  151. package/dist/components/menu/menu-group.svelte +31 -0
  152. package/dist/components/menu/menu-group.svelte.d.ts +4 -0
  153. package/dist/components/menu/menu-item-checkbox.svelte +143 -0
  154. package/dist/components/menu/menu-item-checkbox.svelte.d.ts +15 -0
  155. package/dist/components/menu/menu-item-radio.svelte +147 -0
  156. package/dist/components/menu/menu-item-radio.svelte.d.ts +15 -0
  157. package/dist/components/menu/menu-item-switch.svelte +194 -0
  158. package/dist/components/menu/menu-item-switch.svelte.d.ts +15 -0
  159. package/dist/components/menu/menu-item.svelte +124 -0
  160. package/dist/components/menu/menu-item.svelte.d.ts +18 -0
  161. package/dist/components/menu/menu-list.svelte +38 -0
  162. package/dist/components/menu/menu-list.svelte.d.ts +5 -0
  163. package/dist/components/menu/menu-popover.svelte +125 -0
  164. package/dist/components/menu/menu-popover.svelte.d.ts +12 -0
  165. package/dist/components/menu/menu-trigger.svelte +121 -0
  166. package/dist/components/menu/menu-trigger.svelte.d.ts +4 -0
  167. package/dist/components/menu/menu.svelte +124 -0
  168. package/dist/components/menu/menu.svelte.d.ts +4 -0
  169. package/dist/components/menu/menu.svelte.js +77 -0
  170. package/dist/components/menu/types.d.ts +127 -0
  171. package/dist/components/menu/types.js +1 -0
  172. package/dist/components/number-box/docs/llms.md +37 -0
  173. package/dist/components/number-box/number-box.svelte +115 -0
  174. package/dist/components/number-box/number-box.svelte.d.ts +15 -0
  175. package/dist/components/number-box/types.d.ts +16 -0
  176. package/dist/components/number-box/types.js +1 -0
  177. package/dist/components/persona/docs/llms.md +107 -0
  178. package/dist/components/persona/persona.svelte +79 -0
  179. package/dist/components/persona/persona.svelte.d.ts +4 -0
  180. package/dist/components/persona/types.d.ts +42 -0
  181. package/dist/components/persona/types.js +1 -0
  182. package/dist/components/progress-bar/docs/llms.md +67 -0
  183. package/dist/components/progress-bar/progress-bar.svelte +167 -0
  184. package/dist/components/progress-bar/progress-bar.svelte.d.ts +15 -0
  185. package/dist/components/progress-bar/types.d.ts +39 -0
  186. package/dist/components/progress-bar/types.js +1 -0
  187. package/dist/components/progress-ring/docs/llms.md +76 -0
  188. package/dist/components/progress-ring/progress-ring.svelte +145 -0
  189. package/dist/components/progress-ring/progress-ring.svelte.d.ts +15 -0
  190. package/dist/components/progress-ring/types.d.ts +42 -0
  191. package/dist/components/progress-ring/types.js +1 -0
  192. package/dist/components/radio-button/docs/llms.md +64 -0
  193. package/dist/components/radio-button/radio-button.svelte +129 -0
  194. package/dist/components/radio-button/radio-button.svelte.d.ts +19 -0
  195. package/dist/components/radio-button/types.d.ts +24 -0
  196. package/dist/components/radio-button/types.js +1 -0
  197. package/dist/components/skeleton/docs/llms.md +67 -0
  198. package/dist/components/skeleton/skeleton.svelte +106 -0
  199. package/dist/components/skeleton/skeleton.svelte.d.ts +39 -0
  200. package/dist/components/skeleton/types.d.ts +24 -0
  201. package/dist/components/skeleton/types.js +1 -0
  202. package/dist/components/slider/docs/llms.md +75 -0
  203. package/dist/components/slider/slider.svelte +486 -0
  204. package/dist/components/slider/slider.svelte.d.ts +19 -0
  205. package/dist/components/slider/types.d.ts +102 -0
  206. package/dist/components/slider/types.js +1 -0
  207. package/dist/components/text-box/docs/llms.md +86 -0
  208. package/dist/components/text-box/text-box-button.svelte +65 -0
  209. package/dist/components/text-box/text-box-button.svelte.d.ts +9 -0
  210. package/dist/components/text-box/text-box.svelte +299 -0
  211. package/dist/components/text-box/text-box.svelte.d.ts +16 -0
  212. package/dist/components/text-box/types.d.ts +60 -0
  213. package/dist/components/text-box/types.js +1 -0
  214. package/dist/components/textarea/docs/llms.md +55 -0
  215. package/dist/components/textarea/textarea.svelte +151 -0
  216. package/dist/components/textarea/textarea.svelte.d.ts +17 -0
  217. package/dist/components/textarea/types.d.ts +33 -0
  218. package/dist/components/textarea/types.js +1 -0
  219. package/dist/components/time-picker/docs/llms.md +47 -0
  220. package/dist/components/time-picker/index.d.ts +1 -0
  221. package/dist/components/time-picker/index.js +1 -0
  222. package/dist/components/time-picker/time-picker.svelte +336 -0
  223. package/dist/components/time-picker/time-picker.svelte.d.ts +4 -0
  224. package/dist/components/time-picker/types.d.ts +54 -0
  225. package/dist/components/time-picker/types.js +1 -0
  226. package/dist/components/toggle-switch/docs/llms.md +39 -0
  227. package/dist/components/toggle-switch/toggle-switch.svelte +151 -0
  228. package/dist/components/toggle-switch/toggle-switch.svelte.d.ts +17 -0
  229. package/dist/components/toggle-switch/types.d.ts +20 -0
  230. package/dist/components/toggle-switch/types.js +1 -0
  231. package/dist/components/tooltip/docs/llms.md +74 -0
  232. package/dist/components/tooltip/tooltip.svelte +246 -0
  233. package/dist/components/tooltip/tooltip.svelte.d.ts +18 -0
  234. package/dist/components/tooltip/types.d.ts +67 -0
  235. package/dist/components/tooltip/types.js +1 -0
  236. package/dist/components/tree-view/docs/llms.md +117 -0
  237. package/dist/components/tree-view/tree-view-item-content.svelte +158 -0
  238. package/dist/components/tree-view/tree-view-item-content.svelte.d.ts +4 -0
  239. package/dist/components/tree-view/tree-view-item.svelte +197 -0
  240. package/dist/components/tree-view/tree-view-item.svelte.d.ts +4 -0
  241. package/dist/components/tree-view/tree-view.svelte +220 -0
  242. package/dist/components/tree-view/tree-view.svelte.d.ts +4 -0
  243. package/dist/components/tree-view/tree-view.svelte.js +111 -0
  244. package/dist/components/tree-view/types.d.ts +185 -0
  245. package/dist/components/tree-view/types.js +1 -0
  246. package/dist/css/class-darkmode.css +186 -0
  247. package/dist/css/media-darkmode.css +189 -0
  248. package/dist/css/reset.css +53 -0
  249. package/dist/css/theme.css +276 -0
  250. package/dist/css/typography.css +67 -0
  251. package/dist/css/utils.d.ts +1 -0
  252. package/dist/css/utils.js +153 -0
  253. package/dist/index.d.ts +63 -0
  254. package/dist/index.js +129 -0
  255. package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte +449 -0
  256. package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte.d.ts +22 -0
  257. package/dist/internal/components/render-soc/render-soc.svelte +29 -0
  258. package/dist/internal/components/render-soc/render-soc.svelte.d.ts +30 -0
  259. package/dist/internal/constants.d.ts +26 -0
  260. package/dist/internal/constants.js +4036 -0
  261. package/dist/internal/context.d.ts +14 -0
  262. package/dist/internal/context.js +13 -0
  263. package/dist/internal/dom-utils.svelte.d.ts +6 -0
  264. package/dist/internal/dom-utils.svelte.js +46 -0
  265. package/dist/internal/floating-ui/floating.svelte.d.ts +15 -0
  266. package/dist/internal/floating-ui/floating.svelte.js +26 -0
  267. package/dist/internal/floating-ui/utils.d.ts +3 -0
  268. package/dist/internal/floating-ui/utils.js +30 -0
  269. package/dist/internal/index.d.ts +9 -0
  270. package/dist/internal/index.js +9 -0
  271. package/dist/internal/polyfills/expander.svelte.d.ts +21 -0
  272. package/dist/internal/polyfills/expander.svelte.js +96 -0
  273. package/dist/internal/transitions.d.ts +32 -0
  274. package/dist/internal/transitions.js +37 -0
  275. package/dist/internal/utils.d.ts +22 -0
  276. package/dist/internal/utils.js +63 -0
  277. package/dist/providers/fluentui-svelte/fluentui-svelte.d.ts +19 -0
  278. package/dist/providers/fluentui-svelte/fluentui-svelte.js +11 -0
  279. package/dist/providers/fluentui-svelte/fluentui-svelte.svelte +68 -0
  280. package/dist/providers/fluentui-svelte/fluentui-svelte.svelte.d.ts +9 -0
  281. package/dist/types/index.d.ts +117 -0
  282. package/dist/types/index.js +1 -0
  283. package/package.json +142 -0
@@ -0,0 +1,451 @@
1
+ <script lang="ts">
2
+ import { SvelteDate } from 'svelte/reactivity';
3
+ import { setTabspotAttributes } from 'tabspot';
4
+ import { onMount } from 'svelte';
5
+ import { circOut } from 'svelte/easing';
6
+ import { Flyout } from '../../index.js';
7
+ import CalendarViewDays from './calendar-view-days.svelte';
8
+ import CalendarViewYears from './calendar-view-years.svelte';
9
+ import CalendarViewMonths from './calendar-view-months.svelte';
10
+ import CalendarViewHeader from './calendar-view-header.svelte';
11
+ import CalendarViewControls from './calendar-view-controls.svelte';
12
+ import {
13
+ floating as _floating,
14
+ getCSSDuration,
15
+ flyToOffset,
16
+ getOffset,
17
+ fadeScale,
18
+ reactiveBoundingRect
19
+ } from '../../internal/index.js';
20
+ import {
21
+ compareDates,
22
+ getPageByOffset,
23
+ hasBlackoutBetween,
24
+ indexOfDate,
25
+ rangeLength,
26
+ setCalendarViewContext,
27
+ startOfDay
28
+ } from './calendar-view.svelte.js';
29
+ import { CALENDAR_GRID_CONFIG, VIEW_PRECISION, cellDate, focusCalendarView } from './calendar-view-grid.js';
30
+ import { on } from 'svelte/events';
31
+ import { getReducedMotion } from '../../providers/fluentui-svelte/fluentui-svelte.js';
32
+ import type {
33
+ AnimationDirection,
34
+ CalendarViewProps,
35
+ CalendarViewState,
36
+ DateComparisonPrecision,
37
+ View
38
+ } from './types.js';
39
+
40
+ let {
41
+ ref = $bindable(),
42
+ value = $bindable(null),
43
+ range = $bindable({ start: null, end: null }),
44
+ view = 'days',
45
+ selectionMode = 'single',
46
+ blackoutBreaksRange,
47
+ minDate,
48
+ maxDate,
49
+ locale = 'en-US',
50
+ weekStart = 1,
51
+ blackoutDates,
52
+ headers,
53
+ floating,
54
+ onChange,
55
+ onRangeChange,
56
+ onViewChange,
57
+ ...attributes
58
+ }: CalendarViewProps = $props();
59
+
60
+ const reducedMotion = getReducedMotion();
61
+
62
+ let viewAnimationDirection: AnimationDirection = $state('neutral');
63
+
64
+ let pageAnimationDirection: AnimationDirection = $state('neutral');
65
+
66
+ let pageAnimationDuration = $state(333);
67
+
68
+ let firstValue = $derived(Array.isArray(value) ? value[0] : (value ?? new Date()));
69
+
70
+ // svelte-ignore state_referenced_locally
71
+ let page = $state(
72
+ (!minDate || firstValue >= minDate) && (!maxDate || firstValue < maxDate)
73
+ ? new Date(firstValue.getFullYear(), firstValue.getMonth(), 1)
74
+ : firstValue < minDate!
75
+ ? new Date(minDate!.getFullYear(), minDate!.getMonth(), 1)
76
+ : new Date(maxDate!.getFullYear(), maxDate!.getMonth(), 1)
77
+ );
78
+
79
+ let boundingElement = reactiveBoundingRect();
80
+
81
+ let gridElement: HTMLElement | undefined = $state();
82
+
83
+ // Set when a view change starts from a grid cell, so the new grid can pick focus
84
+ // up where the old one left it. A change started from the header leaves it null:
85
+ // focus belongs to the button that is still there.
86
+ let pendingFocus: { date: Date; precision: DateComparisonPrecision } | null = null;
87
+
88
+ // live region is only announced when its text changes.
89
+ let liveMessage = $state('');
90
+
91
+ let dayFormat = $derived(new Intl.DateTimeFormat(locale, { dateStyle: 'long' }));
92
+
93
+ let dayRangeFormat = $derived(new Intl.DateTimeFormat(locale, { dateStyle: 'medium' }));
94
+
95
+ function updatePage(amount: number = 0, directionOverride: AnimationDirection | undefined = undefined) {
96
+ page = getPageByOffset(amount, page, view);
97
+ if (directionOverride) {
98
+ pageAnimationDirection = directionOverride;
99
+ return;
100
+ }
101
+ if (amount <= -1) {
102
+ pageAnimationDirection = 'up';
103
+ } else if (amount >= 1) {
104
+ pageAnimationDirection = 'down';
105
+ } else {
106
+ pageAnimationDirection = 'neutral';
107
+ }
108
+ }
109
+
110
+ function updateView(e: Event, newView: View, focusDate?: Date) {
111
+ if ((view === 'days' && newView === 'months') || (view === 'months' && newView === 'years')) {
112
+ viewAnimationDirection = 'up';
113
+ } else if ((view === 'years' && newView === 'months') || (view === 'months' && newView === 'days')) {
114
+ viewAnimationDirection = 'down';
115
+ } else {
116
+ viewAnimationDirection = 'neutral';
117
+ }
118
+
119
+ pendingFocus = focusDate ? { date: focusDate, precision: VIEW_PRECISION[newView] } : null;
120
+ pageAnimationDirection = 'neutral';
121
+ view = newView;
122
+ updatePage();
123
+ onViewChange?.(e, newView);
124
+ }
125
+
126
+ function selectDay(e: Event, day: Date) {
127
+ if (selectionMode === 'range') {
128
+ selectRangeDay(e, day);
129
+ return;
130
+ }
131
+
132
+ if (selectionMode === 'multiple') {
133
+ const days = Array.isArray(value) ? value : value ? [value] : [];
134
+ const index = indexOfDate(days, day);
135
+
136
+ value = index === -1 ? [...days, day] : days.filter((_, i) => i !== index);
137
+ } else {
138
+ const single = Array.isArray(value) ? null : value;
139
+
140
+ value = single && compareDates(single, day) ? null : day;
141
+ }
142
+
143
+ onChange?.(e, value);
144
+ }
145
+
146
+ /**
147
+ * One click of a range.
148
+ *
149
+ * The range is only ever built forwards: a click before the start, or one that
150
+ * lands on a finished range, opens a new range on that day rather than stretching
151
+ * or inverting the current one. Clicking the start again closes a range of a
152
+ * single day
153
+ */
154
+ function selectRangeDay(e: Event, day: Date) {
155
+ const start = range.start;
156
+ const restart =
157
+ !start ||
158
+ range.end !== null ||
159
+ startOfDay(day) < startOfDay(start) ||
160
+ // The consumer asked for ranges that claim every day they span, so a
161
+ // blocked day in the way makes this click a new start instead of an end.
162
+ (!!blackoutBreaksRange && hasBlackoutBetween(start, day, blackoutDates));
163
+
164
+ range = restart ? { start: day, end: null } : { start, end: day };
165
+
166
+ if (range.end) {
167
+ const days = rangeLength(range);
168
+ liveMessage = `${dayRangeFormat.formatRange(range.start!, range.end)} selected, ${days} ${days === 1 ? 'day' : 'days'}.`;
169
+ } else {
170
+ liveMessage = `${dayFormat.format(day)} selected as the start date. Choose the end date.`;
171
+ }
172
+
173
+ onRangeChange?.(e, range);
174
+ }
175
+
176
+ function clearSelection(e: Event) {
177
+ if (selectionMode === 'range') {
178
+ if (!range.start && !range.end) return;
179
+
180
+ range = { start: null, end: null };
181
+ liveMessage = 'Date range cleared.';
182
+ onRangeChange?.(e, range);
183
+ return;
184
+ }
185
+
186
+ value = selectionMode === 'multiple' ? [] : null;
187
+ onChange?.(e, value);
188
+ }
189
+
190
+ function selectMonth(e: Event, month: Date) {
191
+ page = new SvelteDate(month.setDate(1));
192
+ updateView(e, 'days', page);
193
+ }
194
+
195
+ function selectYear(e: Event, year: Date) {
196
+ page.setFullYear(year.getFullYear());
197
+ updateView(e, 'months', year);
198
+ }
199
+
200
+ const CALENDAR_STATE: CalendarViewState = {
201
+ get value() {
202
+ return value;
203
+ },
204
+ set value(v) {
205
+ value = v;
206
+ },
207
+ get range() {
208
+ return range;
209
+ },
210
+ set range(v) {
211
+ range = v;
212
+ },
213
+ get view() {
214
+ return view;
215
+ },
216
+ set view(v) {
217
+ view = v;
218
+ },
219
+ get page() {
220
+ return page;
221
+ },
222
+ set page(v) {
223
+ page = v;
224
+ },
225
+ get viewAnimationDirection() {
226
+ return viewAnimationDirection;
227
+ },
228
+ set viewAnimationDirection(v) {
229
+ viewAnimationDirection = v;
230
+ },
231
+ get pageAnimationDirection() {
232
+ return pageAnimationDirection;
233
+ },
234
+ set pageAnimationDirection(v) {
235
+ pageAnimationDirection = v;
236
+ }
237
+ };
238
+
239
+ // svelte-ignore state_referenced_locally
240
+ setCalendarViewContext({
241
+ config: {
242
+ minDate,
243
+ maxDate,
244
+ locale,
245
+ weekStart,
246
+ blackoutDates,
247
+ selectionMode,
248
+ blackoutBreaksRange,
249
+ headers
250
+ },
251
+ get state() {
252
+ return CALENDAR_STATE;
253
+ },
254
+ events: {
255
+ onChange: (e, value) => onChange?.(e, value),
256
+ onViewChange: (e, newView) => onViewChange?.(e, newView)
257
+ },
258
+ methods: {
259
+ updateView,
260
+ updatePage,
261
+ selectDay,
262
+ selectMonth,
263
+ selectYear,
264
+ clearSelection
265
+ }
266
+ });
267
+ $effect.pre(() => {
268
+ pageAnimationDuration = getCSSDuration('--fs-normal-duration') || 333;
269
+
270
+ if (floating?.ref && floating.ref instanceof HTMLElement) boundingElement.ref = floating.ref;
271
+ });
272
+
273
+ /** Which key zooms out of each view, and where it lands. */
274
+ const ZOOM: Record<View, { key: string; to: View }> = {
275
+ days: { key: 'ArrowUp', to: 'months' },
276
+ months: { key: 'ArrowUp', to: 'years' },
277
+ years: { key: 'ArrowDown', to: 'months' }
278
+ };
279
+
280
+ /**
281
+ * Keys the calendar owns rather than the grid: `Ctrl` + arrow moves between views,
282
+ * and `Delete` drops a range that can no longer be undone by clicking. Tabspot
283
+ * never reports either, so one delegated listener on the grid covers all three
284
+ * views and every cell.
285
+ */
286
+ function calendarShortcuts(node: HTMLElement) {
287
+ return on(node, 'keydown', (event) => {
288
+ if (selectionMode === 'range' && (event.key === 'Delete' || event.key === 'Backspace')) {
289
+ event.preventDefault();
290
+ clearSelection(event);
291
+ return;
292
+ }
293
+
294
+ const zoom = ZOOM[view];
295
+
296
+ if (!event.ctrlKey || event.key !== zoom.key) return;
297
+
298
+ updateView(event, zoom.to, cellDate(event.target as Element) ?? undefined);
299
+ });
300
+ }
301
+
302
+ // Opening as a popup: hand focus to the grid so the arrows work straight away.
303
+ // An inline calendar is just part of the page and must not steal focus.
304
+ onMount(() => {
305
+ if (floating && gridElement) focusCalendarView(gridElement, null, VIEW_PRECISION[view]);
306
+ });
307
+
308
+ // The grid is rebuilt on every view change, so the root is registered again
309
+ // each time. This is necessary for tabspot to work correctly.
310
+ $effect(() => {
311
+ if (!gridElement) return;
312
+
313
+ setTabspotAttributes({ element: gridElement, config: CALENDAR_GRID_CONFIG });
314
+
315
+ if (!pendingFocus) return;
316
+
317
+ focusCalendarView(gridElement, pendingFocus.date, pendingFocus.precision);
318
+ pendingFocus = null;
319
+ });
320
+ </script>
321
+
322
+ <!--
323
+ @component
324
+ A calendar view lets a user view and interact with a calendar that they can navigate by month, year, or decade. A user can select a single date or multiple dates.
325
+
326
+ This implementation is originally made by Tropix126 in his FluentSvelte library, I have changed several things but thanks to him for the original work.
327
+ -->
328
+ <div
329
+ class={['fs-calendar-view', { floating }]}
330
+ bind:this={ref}
331
+ in:flyToOffset={floating && floating.ref
332
+ ? {
333
+ y: -floating.ref.getBoundingClientRect().height / 2,
334
+ offset:
335
+ floating.ref instanceof HTMLElement
336
+ ? getOffset(floating.positionConfig) + floating.ref.getBoundingClientRect().height
337
+ : 0,
338
+ duration: pageAnimationDuration,
339
+ easing: circOut,
340
+ css: 'pointer-events: none;',
341
+ reducedMotion: reducedMotion()
342
+ }
343
+ : undefined}
344
+ {@attach floating?.ref ? _floating(floating.ref, floating.positionConfig) : undefined}
345
+ {...attributes}
346
+ >
347
+ <Flyout>
348
+ <CalendarViewControls />
349
+ <div class="calendar-wrapper">
350
+ {#key view}
351
+ <div
352
+ bind:this={gridElement}
353
+ class="calendar-view-stack"
354
+ data-calendar-grid
355
+ {@attach calendarShortcuts}
356
+ in:fadeScale={{
357
+ duration: viewAnimationDirection !== 'neutral' ? 500 : 0,
358
+ easing: circOut,
359
+ baseScale: viewAnimationDirection === 'up' ? 1.29 : 0.84,
360
+ delay: viewAnimationDirection !== 'neutral' ? 150 : 0,
361
+ reducedMotion: reducedMotion()
362
+ }}
363
+ out:fadeScale={{
364
+ duration: viewAnimationDirection !== 'neutral' ? 150 : 0,
365
+ easing: circOut,
366
+ baseScale: viewAnimationDirection === 'up' ? 0.84 : 1.29,
367
+ delay: 0,
368
+ reducedMotion: reducedMotion()
369
+ }}
370
+ >
371
+ {#if view === 'days'}
372
+ <CalendarViewHeader />
373
+ {/if}
374
+
375
+ <!--
376
+ The page slides in and out of here. Clipping it at the viewport is what
377
+ keeps a flying month from crossing the weekday names: on a translucent
378
+ surface you cannot mask, only clip.
379
+ -->
380
+ <div class="page-viewport">
381
+ {#if view === 'days'}
382
+ <CalendarViewDays />
383
+ {:else if view === 'months'}
384
+ <CalendarViewMonths />
385
+ {:else if view === 'years'}
386
+ <CalendarViewYears />
387
+ {/if}
388
+ </div>
389
+ </div>
390
+ {/key}
391
+ </div>
392
+ {#if selectionMode === 'range'}
393
+ <!-- Building a range moves no focus and changes no label: this is the only thing that reports it. -->
394
+ <div class="fs-calendar-live-region" role="status" aria-live="polite">{liveMessage}</div>
395
+ {/if}
396
+ </Flyout>
397
+ </div>
398
+
399
+ <style>
400
+ .fs-calendar-view {
401
+ width: 320px;
402
+ min-width: 280px;
403
+ &.floating {
404
+ position: absolute;
405
+ top: 0;
406
+ left: 0;
407
+ }
408
+ & .calendar-wrapper {
409
+ overflow: hidden;
410
+ position: relative;
411
+ width: 100%;
412
+ aspect-ratio: 1;
413
+ & .calendar-view-stack {
414
+ padding: 0 0.5rem;
415
+ position: absolute;
416
+ inset: 0;
417
+ display: flex;
418
+ flex-direction: column;
419
+ background: var(--fs-layer-on-acrylic-default);
420
+ & .page-viewport {
421
+ position: relative;
422
+ overflow: hidden;
423
+ flex: 1;
424
+ }
425
+ & :global([data-calendar-page][inert]) {
426
+ z-index: -1;
427
+ }
428
+ }
429
+ }
430
+ & .fs-calendar-live-region {
431
+ position: absolute;
432
+ width: 1px;
433
+ height: 1px;
434
+ margin: -1px;
435
+ padding: 0;
436
+ overflow: hidden;
437
+ clip-path: inset(50%);
438
+ white-space: nowrap;
439
+ border: 0;
440
+ }
441
+ & :global(.fs-flyout) {
442
+ padding: 0;
443
+ overflow: hidden;
444
+ height: 100%;
445
+ flex-direction: column;
446
+ & :global(.wrapper) {
447
+ gap: 0;
448
+ }
449
+ }
450
+ }
451
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { CalendarViewProps } from './types.js';
2
+ /**
3
+ * A calendar view lets a user view and interact with a calendar that they can navigate by month, year, or decade. A user can select a single date or multiple dates.
4
+ *
5
+ * This implementation is originally made by Tropix126 in his FluentSvelte library, I have changed several things but thanks to him for the original work.
6
+ */
7
+ declare const CalendarView: import("svelte").Component<CalendarViewProps, {}, "ref" | "value" | "range">;
8
+ type CalendarView = ReturnType<typeof CalendarView>;
9
+ export default CalendarView;
@@ -0,0 +1,196 @@
1
+ import { createFSContext } from '../../internal/index.js';
2
+ import { SvelteDate } from 'svelte/reactivity';
3
+ export const [getCalendarViewContext, setCalendarViewContext] = createFSContext();
4
+ /** Milliseconds in a day. Only ever used with `Math.round`, so DST cannot skew it. */
5
+ const DAY_MS = 86_400_000;
6
+ /**
7
+ * Midnight of `date`.
8
+ *
9
+ * Every date the grid renders is already at midnight, but a consumer can hand us a
10
+ * `range` or a `value` carrying a time, and a range must not change meaning because
11
+ * one of its ends happens to be half past two.
12
+ */
13
+ export function startOfDay(date) {
14
+ return new SvelteDate(date.getFullYear(), date.getMonth(), date.getDate());
15
+ }
16
+ /** Whether a blacked-out date sits strictly inside the interval. Its ends do not count. */
17
+ export function hasBlackoutBetween(from, to, blackoutDates) {
18
+ if (!blackoutDates?.length)
19
+ return false;
20
+ const min = startOfDay(from).getTime();
21
+ const max = startOfDay(to).getTime();
22
+ return blackoutDates.some((date) => {
23
+ const time = startOfDay(date).getTime();
24
+ return time > min && time < max;
25
+ });
26
+ }
27
+ /**
28
+ * Where `day` sits in a finished range, or `undefined` when it sits outside one.
29
+ *
30
+ * A range of a single day returns `undefined` too: there is no band to paint
31
+ * across one cell, and the day already reads as selected.
32
+ */
33
+ export function rangePositionOf(day, range) {
34
+ if (!range.start || !range.end)
35
+ return undefined;
36
+ const time = startOfDay(day).getTime();
37
+ const start = startOfDay(range.start).getTime();
38
+ const end = startOfDay(range.end).getTime();
39
+ if (start === end)
40
+ return undefined;
41
+ if (time === start)
42
+ return 'start';
43
+ if (time === end)
44
+ return 'end';
45
+ return time > start && time < end ? 'between' : undefined;
46
+ }
47
+ /** The first and last day of the cell `date` stands for. */
48
+ function cellSpan(date, precision) {
49
+ switch (precision) {
50
+ case 'month':
51
+ return [
52
+ new SvelteDate(date.getFullYear(), date.getMonth(), 1),
53
+ new SvelteDate(date.getFullYear(), date.getMonth() + 1, 0)
54
+ ];
55
+ case 'year':
56
+ return [new SvelteDate(date.getFullYear(), 0, 1), new SvelteDate(date.getFullYear(), 11, 31)];
57
+ default:
58
+ return [startOfDay(date), startOfDay(date)];
59
+ }
60
+ }
61
+ /**
62
+ * Whether the range touches the cell `date` stands for.
63
+ *
64
+ * A month or a year is one cell standing for many days, so it counts as covered the
65
+ * moment the range overlaps it at all — not only when an end of the range lands on it.
66
+ */
67
+ export function rangeCovers(date, range, precision) {
68
+ if (!range.start)
69
+ return false;
70
+ const [from, to] = cellSpan(date, precision);
71
+ const start = startOfDay(range.start).getTime();
72
+ // Half-built, the range is just its start.
73
+ const end = startOfDay(range.end ?? range.start).getTime();
74
+ return start <= to.getTime() && end >= from.getTime();
75
+ }
76
+ /** How many days a finished range spans, both ends included. */
77
+ export function rangeLength(range) {
78
+ if (!range.start || !range.end)
79
+ return 0;
80
+ return Math.round((startOfDay(range.end).getTime() - startOfDay(range.start).getTime()) / DAY_MS) + 1;
81
+ }
82
+ export function indexOfDate(array, date, precision = 'time') {
83
+ return array.findIndex((d) => compareDates(d, date, precision));
84
+ }
85
+ export function getWeekdayLocale(day, { locale = undefined, format = 'long', offset = 0 } = {}) {
86
+ const formatter = new Intl.DateTimeFormat(locale, {
87
+ weekday: format,
88
+ timeZone: 'UTC'
89
+ }).format(new SvelteDate(Date.UTC(2000, 1, day + offset - 1)));
90
+ // In some locales, the first letter may not be capitalized
91
+ return formatter.charAt(0).toUpperCase() + formatter.slice(1);
92
+ }
93
+ export function getPageByOffset(offset, page, view) {
94
+ if (view === 'days') {
95
+ return new SvelteDate(page.getFullYear(), page.getMonth() + offset, 1);
96
+ }
97
+ else if (view === 'months') {
98
+ return new SvelteDate(page.getFullYear() + offset, 0, 1);
99
+ }
100
+ else if (view === 'years') {
101
+ return new SvelteDate(Math.floor(page.getFullYear() / 10) * 10 + offset * 10, 0, 1);
102
+ }
103
+ // Fallback to current page if view is not recognized
104
+ return page;
105
+ }
106
+ export function getMonthLength(year, month) {
107
+ return new SvelteDate(year, month + 1, 0).getDate() - 1;
108
+ }
109
+ export function getMonthDays(year, month) {
110
+ const days = [];
111
+ for (let i = 0; i < getMonthLength(year, month) + 1; i++) {
112
+ days.push(new SvelteDate(year, month, i + 1));
113
+ }
114
+ return days;
115
+ }
116
+ export function compareDates(a, b, precision = 'time') {
117
+ switch (precision) {
118
+ case 'time':
119
+ return a.getTime() === b.getTime();
120
+ case 'day':
121
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
122
+ case 'month':
123
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
124
+ case 'year':
125
+ return a.getFullYear() === b.getFullYear();
126
+ case 'decade':
127
+ return Math.floor(a.getFullYear() / 10) * 10 === Math.floor(b.getFullYear() / 10) * 10;
128
+ }
129
+ }
130
+ export function getMonthLocale(month, { locale = undefined, format = 'long' } = {}) {
131
+ const formatter = new Intl.DateTimeFormat(locale, {
132
+ month: format
133
+ }).format(new SvelteDate(2000, month));
134
+ // In some locales, the first letter may not be capitalized
135
+ return formatter.charAt(0).toUpperCase() + formatter.slice(1);
136
+ }
137
+ export function getCalendarDays(date, weekStart = 0) {
138
+ const year = date.getFullYear();
139
+ const month = date.getMonth();
140
+ const firstWeekday = new SvelteDate(year, month, 1).getDay();
141
+ const calendarRows = 6;
142
+ let days = [];
143
+ let nextMonth = month + 1;
144
+ let lastMonth = month - 1;
145
+ let nextMonthYear = year;
146
+ let lastMonthYear = year;
147
+ const daysBefore = (firstWeekday - weekStart + 7) % 7;
148
+ if (daysBefore > 0) {
149
+ if (lastMonth === -1) {
150
+ lastMonth = 11;
151
+ lastMonthYear = year - 1;
152
+ }
153
+ days = getMonthDays(lastMonthYear, lastMonth).slice(-daysBefore);
154
+ }
155
+ days = days.concat(getMonthDays(year, month));
156
+ if (nextMonth === 12) {
157
+ nextMonth = 0;
158
+ nextMonthYear = year + 1;
159
+ }
160
+ const daysAfter = 7 * calendarRows - days.length;
161
+ days = days.concat(getMonthDays(nextMonthYear, nextMonth).slice(0, daysAfter));
162
+ return days;
163
+ }
164
+ export function getYearMonths(year) {
165
+ const months = [];
166
+ for (let i = 0; i < 12; i++) {
167
+ months.push(new SvelteDate(year, i, 1));
168
+ }
169
+ return months;
170
+ }
171
+ export function getCalendarMonths(date) {
172
+ const year = date.getFullYear();
173
+ const months = [];
174
+ return months.concat(getYearMonths(year), getYearMonths(year + 1).slice(0, 4));
175
+ }
176
+ export function getCalendarYears(date) {
177
+ const decadeStart = Math.floor(date.getFullYear() / 10) * 10;
178
+ const years = [];
179
+ for (let i = 0; i < 12; i++) {
180
+ years.push(new SvelteDate(decadeStart + i, 0, 1));
181
+ }
182
+ if (decadeStart % 20 === 0) {
183
+ for (let i = 0; i < 2; i++) {
184
+ years.unshift(new SvelteDate(decadeStart - (i + 1), 0, 1));
185
+ }
186
+ for (let i = 0; i < 4; i++) {
187
+ years.push(new SvelteDate(decadeStart + i + 12, 0, 1));
188
+ }
189
+ }
190
+ else {
191
+ for (let i = 0; i < 6; i++) {
192
+ years.push(new SvelteDate(decadeStart + i + 12, 0, 1));
193
+ }
194
+ }
195
+ return years;
196
+ }