@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.
- package/LICENSE +21 -0
- package/dist/ActionBar.d.ts +71 -0
- package/dist/ActionBar.d.ts.map +1 -0
- package/dist/ActionGroup.d.ts +74 -0
- package/dist/ActionGroup.d.ts.map +1 -0
- package/dist/Alert.d.ts +70 -0
- package/dist/Alert.d.ts.map +1 -0
- package/dist/Breadcrumbs.d.ts +10 -2
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +4 -0
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +13 -0
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +2 -2
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +125 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/Color.d.ts +114 -2
- package/dist/Color.d.ts.map +1 -1
- package/dist/ColorEditor.d.ts +42 -0
- package/dist/ColorEditor.d.ts.map +1 -0
- package/dist/ComboBox.d.ts +64 -0
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ContextualHelpTrigger.d.ts +40 -0
- package/dist/ContextualHelpTrigger.d.ts.map +1 -0
- package/dist/DateField.d.ts +27 -2
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +67 -2
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Disclosure.d.ts +2 -0
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/DragAndDrop.d.ts +80 -0
- package/dist/DragAndDrop.d.ts.map +1 -0
- package/dist/DragPreview.d.ts +14 -0
- package/dist/DragPreview.d.ts.map +1 -0
- package/dist/DropZone.d.ts +27 -0
- package/dist/DropZone.d.ts.map +1 -0
- package/dist/FieldError.d.ts +23 -0
- package/dist/FieldError.d.ts.map +1 -0
- package/dist/FileTrigger.d.ts +26 -0
- package/dist/FileTrigger.d.ts.map +1 -0
- package/dist/Focusable.d.ts +27 -0
- package/dist/Focusable.d.ts.map +1 -0
- package/dist/Form.d.ts +27 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/GridList.d.ts +40 -1
- package/dist/GridList.d.ts.map +1 -1
- package/dist/Icon.d.ts +57 -0
- package/dist/Icon.d.ts.map +1 -0
- package/dist/Keyboard.d.ts +13 -0
- package/dist/Keyboard.d.ts.map +1 -0
- package/dist/Link.d.ts.map +1 -1
- package/dist/ListBox.d.ts +43 -1
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListDropTargetDelegate.d.ts +38 -0
- package/dist/ListDropTargetDelegate.d.ts.map +1 -0
- package/dist/Menu.d.ts +20 -2
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +2 -2
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +2 -0
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +2 -0
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +4 -2
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Pressable.d.ts +27 -0
- package/dist/Pressable.d.ts.map +1 -0
- package/dist/ProgressBar.d.ts +2 -2
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RangeCalendar.d.ts +5 -0
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RouterProvider.d.ts +75 -0
- package/dist/RouterProvider.d.ts.map +1 -0
- package/dist/SearchField.d.ts +2 -3
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +11 -0
- package/dist/Select.d.ts.map +1 -1
- package/dist/SelectionIndicator.d.ts +30 -0
- package/dist/SelectionIndicator.d.ts.map +1 -0
- package/dist/SharedElementTransition.d.ts +39 -0
- package/dist/SharedElementTransition.d.ts.map +1 -0
- package/dist/Slider.d.ts +6 -3
- package/dist/Slider.d.ts.map +1 -1
- package/dist/Table.d.ts +39 -0
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +4 -3
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +12 -2
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/Text.d.ts +10 -0
- package/dist/Text.d.ts.map +1 -0
- package/dist/TextField.d.ts +4 -0
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +26 -1
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/Toast.d.ts.map +1 -1
- package/dist/ToggleButton.d.ts +30 -0
- package/dist/ToggleButton.d.ts.map +1 -0
- package/dist/ToggleButtonGroup.d.ts +33 -0
- package/dist/ToggleButtonGroup.d.ts.map +1 -0
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +9 -0
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +44 -2
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Virtualizer.d.ts +61 -0
- package/dist/Virtualizer.d.ts.map +1 -0
- package/dist/VirtualizerLayouts.d.ts +82 -0
- package/dist/VirtualizerLayouts.d.ts.map +1 -0
- package/dist/VisuallyHidden.d.ts +3 -1
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +1 -0
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +57 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13961 -5946
- package/dist/index.js.map +1 -7
- package/dist/index.ssr.js +9612 -2401
- package/dist/index.ssr.js.map +1 -7
- package/dist/useDragAndDrop.d.ts +93 -0
- package/dist/useDragAndDrop.d.ts.map +1 -0
- package/dist/utils.d.ts +7 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/virtualizer/Layout.d.ts +79 -0
- package/dist/virtualizer/Layout.d.ts.map +1 -0
- package/package.json +8 -6
- package/src/ActionBar.tsx +248 -0
- package/src/ActionGroup.tsx +285 -0
- package/src/Alert.tsx +177 -0
- package/src/Autocomplete.tsx +1 -1
- package/src/Breadcrumbs.tsx +103 -17
- package/src/Button.tsx +65 -21
- package/src/Calendar.tsx +179 -53
- package/src/Checkbox.tsx +1 -2
- package/src/Collection.tsx +341 -0
- package/src/Color.tsx +652 -34
- package/src/ColorEditor.tsx +231 -0
- package/src/ComboBox.tsx +315 -81
- package/src/ContextualHelpTrigger.tsx +183 -0
- package/src/DateField.tsx +93 -19
- package/src/DatePicker.tsx +495 -25
- package/src/Dialog.tsx +40 -9
- package/src/Disclosure.tsx +33 -27
- package/src/DragAndDrop.tsx +334 -0
- package/src/DragPreview.tsx +45 -0
- package/src/DropZone.tsx +213 -0
- package/src/FieldError.tsx +67 -0
- package/src/FileTrigger.tsx +83 -0
- package/src/Focusable.tsx +106 -0
- package/src/Form.tsx +85 -0
- package/src/GridList.tsx +379 -41
- package/src/Icon.tsx +154 -0
- package/src/Keyboard.tsx +26 -0
- package/src/Link.tsx +14 -1
- package/src/ListBox.tsx +484 -33
- package/src/ListDropTargetDelegate.ts +282 -0
- package/src/Menu.tsx +388 -35
- package/src/Meter.tsx +7 -3
- package/src/Modal.tsx +32 -4
- package/src/NumberField.tsx +163 -43
- package/src/Popover.tsx +136 -180
- package/src/Pressable.tsx +108 -0
- package/src/ProgressBar.tsx +7 -3
- package/src/RadioGroup.tsx +35 -25
- package/src/RangeCalendar.tsx +100 -68
- package/src/RouterProvider.tsx +240 -0
- package/src/SearchField.tsx +142 -34
- package/src/Select.tsx +221 -73
- package/src/SelectionIndicator.tsx +105 -0
- package/src/SharedElementTransition.tsx +258 -0
- package/src/Slider.tsx +16 -6
- package/src/Table.tsx +417 -57
- package/src/Tabs.tsx +68 -35
- package/src/TagGroup.tsx +121 -36
- package/src/Text.tsx +18 -0
- package/src/TextField.tsx +25 -8
- package/src/TimeField.tsx +101 -151
- package/src/Toast.tsx +108 -14
- package/src/ToggleButton.tsx +159 -0
- package/src/ToggleButtonGroup.tsx +136 -0
- package/src/Toolbar.tsx +14 -8
- package/src/Tooltip.tsx +108 -19
- package/src/Tree.tsx +1143 -87
- package/src/Virtualizer.tsx +702 -0
- package/src/VirtualizerLayouts.ts +265 -0
- package/src/VisuallyHidden.tsx +15 -21
- package/src/contexts.ts +1 -0
- package/src/index.ts +1057 -620
- package/src/useDragAndDrop.ts +351 -0
- package/src/utils.tsx +37 -3
- package/src/virtualizer/Layout.ts +200 -0
package/src/RangeCalendar.tsx
CHANGED
|
@@ -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
|
-
<
|
|
224
|
-
<
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
//
|
|
345
|
-
const
|
|
346
|
-
const
|
|
347
|
-
|
|
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
|
-
<
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
<
|
|
359
|
-
<
|
|
360
|
-
{
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
</
|
|
366
|
-
</
|
|
367
|
-
</
|
|
368
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
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
|
+
}
|