@proyecto-viviana/solidaria-components 0.2.4 → 0.2.9

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 (194) hide show
  1. package/LICENSE +21 -0
  2. package/dist/ActionBar.d.ts +71 -0
  3. package/dist/ActionBar.d.ts.map +1 -0
  4. package/dist/ActionGroup.d.ts +74 -0
  5. package/dist/ActionGroup.d.ts.map +1 -0
  6. package/dist/Alert.d.ts +70 -0
  7. package/dist/Alert.d.ts.map +1 -0
  8. package/dist/Breadcrumbs.d.ts +10 -2
  9. package/dist/Breadcrumbs.d.ts.map +1 -1
  10. package/dist/Button.d.ts +4 -0
  11. package/dist/Button.d.ts.map +1 -1
  12. package/dist/Calendar.d.ts +13 -0
  13. package/dist/Calendar.d.ts.map +1 -1
  14. package/dist/Checkbox.d.ts +2 -2
  15. package/dist/Checkbox.d.ts.map +1 -1
  16. package/dist/Collection.d.ts +125 -0
  17. package/dist/Collection.d.ts.map +1 -0
  18. package/dist/Color.d.ts +114 -2
  19. package/dist/Color.d.ts.map +1 -1
  20. package/dist/ColorEditor.d.ts +42 -0
  21. package/dist/ColorEditor.d.ts.map +1 -0
  22. package/dist/ComboBox.d.ts +64 -0
  23. package/dist/ComboBox.d.ts.map +1 -1
  24. package/dist/ContextualHelpTrigger.d.ts +40 -0
  25. package/dist/ContextualHelpTrigger.d.ts.map +1 -0
  26. package/dist/DateField.d.ts +27 -2
  27. package/dist/DateField.d.ts.map +1 -1
  28. package/dist/DatePicker.d.ts +67 -2
  29. package/dist/DatePicker.d.ts.map +1 -1
  30. package/dist/Dialog.d.ts.map +1 -1
  31. package/dist/Disclosure.d.ts +2 -0
  32. package/dist/Disclosure.d.ts.map +1 -1
  33. package/dist/DragAndDrop.d.ts +80 -0
  34. package/dist/DragAndDrop.d.ts.map +1 -0
  35. package/dist/DragPreview.d.ts +14 -0
  36. package/dist/DragPreview.d.ts.map +1 -0
  37. package/dist/DropZone.d.ts +27 -0
  38. package/dist/DropZone.d.ts.map +1 -0
  39. package/dist/FieldError.d.ts +23 -0
  40. package/dist/FieldError.d.ts.map +1 -0
  41. package/dist/FileTrigger.d.ts +26 -0
  42. package/dist/FileTrigger.d.ts.map +1 -0
  43. package/dist/Focusable.d.ts +27 -0
  44. package/dist/Focusable.d.ts.map +1 -0
  45. package/dist/Form.d.ts +27 -0
  46. package/dist/Form.d.ts.map +1 -0
  47. package/dist/GridList.d.ts +40 -1
  48. package/dist/GridList.d.ts.map +1 -1
  49. package/dist/Icon.d.ts +57 -0
  50. package/dist/Icon.d.ts.map +1 -0
  51. package/dist/Keyboard.d.ts +13 -0
  52. package/dist/Keyboard.d.ts.map +1 -0
  53. package/dist/Link.d.ts.map +1 -1
  54. package/dist/ListBox.d.ts +43 -1
  55. package/dist/ListBox.d.ts.map +1 -1
  56. package/dist/ListDropTargetDelegate.d.ts +38 -0
  57. package/dist/ListDropTargetDelegate.d.ts.map +1 -0
  58. package/dist/Menu.d.ts +20 -2
  59. package/dist/Menu.d.ts.map +1 -1
  60. package/dist/Meter.d.ts +2 -2
  61. package/dist/Meter.d.ts.map +1 -1
  62. package/dist/Modal.d.ts +2 -0
  63. package/dist/Modal.d.ts.map +1 -1
  64. package/dist/NumberField.d.ts +2 -0
  65. package/dist/NumberField.d.ts.map +1 -1
  66. package/dist/Popover.d.ts +4 -2
  67. package/dist/Popover.d.ts.map +1 -1
  68. package/dist/Pressable.d.ts +27 -0
  69. package/dist/Pressable.d.ts.map +1 -0
  70. package/dist/ProgressBar.d.ts +2 -2
  71. package/dist/ProgressBar.d.ts.map +1 -1
  72. package/dist/RadioGroup.d.ts.map +1 -1
  73. package/dist/RangeCalendar.d.ts +5 -0
  74. package/dist/RangeCalendar.d.ts.map +1 -1
  75. package/dist/RouterProvider.d.ts +75 -0
  76. package/dist/RouterProvider.d.ts.map +1 -0
  77. package/dist/SearchField.d.ts +2 -3
  78. package/dist/SearchField.d.ts.map +1 -1
  79. package/dist/Select.d.ts +11 -0
  80. package/dist/Select.d.ts.map +1 -1
  81. package/dist/SelectionIndicator.d.ts +30 -0
  82. package/dist/SelectionIndicator.d.ts.map +1 -0
  83. package/dist/SharedElementTransition.d.ts +39 -0
  84. package/dist/SharedElementTransition.d.ts.map +1 -0
  85. package/dist/Slider.d.ts +6 -3
  86. package/dist/Slider.d.ts.map +1 -1
  87. package/dist/Table.d.ts +39 -0
  88. package/dist/Table.d.ts.map +1 -1
  89. package/dist/Tabs.d.ts +4 -3
  90. package/dist/Tabs.d.ts.map +1 -1
  91. package/dist/TagGroup.d.ts +12 -2
  92. package/dist/TagGroup.d.ts.map +1 -1
  93. package/dist/Text.d.ts +10 -0
  94. package/dist/Text.d.ts.map +1 -0
  95. package/dist/TextField.d.ts +4 -0
  96. package/dist/TextField.d.ts.map +1 -1
  97. package/dist/TimeField.d.ts +26 -1
  98. package/dist/TimeField.d.ts.map +1 -1
  99. package/dist/Toast.d.ts.map +1 -1
  100. package/dist/ToggleButton.d.ts +30 -0
  101. package/dist/ToggleButton.d.ts.map +1 -0
  102. package/dist/ToggleButtonGroup.d.ts +33 -0
  103. package/dist/ToggleButtonGroup.d.ts.map +1 -0
  104. package/dist/Toolbar.d.ts.map +1 -1
  105. package/dist/Tooltip.d.ts +9 -0
  106. package/dist/Tooltip.d.ts.map +1 -1
  107. package/dist/Tree.d.ts +44 -2
  108. package/dist/Tree.d.ts.map +1 -1
  109. package/dist/Virtualizer.d.ts +61 -0
  110. package/dist/Virtualizer.d.ts.map +1 -0
  111. package/dist/VirtualizerLayouts.d.ts +82 -0
  112. package/dist/VirtualizerLayouts.d.ts.map +1 -0
  113. package/dist/VisuallyHidden.d.ts +3 -1
  114. package/dist/VisuallyHidden.d.ts.map +1 -1
  115. package/dist/contexts.d.ts +1 -0
  116. package/dist/contexts.d.ts.map +1 -1
  117. package/dist/index.d.ts +57 -25
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/index.js +13961 -5946
  120. package/dist/index.js.map +1 -7
  121. package/dist/index.ssr.js +9612 -2401
  122. package/dist/index.ssr.js.map +1 -7
  123. package/dist/useDragAndDrop.d.ts +93 -0
  124. package/dist/useDragAndDrop.d.ts.map +1 -0
  125. package/dist/utils.d.ts +7 -1
  126. package/dist/utils.d.ts.map +1 -1
  127. package/dist/virtualizer/Layout.d.ts +79 -0
  128. package/dist/virtualizer/Layout.d.ts.map +1 -0
  129. package/package.json +8 -6
  130. package/src/ActionBar.tsx +248 -0
  131. package/src/ActionGroup.tsx +285 -0
  132. package/src/Alert.tsx +177 -0
  133. package/src/Autocomplete.tsx +1 -1
  134. package/src/Breadcrumbs.tsx +103 -17
  135. package/src/Button.tsx +65 -21
  136. package/src/Calendar.tsx +179 -53
  137. package/src/Checkbox.tsx +1 -2
  138. package/src/Collection.tsx +341 -0
  139. package/src/Color.tsx +652 -34
  140. package/src/ColorEditor.tsx +231 -0
  141. package/src/ComboBox.tsx +315 -81
  142. package/src/ContextualHelpTrigger.tsx +183 -0
  143. package/src/DateField.tsx +93 -19
  144. package/src/DatePicker.tsx +495 -25
  145. package/src/Dialog.tsx +40 -9
  146. package/src/Disclosure.tsx +33 -27
  147. package/src/DragAndDrop.tsx +334 -0
  148. package/src/DragPreview.tsx +45 -0
  149. package/src/DropZone.tsx +213 -0
  150. package/src/FieldError.tsx +67 -0
  151. package/src/FileTrigger.tsx +83 -0
  152. package/src/Focusable.tsx +106 -0
  153. package/src/Form.tsx +85 -0
  154. package/src/GridList.tsx +379 -41
  155. package/src/Icon.tsx +154 -0
  156. package/src/Keyboard.tsx +26 -0
  157. package/src/Link.tsx +14 -1
  158. package/src/ListBox.tsx +484 -33
  159. package/src/ListDropTargetDelegate.ts +282 -0
  160. package/src/Menu.tsx +388 -35
  161. package/src/Meter.tsx +7 -3
  162. package/src/Modal.tsx +32 -4
  163. package/src/NumberField.tsx +163 -43
  164. package/src/Popover.tsx +136 -180
  165. package/src/Pressable.tsx +108 -0
  166. package/src/ProgressBar.tsx +7 -3
  167. package/src/RadioGroup.tsx +35 -25
  168. package/src/RangeCalendar.tsx +100 -68
  169. package/src/RouterProvider.tsx +240 -0
  170. package/src/SearchField.tsx +142 -34
  171. package/src/Select.tsx +221 -73
  172. package/src/SelectionIndicator.tsx +105 -0
  173. package/src/SharedElementTransition.tsx +258 -0
  174. package/src/Slider.tsx +16 -6
  175. package/src/Table.tsx +417 -57
  176. package/src/Tabs.tsx +68 -35
  177. package/src/TagGroup.tsx +121 -36
  178. package/src/Text.tsx +18 -0
  179. package/src/TextField.tsx +25 -8
  180. package/src/TimeField.tsx +101 -151
  181. package/src/Toast.tsx +108 -14
  182. package/src/ToggleButton.tsx +159 -0
  183. package/src/ToggleButtonGroup.tsx +136 -0
  184. package/src/Toolbar.tsx +14 -8
  185. package/src/Tooltip.tsx +108 -19
  186. package/src/Tree.tsx +1143 -87
  187. package/src/Virtualizer.tsx +702 -0
  188. package/src/VirtualizerLayouts.ts +265 -0
  189. package/src/VisuallyHidden.tsx +15 -21
  190. package/src/contexts.ts +1 -0
  191. package/src/index.ts +1057 -620
  192. package/src/useDragAndDrop.ts +351 -0
  193. package/src/utils.tsx +37 -3
  194. package/src/virtualizer/Layout.ts +200 -0
@@ -13,6 +13,7 @@ import {
13
13
  splitProps,
14
14
  useContext,
15
15
  For,
16
+ Index,
16
17
  Show,
17
18
  } from 'solid-js';
18
19
  import {
@@ -29,6 +30,8 @@ import {
29
30
  type CalendarDate,
30
31
  type DateValue,
31
32
  type RangeValue,
33
+ endOfMonth,
34
+ isSameMonth,
32
35
  } from '@proyecto-viviana/solid-stately';
33
36
  import {
34
37
  type RenderChildren,
@@ -79,6 +82,8 @@ export interface RangeCalendarGridProps extends Omit<AriaCalendarGridProps, 'sta
79
82
  class?: ClassNameOrFunction<RangeCalendarGridRenderProps>;
80
83
  /** The inline style for the element. */
81
84
  style?: StyleOrFunction<RangeCalendarGridRenderProps>;
85
+ /** Number of months to offset from the start. */
86
+ offset?: { months?: number };
82
87
  }
83
88
 
84
89
  export interface RangeCalendarCellRenderProps {
@@ -120,6 +125,8 @@ export interface RangeCalendarCellProps extends SlotProps {
120
125
  // ============================================
121
126
 
122
127
  export const RangeCalendarContext = createContext<RangeCalendarState<DateValue> | null>(null);
128
+ export const RangeCalendarStateContext = createContext<RangeCalendarState<DateValue> | null>(null);
129
+ const RangeCalendarGridMonthContext = createContext<CalendarDate | null>(null);
123
130
 
124
131
  export function useRangeCalendarContext(): RangeCalendarState<DateValue> {
125
132
  const context = useContext(RangeCalendarContext);
@@ -220,18 +227,20 @@ function RangeCalendarInner<T extends DateValue = CalendarDate>(
220
227
  );
221
228
 
222
229
  return (
223
- <RangeCalendarContext.Provider value={state as unknown as RangeCalendarState<DateValue>}>
224
- <div
225
- {...calendarAria.calendarProps}
226
- class={renderProps.class()}
227
- style={renderProps.style()}
228
- data-disabled={dataAttr(state.isDisabled())}
229
- data-readonly={dataAttr(state.isReadOnly())}
230
- data-dragging={dataAttr(state.isDragging())}
231
- >
232
- {props.children}
233
- </div>
234
- </RangeCalendarContext.Provider>
230
+ <RangeCalendarStateContext.Provider value={state as unknown as RangeCalendarState<DateValue>}>
231
+ <RangeCalendarContext.Provider value={state as unknown as RangeCalendarState<DateValue>}>
232
+ <div
233
+ {...calendarAria.calendarProps}
234
+ class={renderProps.class()}
235
+ style={renderProps.style()}
236
+ data-disabled={dataAttr(state.isDisabled())}
237
+ data-readonly={dataAttr(state.isReadOnly())}
238
+ data-dragging={dataAttr(state.isDragging())}
239
+ >
240
+ {props.children}
241
+ </div>
242
+ </RangeCalendarContext.Provider>
243
+ </RangeCalendarStateContext.Provider>
235
244
  );
236
245
  }
237
246
 
@@ -316,10 +325,17 @@ export function RangeCalendarButton(props: RangeCalendarButtonProps): JSX.Elemen
316
325
  export function RangeCalendarGrid(props: RangeCalendarGridProps): JSX.Element {
317
326
  const state = useRangeCalendarContext();
318
327
  const [gridRef, setGridRef] = createSignal<HTMLTableElement | null>(null);
328
+ const startDate = createMemo(() => {
329
+ const offsetMonths = props.offset?.months ?? 0;
330
+ const baseStart = state.visibleRange().start;
331
+ return offsetMonths ? baseStart.add({ months: offsetMonths }) : baseStart;
332
+ });
319
333
 
320
334
  // Create grid ARIA props
321
335
  const gridAria = createCalendarGrid(
322
336
  {
337
+ startDate: startDate(),
338
+ endDate: endOfMonth(startDate()),
323
339
  weekdayStyle: props.weekdayStyle,
324
340
  },
325
341
  state as unknown as Parameters<typeof createCalendarGrid>[1],
@@ -341,48 +357,55 @@ export function RangeCalendarGrid(props: RangeCalendarGridProps): JSX.Element {
341
357
  renderValues
342
358
  );
343
359
 
344
- // Get weeks to render
345
- const weeks = createMemo(() => {
346
- const numWeeks = state.getWeeksInMonth();
347
- return Array.from({ length: numWeeks }, (_, i) => i);
360
+ // Memoize all dates for the grid to avoid reactive loops in render paths.
361
+ const allDates = createMemo(() => {
362
+ const monthStart = startDate();
363
+ const numWeeks = state.getWeeksInMonth(monthStart);
364
+ const weekDates: (CalendarDate | null)[][] = [];
365
+
366
+ for (let weekIndex = 0; weekIndex < numWeeks; weekIndex++) {
367
+ weekDates.push(state.getDatesInWeek(weekIndex, monthStart));
368
+ }
369
+
370
+ return weekDates;
348
371
  });
349
372
 
350
373
  return (
351
- <table
352
- ref={setGridRef}
353
- {...gridAria.gridProps}
354
- class={renderProps.class()}
355
- style={renderProps.style()}
356
- >
357
- <thead {...gridAria.headerProps}>
358
- <tr>
359
- <For each={gridAria.weekDays}>
360
- {(day) => (
361
- <th scope="col" class="solidaria-RangeCalendarHeaderCell">
362
- {day}
363
- </th>
374
+ <RangeCalendarGridMonthContext.Provider value={startDate()}>
375
+ <table
376
+ ref={setGridRef}
377
+ {...gridAria.gridProps}
378
+ class={renderProps.class()}
379
+ style={renderProps.style()}
380
+ >
381
+ <thead {...gridAria.headerProps}>
382
+ <tr>
383
+ <For each={gridAria.weekDays}>
384
+ {(day) => (
385
+ <th scope="col" class="solidaria-RangeCalendarHeaderCell">
386
+ {day}
387
+ </th>
388
+ )}
389
+ </For>
390
+ </tr>
391
+ </thead>
392
+ <tbody>
393
+ <Index each={allDates()}>
394
+ {(weekDates) => (
395
+ <tr>
396
+ <Index each={weekDates()}>
397
+ {(date) => (
398
+ <Show when={date()} fallback={<td />}>
399
+ {props.children?.(date()!)}
400
+ </Show>
401
+ )}
402
+ </Index>
403
+ </tr>
364
404
  )}
365
- </For>
366
- </tr>
367
- </thead>
368
- <tbody>
369
- <For each={weeks()}>
370
- {(weekIndex) => (
371
- <tr>
372
- <For each={state.getDatesInWeek(weekIndex)}>
373
- {(date) => (
374
- <Show when={date}>
375
- <td>
376
- {props.children?.(date!)}
377
- </td>
378
- </Show>
379
- )}
380
- </For>
381
- </tr>
382
- )}
383
- </For>
384
- </tbody>
385
- </table>
405
+ </Index>
406
+ </tbody>
407
+ </table>
408
+ </RangeCalendarGridMonthContext.Provider>
386
409
  );
387
410
  }
388
411
 
@@ -395,11 +418,18 @@ export function RangeCalendarGrid(props: RangeCalendarGridProps): JSX.Element {
395
418
  */
396
419
  export function RangeCalendarCell(props: RangeCalendarCellProps): JSX.Element {
397
420
  const state = useRangeCalendarContext();
421
+ const currentMonthStart = useContext(RangeCalendarGridMonthContext);
398
422
  const [cellRef, setCellRef] = createSignal<HTMLDivElement | null>(null);
423
+ const isOutsideMonth = createMemo(
424
+ () => currentMonthStart != null && !isSameMonth(currentMonthStart, props.date)
425
+ );
399
426
 
400
427
  // Create cell ARIA props
401
428
  const cellAria = createRangeCalendarCell(
402
- { date: props.date },
429
+ () => ({
430
+ date: props.date,
431
+ isOutsideMonth: isOutsideMonth(),
432
+ }),
403
433
  state,
404
434
  cellRef
405
435
  );
@@ -438,23 +468,25 @@ export function RangeCalendarCell(props: RangeCalendarCellProps): JSX.Element {
438
468
  };
439
469
 
440
470
  return (
441
- <div
442
- ref={setCellRef}
443
- {...cellAria.buttonProps}
444
- class={renderProps.class()}
445
- style={renderProps.style()}
446
- data-selected={dataAttr(cellAria.isSelected)}
447
- data-selection-start={dataAttr(cellAria.isSelectionStart)}
448
- data-selection-end={dataAttr(cellAria.isSelectionEnd)}
449
- data-focused={dataAttr(cellAria.isFocused)}
450
- data-disabled={dataAttr(cellAria.isDisabled)}
451
- data-unavailable={dataAttr(cellAria.isUnavailable)}
452
- data-outside-month={dataAttr(cellAria.isOutsideMonth)}
453
- data-today={dataAttr(cellAria.isToday)}
454
- data-pressed={dataAttr(cellAria.isPressed)}
455
- >
456
- {getChildren()}
457
- </div>
471
+ <td {...cellAria.cellProps}>
472
+ <div
473
+ ref={setCellRef}
474
+ {...cellAria.buttonProps}
475
+ class={renderProps.class()}
476
+ style={renderProps.style()}
477
+ data-selected={dataAttr(cellAria.isSelected)}
478
+ data-selection-start={dataAttr(cellAria.isSelectionStart)}
479
+ data-selection-end={dataAttr(cellAria.isSelectionEnd)}
480
+ data-focused={dataAttr(cellAria.isFocused)}
481
+ data-disabled={dataAttr(cellAria.isDisabled)}
482
+ data-unavailable={dataAttr(cellAria.isUnavailable)}
483
+ data-outside-month={dataAttr(cellAria.isOutsideMonth)}
484
+ data-today={dataAttr(cellAria.isToday)}
485
+ data-pressed={dataAttr(cellAria.isPressed)}
486
+ >
487
+ {getChildren()}
488
+ </div>
489
+ </td>
458
490
  );
459
491
  }
460
492
 
@@ -0,0 +1,240 @@
1
+ /**
2
+ * RouterProvider for solidaria-components
3
+ *
4
+ * A context provider for client-side router integration.
5
+ * SolidJS apps typically use TanStack Router or SolidRouter directly;
6
+ * this provides API compatibility with React Aria's RouterProvider.
7
+ */
8
+
9
+ import { type JSX, createContext, useContext } from 'solid-js';
10
+
11
+ // ============================================
12
+ // TYPES
13
+ // ============================================
14
+
15
+ export interface RouterClickModifiers {
16
+ metaKey?: boolean;
17
+ ctrlKey?: boolean;
18
+ altKey?: boolean;
19
+ shiftKey?: boolean;
20
+ }
21
+
22
+ export interface RouterContextValue {
23
+ /** Whether the router is a native browser router (no client-side navigation). */
24
+ isNative: boolean;
25
+ /** Navigate to a given href. */
26
+ navigate: (href: string, routerOptions?: RouterOptions) => void;
27
+ /** Open a link target with router-aware navigation behavior. */
28
+ open: (
29
+ target: Element,
30
+ modifiers: RouterClickModifiers,
31
+ href: string,
32
+ routerOptions?: RouterOptions
33
+ ) => void;
34
+ /** Transform an href for the router. */
35
+ useHref: (href: string) => string;
36
+ }
37
+
38
+ export interface RouterOptions {
39
+ /** Whether to replace the current history entry. */
40
+ replace?: boolean;
41
+ /** Additional router-specific options. */
42
+ [key: string]: unknown;
43
+ }
44
+
45
+ export interface RouterProviderProps {
46
+ /** A function that performs client-side navigation. */
47
+ navigate: (href: string, routerOptions?: RouterOptions) => void;
48
+ /** An optional function that transforms hrefs. */
49
+ useHref?: (href: string) => string;
50
+ /** Children to render. */
51
+ children: JSX.Element;
52
+ }
53
+
54
+ // ============================================
55
+ // CONTEXT
56
+ // ============================================
57
+
58
+ const defaultRouter: RouterContextValue = {
59
+ isNative: true,
60
+ navigate: () => {},
61
+ open: (target, modifiers) => {
62
+ openSyntheticLink(target, modifiers);
63
+ },
64
+ useHref: (href: string) => href,
65
+ };
66
+
67
+ export const RouterContext = createContext<RouterContextValue>(defaultRouter);
68
+
69
+ // ============================================
70
+ // HELPERS
71
+ // ============================================
72
+
73
+ export interface LinkDOMProps {
74
+ href?: string;
75
+ target?: string;
76
+ rel?: string;
77
+ download?: string | boolean;
78
+ ping?: string;
79
+ referrerPolicy?:
80
+ | ''
81
+ | 'no-referrer'
82
+ | 'no-referrer-when-downgrade'
83
+ | 'origin'
84
+ | 'origin-when-cross-origin'
85
+ | 'same-origin'
86
+ | 'strict-origin'
87
+ | 'strict-origin-when-cross-origin'
88
+ | 'unsafe-url';
89
+ }
90
+
91
+ export function shouldClientNavigate(link: HTMLAnchorElement, modifiers: RouterClickModifiers): boolean {
92
+ const target = link.getAttribute('target');
93
+ const sameOrigin = typeof location === 'undefined' ? true : link.origin === location.origin;
94
+ return (
95
+ (!target || target === '_self') &&
96
+ sameOrigin &&
97
+ !link.hasAttribute('download') &&
98
+ !modifiers.metaKey &&
99
+ !modifiers.ctrlKey &&
100
+ !modifiers.altKey &&
101
+ !modifiers.shiftKey
102
+ );
103
+ }
104
+
105
+ export function openLink(target: HTMLAnchorElement, modifiers: RouterClickModifiers): void {
106
+ const event = new MouseEvent('click', {
107
+ metaKey: modifiers.metaKey,
108
+ ctrlKey: modifiers.ctrlKey,
109
+ altKey: modifiers.altKey,
110
+ shiftKey: modifiers.shiftKey,
111
+ detail: 1,
112
+ bubbles: true,
113
+ cancelable: true,
114
+ });
115
+ target.dispatchEvent(event);
116
+ }
117
+
118
+ function getSyntheticLink(target: Element, open: (link: HTMLAnchorElement) => void): void {
119
+ if (target instanceof HTMLAnchorElement) {
120
+ open(target);
121
+ return;
122
+ }
123
+
124
+ const href = target.getAttribute('data-href');
125
+ if (!href) {
126
+ return;
127
+ }
128
+
129
+ const link = document.createElement('a');
130
+ link.href = href;
131
+
132
+ const targetValue = target.getAttribute('data-target');
133
+ if (targetValue) link.target = targetValue;
134
+
135
+ const rel = target.getAttribute('data-rel');
136
+ if (rel) link.rel = rel;
137
+
138
+ const download = target.getAttribute('data-download');
139
+ if (download) link.download = download;
140
+
141
+ const ping = target.getAttribute('data-ping');
142
+ if (ping) link.ping = ping;
143
+
144
+ const referrerPolicy = target.getAttribute('data-referrer-policy');
145
+ if (referrerPolicy) {
146
+ link.referrerPolicy = referrerPolicy;
147
+ }
148
+
149
+ target.appendChild(link);
150
+ open(link);
151
+ target.removeChild(link);
152
+ }
153
+
154
+ function openSyntheticLink(target: Element, modifiers: RouterClickModifiers): void {
155
+ getSyntheticLink(target, (link) => openLink(link, modifiers));
156
+ }
157
+
158
+ export function useLinkProps(props?: LinkDOMProps): LinkDOMProps {
159
+ const router = useRouter();
160
+ const href = props?.href ?? '';
161
+ return {
162
+ href: props?.href ? router.useHref(href) : undefined,
163
+ target: props?.target,
164
+ rel: props?.rel,
165
+ download: props?.download,
166
+ ping: props?.ping,
167
+ referrerPolicy: props?.referrerPolicy,
168
+ };
169
+ }
170
+
171
+ export function handleLinkClick(
172
+ event: MouseEvent,
173
+ router: RouterContextValue,
174
+ href: string | undefined,
175
+ routerOptions?: RouterOptions
176
+ ): void {
177
+ if (
178
+ !router.isNative &&
179
+ event.currentTarget instanceof HTMLAnchorElement &&
180
+ event.currentTarget.href &&
181
+ !event.defaultPrevented &&
182
+ href &&
183
+ shouldClientNavigate(event.currentTarget, event)
184
+ ) {
185
+ event.preventDefault();
186
+ router.open(event.currentTarget, event, href, routerOptions);
187
+ }
188
+ }
189
+
190
+ // ============================================
191
+ // COMPONENT
192
+ // ============================================
193
+
194
+ /**
195
+ * A RouterProvider accepts a `navigate` function from a client-side router,
196
+ * and provides it to all nested solidaria links to enable client-side navigation.
197
+ *
198
+ * @example
199
+ * ```tsx
200
+ * import { useNavigate } from '@solidjs/router';
201
+ *
202
+ * function App() {
203
+ * const navigate = useNavigate();
204
+ * return (
205
+ * <RouterProvider navigate={navigate}>
206
+ * <Link href="/about">About</Link>
207
+ * </RouterProvider>
208
+ * );
209
+ * }
210
+ * ```
211
+ */
212
+ export function RouterProvider(props: RouterProviderProps): JSX.Element {
213
+ const ctx: RouterContextValue = {
214
+ isNative: false,
215
+ navigate: props.navigate,
216
+ open: (target, modifiers, href, routerOptions) => {
217
+ getSyntheticLink(target, (link) => {
218
+ if (shouldClientNavigate(link, modifiers)) {
219
+ props.navigate(href, routerOptions);
220
+ } else {
221
+ openLink(link, modifiers);
222
+ }
223
+ });
224
+ },
225
+ useHref: props.useHref ?? ((href: string) => href),
226
+ };
227
+
228
+ return (
229
+ <RouterContext.Provider value={ctx}>
230
+ {props.children}
231
+ </RouterContext.Provider>
232
+ );
233
+ }
234
+
235
+ /**
236
+ * Returns the current router context value.
237
+ */
238
+ export function useRouter(): RouterContextValue {
239
+ return useContext(RouterContext);
240
+ }