@proyecto-viviana/solidaria-components 0.2.9 → 0.3.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.
- package/README.md +39 -272
- package/dist/ActionBar.d.ts +21 -13
- package/dist/ActionBar.d.ts.map +1 -1
- package/dist/ActionGroup.d.ts +8 -8
- package/dist/ActionGroup.d.ts.map +1 -1
- package/dist/Alert.d.ts +5 -5
- package/dist/Alert.d.ts.map +1 -1
- package/dist/Autocomplete.d.ts +5 -5
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Breadcrumbs.d.ts +18 -7
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +24 -5
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +38 -7
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +32 -7
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +19 -14
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Color.d.ts +103 -14
- package/dist/Color.d.ts.map +1 -1
- package/dist/ColorEditor.d.ts +6 -6
- package/dist/ColorEditor.d.ts.map +1 -1
- package/dist/ComboBox.d.ts +85 -19
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ContextualHelpTrigger.d.ts +2 -2
- package/dist/ContextualHelpTrigger.d.ts.map +1 -1
- package/dist/DateField.d.ts +8 -6
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +53 -22
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DateRangePickerContext.d.ts +30 -0
- package/dist/DateRangePickerContext.d.ts.map +1 -0
- package/dist/Dialog.d.ts +5 -5
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Disclosure.d.ts +23 -5
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/DragAndDrop.d.ts +6 -6
- package/dist/DragAndDrop.d.ts.map +1 -1
- package/dist/DragPreview.d.ts +2 -2
- package/dist/DragPreview.d.ts.map +1 -1
- package/dist/DropZone.d.ts +4 -4
- package/dist/DropZone.d.ts.map +1 -1
- package/dist/FieldError.d.ts +9 -5
- package/dist/FieldError.d.ts.map +1 -1
- package/dist/FileTrigger.d.ts +3 -3
- package/dist/FileTrigger.d.ts.map +1 -1
- package/dist/Focusable.d.ts +2 -2
- package/dist/Focusable.d.ts.map +1 -1
- package/dist/Form.d.ts +18 -4
- package/dist/Form.d.ts.map +1 -1
- package/dist/GridList.d.ts +32 -12
- package/dist/GridList.d.ts.map +1 -1
- package/dist/HiddenDateInput.d.ts +26 -0
- package/dist/HiddenDateInput.d.ts.map +1 -0
- package/dist/HiddenTimeInput.d.ts +25 -0
- package/dist/HiddenTimeInput.d.ts.map +1 -0
- package/dist/Icon.d.ts +5 -5
- package/dist/Icon.d.ts.map +1 -1
- package/dist/Keyboard.d.ts +1 -1
- package/dist/Landmark.d.ts +3 -3
- package/dist/Landmark.d.ts.map +1 -1
- package/dist/Link.d.ts +10 -4
- package/dist/Link.d.ts.map +1 -1
- package/dist/ListBox.d.ts +32 -12
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListDropTargetDelegate.d.ts +6 -6
- package/dist/ListDropTargetDelegate.d.ts.map +1 -1
- package/dist/Menu.d.ts +65 -14
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +3 -3
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +5 -5
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +8 -12
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +28 -5
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Pressable.d.ts +2 -2
- package/dist/Pressable.d.ts.map +1 -1
- package/dist/ProgressBar.d.ts +5 -3
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/RadioGroup.d.ts +43 -9
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RangeCalendar.d.ts +34 -7
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RouterProvider.d.ts +2 -2
- package/dist/RouterProvider.d.ts.map +1 -1
- package/dist/SearchField.d.ts +23 -20
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +41 -11
- package/dist/Select.d.ts.map +1 -1
- package/dist/SelectionIndicator.d.ts +3 -3
- package/dist/SelectionIndicator.d.ts.map +1 -1
- package/dist/Separator.d.ts +9 -3
- package/dist/Separator.d.ts.map +1 -1
- package/dist/SharedElementTransition.d.ts +6 -4
- package/dist/SharedElementTransition.d.ts.map +1 -1
- package/dist/Slider.d.ts +12 -8
- package/dist/Slider.d.ts.map +1 -1
- package/dist/StepList.d.ts +90 -0
- package/dist/StepList.d.ts.map +1 -0
- package/dist/Switch.d.ts +11 -5
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Table.d.ts +187 -23
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +45 -9
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +12 -10
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/Text.d.ts +2 -2
- package/dist/TextField.d.ts +15 -11
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +6 -6
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/Toast.d.ts +29 -14
- package/dist/Toast.d.ts.map +1 -1
- package/dist/ToggleButton.d.ts +11 -5
- package/dist/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButtonGroup.d.ts +7 -7
- package/dist/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/Toolbar.d.ts +7 -3
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +50 -8
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +66 -17
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Virtualizer.d.ts +12 -12
- package/dist/Virtualizer.d.ts.map +1 -1
- package/dist/VirtualizerLayouts.d.ts +2 -2
- package/dist/VirtualizerLayouts.d.ts.map +1 -1
- package/dist/VisuallyHidden.d.ts +1 -1
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +5 -1
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +73 -71
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23247 -18564
- package/dist/index.js.map +1 -1
- package/dist/index.jsx +18110 -0
- package/dist/index.jsx.map +1 -0
- package/dist/useDragAndDrop.d.ts +13 -13
- package/dist/useDragAndDrop.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/virtualizer/Layout.d.ts +1 -1
- package/dist/virtualizer/Layout.d.ts.map +1 -1
- package/package.json +31 -32
- package/src/ActionBar.tsx +75 -72
- package/src/ActionGroup.tsx +53 -61
- package/src/Alert.tsx +17 -42
- package/src/Autocomplete.tsx +39 -44
- package/src/Breadcrumbs.tsx +149 -80
- package/src/Button.tsx +267 -70
- package/src/Calendar.tsx +218 -138
- package/src/Checkbox.tsx +413 -121
- package/src/Collection.tsx +67 -58
- package/src/Color.tsx +803 -380
- package/src/ColorEditor.tsx +131 -149
- package/src/ComboBox.tsx +414 -249
- package/src/ContextualHelpTrigger.tsx +86 -74
- package/src/DateField.tsx +185 -91
- package/src/DatePicker.tsx +524 -213
- package/src/DateRangePickerContext.tsx +44 -0
- package/src/Dialog.tsx +156 -118
- package/src/Disclosure.tsx +127 -80
- package/src/DragAndDrop.tsx +60 -54
- package/src/DragPreview.tsx +13 -11
- package/src/DropZone.tsx +42 -22
- package/src/FieldError.tsx +45 -23
- package/src/FileTrigger.tsx +19 -19
- package/src/Focusable.tsx +21 -24
- package/src/Form.tsx +71 -16
- package/src/GridList.tsx +273 -197
- package/src/HiddenDateInput.tsx +153 -0
- package/src/HiddenTimeInput.tsx +133 -0
- package/src/Icon.tsx +22 -43
- package/src/Keyboard.tsx +3 -3
- package/src/Landmark.tsx +37 -63
- package/src/Link.tsx +125 -75
- package/src/ListBox.tsx +332 -233
- package/src/ListDropTargetDelegate.ts +81 -80
- package/src/Menu.tsx +1023 -274
- package/src/Meter.tsx +38 -56
- package/src/Modal.tsx +243 -175
- package/src/NumberField.tsx +139 -143
- package/src/Popover.tsx +386 -233
- package/src/Pressable.tsx +21 -21
- package/src/ProgressBar.tsx +48 -57
- package/src/RadioGroup.tsx +524 -122
- package/src/RangeCalendar.tsx +157 -90
- package/src/RouterProvider.tsx +30 -47
- package/src/SearchField.tsx +362 -143
- package/src/Select.tsx +656 -233
- package/src/SelectionIndicator.tsx +18 -15
- package/src/Separator.tsx +47 -49
- package/src/SharedElementTransition.tsx +103 -97
- package/src/Slider.tsx +138 -98
- package/src/StepList.tsx +272 -0
- package/src/Switch.tsx +93 -46
- package/src/Table.tsx +1308 -342
- package/src/Tabs.tsx +324 -103
- package/src/TagGroup.tsx +139 -126
- package/src/Text.tsx +3 -3
- package/src/TextField.tsx +389 -79
- package/src/TimeField.tsx +136 -76
- package/src/Toast.tsx +209 -157
- package/src/ToggleButton.tsx +47 -37
- package/src/ToggleButtonGroup.tsx +39 -34
- package/src/Toolbar.tsx +54 -69
- package/src/Tooltip.tsx +387 -119
- package/src/Tree.tsx +651 -368
- package/src/Virtualizer.tsx +208 -180
- package/src/VirtualizerLayouts.ts +45 -30
- package/src/VisuallyHidden.tsx +19 -19
- package/src/contexts.ts +29 -37
- package/src/index.ts +110 -195
- package/src/useDragAndDrop.ts +87 -71
- package/src/utils.tsx +40 -55
- package/src/virtualizer/Layout.ts +14 -22
- package/dist/index.ssr.js +0 -16996
- package/dist/index.ssr.js.map +0 -1
|
@@ -2,22 +2,15 @@
|
|
|
2
2
|
* Shared SelectionIndicator primitive for selected collection items.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
type JSX,
|
|
7
|
-
createContext,
|
|
8
|
-
createMemo,
|
|
9
|
-
splitProps,
|
|
10
|
-
useContext,
|
|
11
|
-
Show,
|
|
12
|
-
} from 'solid-js';
|
|
5
|
+
import { type JSX, createContext, createMemo, splitProps, useContext, Show } from "solid-js";
|
|
13
6
|
import {
|
|
14
7
|
type RenderChildren,
|
|
15
8
|
type ClassNameOrFunction,
|
|
16
9
|
type StyleOrFunction,
|
|
17
10
|
type SlotProps,
|
|
18
11
|
useRenderProps,
|
|
19
|
-
} from
|
|
20
|
-
import { SharedElement, useHasSharedElementTransitionScope } from
|
|
12
|
+
} from "./utils";
|
|
13
|
+
import { SharedElement, useHasSharedElementTransitionScope } from "./SharedElementTransition";
|
|
21
14
|
|
|
22
15
|
export interface SelectionIndicatorContextValue {
|
|
23
16
|
isSelected: () => boolean;
|
|
@@ -30,7 +23,8 @@ export interface SelectionIndicatorRenderProps {
|
|
|
30
23
|
isSelected: boolean;
|
|
31
24
|
}
|
|
32
25
|
|
|
33
|
-
export interface SelectionIndicatorProps
|
|
26
|
+
export interface SelectionIndicatorProps
|
|
27
|
+
extends SlotProps, Omit<JSX.HTMLAttributes<HTMLSpanElement>, "class" | "style" | "children"> {
|
|
34
28
|
/** Optional controlled selected state override. */
|
|
35
29
|
isSelected?: boolean;
|
|
36
30
|
/** Whether to keep mounted when not selected. */
|
|
@@ -47,7 +41,14 @@ export interface SelectionIndicatorProps extends SlotProps, Omit<JSX.HTMLAttribu
|
|
|
47
41
|
* SelectionIndicator renders when its parent item is selected.
|
|
48
42
|
*/
|
|
49
43
|
export function SelectionIndicator(props: SelectionIndicatorProps): JSX.Element {
|
|
50
|
-
const [local, domProps] = splitProps(props, [
|
|
44
|
+
const [local, domProps] = splitProps(props, [
|
|
45
|
+
"isSelected",
|
|
46
|
+
"shouldForceMount",
|
|
47
|
+
"children",
|
|
48
|
+
"class",
|
|
49
|
+
"style",
|
|
50
|
+
"slot",
|
|
51
|
+
]);
|
|
51
52
|
|
|
52
53
|
const context = useContext(SelectionIndicatorContext);
|
|
53
54
|
const hasSharedElementScope = useHasSharedElementTransitionScope();
|
|
@@ -63,13 +64,15 @@ export function SelectionIndicator(props: SelectionIndicatorProps): JSX.Element
|
|
|
63
64
|
children: local.children,
|
|
64
65
|
class: local.class,
|
|
65
66
|
style: local.style,
|
|
66
|
-
defaultClassName:
|
|
67
|
+
defaultClassName: "solidaria-SelectionIndicator",
|
|
67
68
|
},
|
|
68
|
-
renderValues
|
|
69
|
+
renderValues,
|
|
69
70
|
);
|
|
70
71
|
|
|
71
72
|
const sharedElementProps = createMemo(() => {
|
|
72
|
-
const { ref: _ref, ...rest } = domProps as JSX.HTMLAttributes<HTMLSpanElement> & {
|
|
73
|
+
const { ref: _ref, ...rest } = domProps as JSX.HTMLAttributes<HTMLSpanElement> & {
|
|
74
|
+
ref?: unknown;
|
|
75
|
+
};
|
|
73
76
|
return rest;
|
|
74
77
|
});
|
|
75
78
|
|
package/src/Separator.tsx
CHANGED
|
@@ -5,51 +5,42 @@
|
|
|
5
5
|
* Port of react-aria-components/src/Separator.tsx
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
createContext,
|
|
11
|
-
createMemo,
|
|
12
|
-
splitProps,
|
|
13
|
-
} from 'solid-js';
|
|
14
|
-
import { Dynamic } from 'solid-js/web';
|
|
8
|
+
import { type JSX, createContext, createMemo, splitProps } from "solid-js";
|
|
9
|
+
import { Dynamic } from "solid-js/web";
|
|
15
10
|
import {
|
|
16
11
|
createSeparator,
|
|
17
12
|
type AriaSeparatorProps,
|
|
18
13
|
type Orientation,
|
|
19
|
-
} from
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} from './utils';
|
|
14
|
+
} from "@proyecto-viviana/solidaria";
|
|
15
|
+
import { type SlotProps, filterDOMProps } from "./utils";
|
|
16
|
+
|
|
17
|
+
type RefLike<T> = ((el: T) => void) | { current?: T | null } | undefined;
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
function assignRef<T>(ref: RefLike<T>, el: T): void {
|
|
20
|
+
if (!ref) return;
|
|
21
|
+
if (typeof ref === "function") {
|
|
22
|
+
ref(el);
|
|
23
|
+
} else {
|
|
24
|
+
ref.current = el;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
28
27
|
|
|
29
28
|
export interface SeparatorRenderProps {
|
|
30
29
|
/** The orientation of the separator. */
|
|
31
30
|
orientation: Orientation;
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
export interface SeparatorProps
|
|
35
|
-
extends AriaSeparatorProps,
|
|
36
|
-
SlotProps {
|
|
33
|
+
export interface SeparatorProps extends AriaSeparatorProps, SlotProps {
|
|
37
34
|
/** The CSS className for the element. A function may be provided to receive render props. */
|
|
38
35
|
class?: string | ((renderProps: SeparatorRenderProps) => string);
|
|
39
36
|
/** The inline style for the element. A function may be provided to receive render props. */
|
|
40
37
|
style?: JSX.CSSProperties | ((renderProps: SeparatorRenderProps) => JSX.CSSProperties);
|
|
38
|
+
/** Ref for the underlying separator element. */
|
|
39
|
+
ref?: RefLike<HTMLElement>;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
// ============================================
|
|
44
|
-
// CONTEXT
|
|
45
|
-
// ============================================
|
|
46
|
-
|
|
47
42
|
export const SeparatorContext = createContext<SeparatorProps | null>(null);
|
|
48
43
|
|
|
49
|
-
// ============================================
|
|
50
|
-
// SEPARATOR COMPONENT
|
|
51
|
-
// ============================================
|
|
52
|
-
|
|
53
44
|
/**
|
|
54
45
|
* A separator is a visual divider between two groups of content,
|
|
55
46
|
* e.g. groups of menu items or sections of a page.
|
|
@@ -66,55 +57,61 @@ export const SeparatorContext = createContext<SeparatorProps | null>(null);
|
|
|
66
57
|
* ```
|
|
67
58
|
*/
|
|
68
59
|
export function Separator(props: SeparatorProps): JSX.Element {
|
|
69
|
-
const [local, ariaProps] = splitProps(props, [
|
|
70
|
-
'class',
|
|
71
|
-
'style',
|
|
72
|
-
'slot',
|
|
73
|
-
]);
|
|
60
|
+
const [local, ariaProps] = splitProps(props, ["class", "style", "ref", "slot"]);
|
|
74
61
|
|
|
75
|
-
// Determine the element type
|
|
76
62
|
const elementType = createMemo(() => {
|
|
77
|
-
let element = ariaProps.elementType ||
|
|
63
|
+
let element = ariaProps.elementType || "hr";
|
|
78
64
|
// If vertical and using hr, switch to div since hr is inherently horizontal
|
|
79
|
-
if (element ===
|
|
80
|
-
element =
|
|
65
|
+
if (element === "hr" && ariaProps.orientation === "vertical") {
|
|
66
|
+
element = "div";
|
|
81
67
|
}
|
|
82
68
|
return element;
|
|
83
69
|
});
|
|
84
70
|
|
|
85
|
-
// Create separator aria props
|
|
86
71
|
const separatorAria = createSeparator({
|
|
87
|
-
get orientation() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
get
|
|
91
|
-
|
|
72
|
+
get orientation() {
|
|
73
|
+
return ariaProps.orientation;
|
|
74
|
+
},
|
|
75
|
+
get elementType() {
|
|
76
|
+
return ariaProps.elementType;
|
|
77
|
+
},
|
|
78
|
+
get "aria-label"() {
|
|
79
|
+
return ariaProps["aria-label"];
|
|
80
|
+
},
|
|
81
|
+
get "aria-labelledby"() {
|
|
82
|
+
return ariaProps["aria-labelledby"];
|
|
83
|
+
},
|
|
84
|
+
get "aria-describedby"() {
|
|
85
|
+
return ariaProps["aria-describedby"];
|
|
86
|
+
},
|
|
87
|
+
get "aria-details"() {
|
|
88
|
+
return ariaProps["aria-details"];
|
|
89
|
+
},
|
|
90
|
+
get id() {
|
|
91
|
+
return ariaProps.id;
|
|
92
|
+
},
|
|
92
93
|
});
|
|
93
94
|
|
|
94
|
-
// Render props values
|
|
95
95
|
const renderValues = createMemo<SeparatorRenderProps>(() => ({
|
|
96
|
-
orientation: ariaProps.orientation ??
|
|
96
|
+
orientation: ariaProps.orientation ?? "horizontal",
|
|
97
97
|
}));
|
|
98
98
|
|
|
99
|
-
// Resolve class
|
|
100
99
|
const resolvedClass = createMemo(() => {
|
|
101
100
|
const cls = local.class;
|
|
102
|
-
if (typeof cls ===
|
|
101
|
+
if (typeof cls === "function") {
|
|
103
102
|
return cls(renderValues());
|
|
104
103
|
}
|
|
105
|
-
return cls ??
|
|
104
|
+
return cls ?? "solidaria-Separator";
|
|
106
105
|
});
|
|
107
106
|
|
|
108
|
-
// Resolve style
|
|
109
107
|
const resolvedStyle = createMemo(() => {
|
|
110
108
|
const style = local.style;
|
|
111
|
-
if (typeof style ===
|
|
109
|
+
if (typeof style === "function") {
|
|
112
110
|
return style(renderValues());
|
|
113
111
|
}
|
|
114
112
|
return style;
|
|
115
113
|
});
|
|
116
114
|
|
|
117
|
-
// Filter DOM props
|
|
118
115
|
const domProps = createMemo(() => filterDOMProps(ariaProps, { global: true }));
|
|
119
116
|
|
|
120
117
|
return (
|
|
@@ -122,6 +119,7 @@ export function Separator(props: SeparatorProps): JSX.Element {
|
|
|
122
119
|
component={elementType()}
|
|
123
120
|
{...domProps()}
|
|
124
121
|
{...separatorAria.separatorProps}
|
|
122
|
+
ref={(el: HTMLElement) => assignRef(local.ref, el)}
|
|
125
123
|
class={resolvedClass()}
|
|
126
124
|
style={resolvedStyle()}
|
|
127
125
|
slot={local.slot}
|
|
@@ -19,20 +19,20 @@ import {
|
|
|
19
19
|
useContext,
|
|
20
20
|
Show,
|
|
21
21
|
on,
|
|
22
|
-
} from
|
|
22
|
+
} from "solid-js";
|
|
23
23
|
import {
|
|
24
24
|
type ClassNameOrFunction,
|
|
25
25
|
type StyleOrFunction,
|
|
26
26
|
type RenderChildren,
|
|
27
27
|
useRenderProps,
|
|
28
28
|
filterDOMProps,
|
|
29
|
-
} from
|
|
29
|
+
} from "./utils";
|
|
30
30
|
|
|
31
|
-
type SharedElementLifecycle =
|
|
31
|
+
type SharedElementLifecycle = "hidden" | "entering" | "visible" | "exiting";
|
|
32
32
|
|
|
33
33
|
/** Safe wrapper — jsdom doesn't implement the Web Animations API. */
|
|
34
34
|
function getAnimations(el: HTMLElement): Animation[] {
|
|
35
|
-
return typeof el.getAnimations ===
|
|
35
|
+
return typeof el.getAnimations === "function" ? el.getAnimations() : [];
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
interface Snapshot {
|
|
@@ -63,9 +63,7 @@ export function SharedElementTransition(props: SharedElementTransitionProps): JS
|
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
return (
|
|
66
|
-
<SharedElementContext.Provider value={scope}>
|
|
67
|
-
{props.children}
|
|
68
|
-
</SharedElementContext.Provider>
|
|
66
|
+
<SharedElementContext.Provider value={scope}>{props.children}</SharedElementContext.Provider>
|
|
69
67
|
);
|
|
70
68
|
}
|
|
71
69
|
|
|
@@ -74,8 +72,10 @@ export interface SharedElementRenderProps {
|
|
|
74
72
|
isExiting: boolean;
|
|
75
73
|
}
|
|
76
74
|
|
|
77
|
-
export interface SharedElementPropsBase
|
|
78
|
-
|
|
75
|
+
export interface SharedElementPropsBase extends Omit<
|
|
76
|
+
JSX.HTMLAttributes<HTMLDivElement>,
|
|
77
|
+
"children" | "class" | "style" | "ref"
|
|
78
|
+
> {
|
|
79
79
|
children?: RenderChildren<SharedElementRenderProps>;
|
|
80
80
|
class?: ClassNameOrFunction<SharedElementRenderProps>;
|
|
81
81
|
style?: StyleOrFunction<SharedElementRenderProps>;
|
|
@@ -84,7 +84,7 @@ export interface SharedElementPropsBase
|
|
|
84
84
|
export interface SharedElementProps extends SharedElementPropsBase {
|
|
85
85
|
name: string;
|
|
86
86
|
isVisible?: boolean;
|
|
87
|
-
ref?:
|
|
87
|
+
ref?: ((el: HTMLDivElement) => void) | { current?: HTMLDivElement };
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/**
|
|
@@ -94,15 +94,20 @@ export interface SharedElementProps extends SharedElementPropsBase {
|
|
|
94
94
|
export function SharedElement(props: SharedElementProps): JSX.Element | null {
|
|
95
95
|
const scope = useContext(SharedElementContext);
|
|
96
96
|
if (!scope) {
|
|
97
|
-
throw new Error(
|
|
97
|
+
throw new Error("<SharedElement> must be rendered inside a <SharedElementTransition>");
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
const [local, domProps] = splitProps(props, [
|
|
101
|
-
|
|
101
|
+
"name",
|
|
102
|
+
"isVisible",
|
|
103
|
+
"children",
|
|
104
|
+
"class",
|
|
105
|
+
"style",
|
|
106
|
+
"ref",
|
|
102
107
|
]);
|
|
103
108
|
|
|
104
109
|
const [lifecycle, setLifecycle] = createSignal<SharedElementLifecycle>(
|
|
105
|
-
local.isVisible === false ?
|
|
110
|
+
local.isVisible === false ? "hidden" : "visible",
|
|
106
111
|
);
|
|
107
112
|
|
|
108
113
|
let elementRef: HTMLDivElement | undefined;
|
|
@@ -112,99 +117,100 @@ export function SharedElement(props: SharedElementProps): JSX.Element | null {
|
|
|
112
117
|
elementRef = el;
|
|
113
118
|
// Forward ref to consumer
|
|
114
119
|
const userRef = local.ref;
|
|
115
|
-
if (typeof userRef ===
|
|
120
|
+
if (typeof userRef === "function") {
|
|
116
121
|
userRef(el);
|
|
117
122
|
} else if (userRef !== undefined) {
|
|
118
|
-
|
|
119
|
-
(local as any).ref = el;
|
|
123
|
+
userRef.current = el;
|
|
120
124
|
}
|
|
121
125
|
};
|
|
122
126
|
|
|
123
127
|
// Handle visibility transitions with FLIP animation
|
|
124
|
-
createEffect(
|
|
125
|
-
(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
createEffect(
|
|
129
|
+
on(
|
|
130
|
+
() => local.isVisible !== false,
|
|
131
|
+
(isVisible) => {
|
|
132
|
+
const name = local.name;
|
|
133
|
+
const element = elementRef;
|
|
129
134
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
if (frame != null) {
|
|
136
|
+
cancelAnimationFrame(frame);
|
|
137
|
+
frame = undefined;
|
|
138
|
+
}
|
|
134
139
|
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
if (isVisible && element) {
|
|
141
|
+
const prevSnapshot = scope.snapshots[name];
|
|
137
142
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
if (prevSnapshot) {
|
|
144
|
+
// FLIP: Element is transitioning from a previous instance.
|
|
145
|
+
setLifecycle("visible");
|
|
146
|
+
const animations = getAnimations(element);
|
|
142
147
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
// Set properties to animate from.
|
|
149
|
+
const values = prevSnapshot.style.map(([property, prevValue]) => {
|
|
150
|
+
const value = element.style.getPropertyValue(property);
|
|
151
|
+
if (property === "translate") {
|
|
152
|
+
const prevRect = prevSnapshot.rect;
|
|
153
|
+
const currentRect = element.getBoundingClientRect();
|
|
154
|
+
const deltaX = prevRect.left - currentRect.left;
|
|
155
|
+
const deltaY = prevRect.top - currentRect.top;
|
|
156
|
+
element.style.setProperty("translate", `${deltaX}px ${deltaY}px`);
|
|
157
|
+
} else {
|
|
158
|
+
element.style.setProperty(property, prevValue);
|
|
159
|
+
}
|
|
160
|
+
return [property, value] as [string, string];
|
|
161
|
+
});
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
// Cancel any new animations triggered by these properties.
|
|
164
|
+
for (const a of getAnimations(element)) {
|
|
165
|
+
if (!animations.includes(a)) {
|
|
166
|
+
a.cancel();
|
|
167
|
+
}
|
|
162
168
|
}
|
|
163
|
-
}
|
|
164
169
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
// Remove overrides after one frame to animate to the current values.
|
|
171
|
+
frame = requestAnimationFrame(() => {
|
|
172
|
+
frame = undefined;
|
|
173
|
+
for (const [property, value] of values) {
|
|
174
|
+
element.style.setProperty(property, value);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
delete scope.snapshots[name];
|
|
179
|
+
} else {
|
|
180
|
+
// No previous instance exists, apply the entering state.
|
|
181
|
+
queueMicrotask(() => setLifecycle("entering"));
|
|
182
|
+
frame = requestAnimationFrame(() => {
|
|
183
|
+
frame = undefined;
|
|
184
|
+
setLifecycle("visible");
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
} else if (!isVisible && element) {
|
|
188
|
+
// Wait a microtask to check if a snapshot still exists (meaning no new
|
|
189
|
+
// SharedElement consumed it), then enter exiting state.
|
|
190
|
+
queueMicrotask(() => {
|
|
191
|
+
if (scope.snapshots[name]) {
|
|
192
|
+
delete scope.snapshots[name];
|
|
193
|
+
setLifecycle("exiting");
|
|
194
|
+
// Wait for animations to finish before hiding.
|
|
195
|
+
Promise.all(getAnimations(element).map((a) => a.finished))
|
|
196
|
+
.then(() => setLifecycle("hidden"))
|
|
197
|
+
.catch(() => {});
|
|
198
|
+
} else {
|
|
199
|
+
// Snapshot was consumed by another instance, unmount immediately.
|
|
200
|
+
setLifecycle("hidden");
|
|
170
201
|
}
|
|
171
202
|
});
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// No previous instance exists, apply the entering state.
|
|
176
|
-
queueMicrotask(() => setLifecycle('entering'));
|
|
203
|
+
} else if (isVisible) {
|
|
204
|
+
// Element not yet in DOM, entering fresh
|
|
205
|
+
setLifecycle("entering");
|
|
177
206
|
frame = requestAnimationFrame(() => {
|
|
178
207
|
frame = undefined;
|
|
179
|
-
setLifecycle(
|
|
208
|
+
setLifecycle("visible");
|
|
180
209
|
});
|
|
181
210
|
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
queueMicrotask(() => {
|
|
186
|
-
if (scope.snapshots[name]) {
|
|
187
|
-
delete scope.snapshots[name];
|
|
188
|
-
setLifecycle('exiting');
|
|
189
|
-
// Wait for animations to finish before hiding.
|
|
190
|
-
Promise.all(getAnimations(element).map(a => a.finished))
|
|
191
|
-
.then(() => setLifecycle('hidden'))
|
|
192
|
-
.catch(() => {});
|
|
193
|
-
} else {
|
|
194
|
-
// Snapshot was consumed by another instance, unmount immediately.
|
|
195
|
-
setLifecycle('hidden');
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
} else if (isVisible) {
|
|
199
|
-
// Element not yet in DOM, entering fresh
|
|
200
|
-
setLifecycle('entering');
|
|
201
|
-
frame = requestAnimationFrame(() => {
|
|
202
|
-
frame = undefined;
|
|
203
|
-
setLifecycle('visible');
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
));
|
|
211
|
+
},
|
|
212
|
+
),
|
|
213
|
+
);
|
|
208
214
|
|
|
209
215
|
// Capture snapshot on cleanup (unmount)
|
|
210
216
|
onCleanup(() => {
|
|
@@ -213,14 +219,14 @@ export function SharedElement(props: SharedElementProps): JSX.Element | null {
|
|
|
213
219
|
}
|
|
214
220
|
|
|
215
221
|
const element = elementRef;
|
|
216
|
-
if (element && element.isConnected && !element.hasAttribute(
|
|
222
|
+
if (element && element.isConnected && !element.hasAttribute("data-exiting")) {
|
|
217
223
|
// Store a snapshot of the rectangle and computed style for transitioning properties.
|
|
218
224
|
const style = window.getComputedStyle(element);
|
|
219
|
-
if (style.transitionProperty !==
|
|
225
|
+
if (style.transitionProperty !== "none") {
|
|
220
226
|
const transitionProperty = style.transitionProperty.split(/\s*,\s*/);
|
|
221
227
|
scope.snapshots[local.name] = {
|
|
222
228
|
rect: element.getBoundingClientRect(),
|
|
223
|
-
style: transitionProperty.map(
|
|
229
|
+
style: transitionProperty.map((property) => [property, style.getPropertyValue(property)]),
|
|
224
230
|
};
|
|
225
231
|
}
|
|
226
232
|
}
|
|
@@ -231,25 +237,25 @@ export function SharedElement(props: SharedElementProps): JSX.Element | null {
|
|
|
231
237
|
children: local.children,
|
|
232
238
|
class: local.class,
|
|
233
239
|
style: local.style,
|
|
234
|
-
defaultClassName:
|
|
240
|
+
defaultClassName: "solidaria-SharedElement",
|
|
235
241
|
},
|
|
236
242
|
() => ({
|
|
237
|
-
isEntering: lifecycle() ===
|
|
238
|
-
isExiting: lifecycle() ===
|
|
239
|
-
})
|
|
243
|
+
isEntering: lifecycle() === "entering",
|
|
244
|
+
isExiting: lifecycle() === "exiting",
|
|
245
|
+
}),
|
|
240
246
|
);
|
|
241
247
|
|
|
242
248
|
const filteredDomProps = createMemo(() => filterDOMProps(domProps, { global: true }));
|
|
243
249
|
|
|
244
250
|
return (
|
|
245
|
-
<Show when={lifecycle() !==
|
|
251
|
+
<Show when={lifecycle() !== "hidden"}>
|
|
246
252
|
<div
|
|
247
253
|
ref={setRef}
|
|
248
254
|
{...filteredDomProps()}
|
|
249
255
|
class={renderProps.class()}
|
|
250
256
|
style={renderProps.style()}
|
|
251
|
-
data-entering={lifecycle() ===
|
|
252
|
-
data-exiting={lifecycle() ===
|
|
257
|
+
data-entering={lifecycle() === "entering" || undefined}
|
|
258
|
+
data-exiting={lifecycle() === "exiting" || undefined}
|
|
253
259
|
>
|
|
254
260
|
{renderProps.renderChildren()}
|
|
255
261
|
</div>
|