@mrmeg/expo-ui 0.12.0 → 0.13.0-rsd.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/dist/components/Accordion.d.ts +38 -18
- package/dist/components/Accordion.js +137 -121
- package/dist/components/AnimatedView.d.ts +13 -24
- package/dist/components/AnimatedView.js +70 -29
- package/dist/components/Badge.d.ts +2 -2
- package/dist/components/Badge.js +45 -47
- package/dist/components/BottomSheet.d.ts +30 -73
- package/dist/components/BottomSheet.js +240 -188
- package/dist/components/Button.d.ts +43 -56
- package/dist/components/Button.js +189 -203
- package/dist/components/Card.d.ts +7 -10
- package/dist/components/Card.js +90 -105
- package/dist/components/Checkbox.d.ts +20 -8
- package/dist/components/Checkbox.js +77 -80
- package/dist/components/Collapsible.d.ts +47 -47
- package/dist/components/Collapsible.js +108 -29
- package/dist/components/Dialog.d.ts +80 -121
- package/dist/components/Dialog.js +225 -132
- package/dist/components/DismissKeyboard.d.ts +1 -1
- package/dist/components/DismissKeyboard.js +70 -26
- package/dist/components/Drawer.d.ts +37 -76
- package/dist/components/Drawer.js +252 -486
- package/dist/components/DropdownMenu.d.ts +106 -113
- package/dist/components/DropdownMenu.js +350 -204
- package/dist/components/EmptyState.d.ts +2 -2
- package/dist/components/EmptyState.js +41 -34
- package/dist/components/InputOTP.d.ts +19 -53
- package/dist/components/InputOTP.js +81 -102
- package/dist/components/KeyboardAvoidingView.d.ts +6 -3
- package/dist/components/KeyboardAvoidingView.js +18 -5
- package/dist/components/Label.d.ts +12 -17
- package/dist/components/Label.js +38 -51
- package/dist/components/MaxWidthContainer.d.ts +5 -16
- package/dist/components/MaxWidthContainer.js +28 -29
- package/dist/components/Notification.d.ts +5 -9
- package/dist/components/Notification.js +190 -187
- package/dist/components/Popover.d.ts +38 -66
- package/dist/components/Popover.js +158 -69
- package/dist/components/Progress.d.ts +5 -4
- package/dist/components/Progress.js +65 -77
- package/dist/components/RadioGroup.d.ts +30 -24
- package/dist/components/RadioGroup.js +90 -94
- package/dist/components/Select.d.ts +62 -74
- package/dist/components/Select.js +241 -154
- package/dist/components/Separator.d.ts +13 -23
- package/dist/components/Separator.js +29 -36
- package/dist/components/Skeleton.d.ts +8 -7
- package/dist/components/Skeleton.js +74 -61
- package/dist/components/StyledText.context.d.ts +6 -2
- package/dist/components/StyledText.context.js +3 -0
- package/dist/components/StyledText.d.ts +29 -7
- package/dist/components/StyledText.js +92 -29
- package/dist/components/Switch.d.ts +18 -6
- package/dist/components/Switch.js +112 -106
- package/dist/components/Tabs.d.ts +26 -16
- package/dist/components/Tabs.js +189 -91
- package/dist/components/TextInput.d.ts +6 -19
- package/dist/components/TextInput.js +261 -195
- package/dist/components/Toggle.d.ts +23 -41
- package/dist/components/Toggle.js +84 -98
- package/dist/components/ToggleGroup.d.ts +37 -29
- package/dist/components/ToggleGroup.js +113 -108
- package/dist/components/Tooltip.d.ts +41 -111
- package/dist/components/Tooltip.js +156 -118
- package/dist/components/UIProvider.d.ts +1 -1
- package/dist/components/UIProvider.js +1 -1
- package/dist/components/keyboardFocusRegistry.d.ts +15 -0
- package/dist/components/keyboardFocusRegistry.js +27 -0
- package/dist/hooks/useTheme.d.ts +34 -10
- package/dist/hooks/useTheme.js +20 -8
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.js +2 -0
- package/dist/lib/portal.d.ts +16 -0
- package/dist/lib/portal.js +84 -0
- package/dist/lib/styles.d.ts +32 -0
- package/dist/lib/styles.js +91 -0
- package/dist/lib/useAnchoredPosition.d.ts +57 -0
- package/dist/lib/useAnchoredPosition.js +120 -0
- package/package.json +4 -22
|
@@ -1,28 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
type BaseAccordionRootProps =
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type LooseStyle } from "../lib/styles";
|
|
3
|
+
type BaseAccordionRootProps = {
|
|
4
4
|
disabled?: boolean;
|
|
5
|
+
/** Single-type only: allow closing the open item by re-pressing it. */
|
|
5
6
|
collapsible?: boolean;
|
|
7
|
+
/** Platform: WEB ONLY (kept for API compat; unused). */
|
|
6
8
|
dir?: "ltr" | "rtl";
|
|
9
|
+
/** Platform: WEB ONLY (kept for API compat; unused). */
|
|
7
10
|
orientation?: "vertical" | "horizontal";
|
|
8
|
-
style?:
|
|
11
|
+
style?: LooseStyle;
|
|
12
|
+
children?: React.ReactNode;
|
|
9
13
|
};
|
|
10
|
-
type
|
|
14
|
+
type SingleAccordionRootProps = BaseAccordionRootProps & {
|
|
11
15
|
type: "single";
|
|
12
16
|
defaultValue?: string;
|
|
13
17
|
value?: string;
|
|
14
18
|
onValueChange?: (value: string | undefined) => void;
|
|
15
19
|
};
|
|
16
|
-
type
|
|
20
|
+
type MultipleAccordionRootProps = BaseAccordionRootProps & {
|
|
17
21
|
type: "multiple";
|
|
18
22
|
defaultValue?: string[];
|
|
19
23
|
value?: string[];
|
|
20
24
|
onValueChange?: (value: string[]) => void;
|
|
21
25
|
};
|
|
22
|
-
type AccordionRootProps =
|
|
26
|
+
type AccordionRootProps = SingleAccordionRootProps | MultipleAccordionRootProps;
|
|
23
27
|
/**
|
|
24
|
-
* Accordion Root Component
|
|
25
|
-
* Container for accordion items with
|
|
28
|
+
* Accordion Root Component (react-strict-dom)
|
|
29
|
+
* Container for accordion items with single or multiple open items. Supports
|
|
30
|
+
* controlled (`value`) and uncontrolled (`defaultValue`) usage.
|
|
26
31
|
*
|
|
27
32
|
* Usage:
|
|
28
33
|
* <Accordion type="single" collapsible>
|
|
@@ -32,23 +37,38 @@ type AccordionRootProps = WebSingleAccordionRootProps | WebMultipleAccordionRoot
|
|
|
32
37
|
* </AccordionItem>
|
|
33
38
|
* </Accordion>
|
|
34
39
|
*/
|
|
35
|
-
declare function Accordion(
|
|
40
|
+
declare function Accordion(props: AccordionRootProps): React.JSX.Element;
|
|
41
|
+
export interface AccordionItemProps {
|
|
42
|
+
value: string;
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
children?: React.ReactNode;
|
|
45
|
+
style?: LooseStyle;
|
|
46
|
+
}
|
|
36
47
|
/**
|
|
37
48
|
* Accordion Item Component
|
|
38
|
-
* Individual accordion item with border
|
|
49
|
+
* Individual accordion item with a bottom border. Shares its expanded state
|
|
50
|
+
* with the Trigger (chevron) and Content via context.
|
|
39
51
|
*/
|
|
40
|
-
declare function AccordionItem({
|
|
52
|
+
declare function AccordionItem({ value, disabled: itemDisabled, children, style }: AccordionItemProps): React.JSX.Element;
|
|
53
|
+
export interface AccordionTriggerProps {
|
|
54
|
+
children?: React.ReactNode;
|
|
55
|
+
style?: LooseStyle;
|
|
56
|
+
}
|
|
41
57
|
/**
|
|
42
58
|
* Accordion Trigger Component
|
|
43
|
-
* Clickable header that expands/collapses the
|
|
44
|
-
*
|
|
59
|
+
* Clickable header that expands/collapses the item. Includes an animated
|
|
60
|
+
* chevron that rotates with the expanded state.
|
|
45
61
|
*/
|
|
46
|
-
declare function AccordionTrigger({ children, style
|
|
62
|
+
declare function AccordionTrigger({ children, style }: AccordionTriggerProps): React.JSX.Element;
|
|
63
|
+
export interface AccordionContentProps {
|
|
64
|
+
/** Keep content mounted (hidden) when collapsed instead of unmounting. */
|
|
65
|
+
forceMount?: boolean;
|
|
47
66
|
children?: React.ReactNode;
|
|
48
|
-
|
|
67
|
+
style?: LooseStyle;
|
|
68
|
+
}
|
|
49
69
|
/**
|
|
50
70
|
* Accordion Content Component
|
|
51
|
-
* Expandable content area
|
|
71
|
+
* Expandable content area. Unmounts when collapsed unless `forceMount` is set.
|
|
52
72
|
*/
|
|
53
|
-
declare function AccordionContent({ children, style
|
|
73
|
+
declare function AccordionContent({ forceMount, children, style }: AccordionContentProps): React.JSX.Element | null;
|
|
54
74
|
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|
|
@@ -1,62 +1,31 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createContext, use, useCallback, useMemo, useState } from "react";
|
|
3
|
+
import { css, html } from "react-strict-dom";
|
|
4
4
|
import { Icon } from "./Icon.js";
|
|
5
5
|
import { TextClassContext, TextSelectabilityContext } from "./StyledText.context";
|
|
6
6
|
import { useTheme } from "../hooks/useTheme.js";
|
|
7
7
|
import { useReducedMotion } from "../hooks/useReduceMotion.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
function normalizeMultipleValue(value) {
|
|
17
|
-
return value ?? [];
|
|
18
|
-
}
|
|
19
|
-
function WebSingleAccordionRoot(props) {
|
|
20
|
-
const isControlled = Object.prototype.hasOwnProperty.call(props, "value");
|
|
21
|
-
const [uncontrolledValue, setUncontrolledValue] = useState(() => normalizeSingleValue(props.defaultValue));
|
|
22
|
-
const normalizedValue = isControlled
|
|
23
|
-
? normalizeSingleValue(props.value)
|
|
24
|
-
: uncontrolledValue;
|
|
25
|
-
const handleValueChange = (nextValue) => {
|
|
26
|
-
const normalizedNextValue = normalizeSingleValue(nextValue);
|
|
27
|
-
if (!isControlled) {
|
|
28
|
-
setUncontrolledValue(normalizedNextValue);
|
|
29
|
-
}
|
|
30
|
-
props.onValueChange?.(denormalizeSingleValue(normalizedNextValue));
|
|
31
|
-
};
|
|
32
|
-
const { children, style, type: _type, defaultValue: _defaultValue, onValueChange: _onValueChange, value: _value, ...rootProps } = props;
|
|
33
|
-
return (_jsx(AccordionPrimitive.Root, { ...rootProps, type: "single", value: normalizedValue, onValueChange: handleValueChange, asChild: false, children: _jsx(View, { style: style, children: children }) }));
|
|
34
|
-
}
|
|
35
|
-
function WebMultipleAccordionRoot(props) {
|
|
36
|
-
const isControlled = Object.prototype.hasOwnProperty.call(props, "value");
|
|
37
|
-
const [uncontrolledValue, setUncontrolledValue] = useState(() => normalizeMultipleValue(props.defaultValue));
|
|
38
|
-
const normalizedValue = isControlled
|
|
39
|
-
? normalizeMultipleValue(props.value)
|
|
40
|
-
: uncontrolledValue;
|
|
41
|
-
const handleValueChange = (nextValue) => {
|
|
42
|
-
const normalizedNextValue = normalizeMultipleValue(nextValue);
|
|
43
|
-
if (!isControlled) {
|
|
44
|
-
setUncontrolledValue(normalizedNextValue);
|
|
45
|
-
}
|
|
46
|
-
props.onValueChange?.(normalizedNextValue);
|
|
47
|
-
};
|
|
48
|
-
const { children, style, type: _type, defaultValue: _defaultValue, onValueChange: _onValueChange, value: _value, ...rootProps } = props;
|
|
49
|
-
return (_jsx(AccordionPrimitive.Root, { ...rootProps, type: "multiple", value: normalizedValue, onValueChange: handleValueChange, asChild: false, children: _jsx(View, { style: style, children: children }) }));
|
|
8
|
+
import { sanitizeWebStyle } from "../lib/styles.js";
|
|
9
|
+
const AccordionContext = createContext(null);
|
|
10
|
+
function useAccordionContext() {
|
|
11
|
+
const ctx = use(AccordionContext);
|
|
12
|
+
if (!ctx) {
|
|
13
|
+
throw new Error("Accordion compound components must be used within an <Accordion>");
|
|
14
|
+
}
|
|
15
|
+
return ctx;
|
|
50
16
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
17
|
+
const AccordionItemContext = createContext(null);
|
|
18
|
+
function useAccordionItemContext() {
|
|
19
|
+
const ctx = use(AccordionItemContext);
|
|
20
|
+
if (!ctx) {
|
|
21
|
+
throw new Error("AccordionTrigger/AccordionContent must be used within an <AccordionItem>");
|
|
54
22
|
}
|
|
55
|
-
return
|
|
23
|
+
return ctx;
|
|
56
24
|
}
|
|
57
25
|
/**
|
|
58
|
-
* Accordion Root Component
|
|
59
|
-
* Container for accordion items with
|
|
26
|
+
* Accordion Root Component (react-strict-dom)
|
|
27
|
+
* Container for accordion items with single or multiple open items. Supports
|
|
28
|
+
* controlled (`value`) and uncontrolled (`defaultValue`) usage.
|
|
60
29
|
*
|
|
61
30
|
* Usage:
|
|
62
31
|
* <Accordion type="single" collapsible>
|
|
@@ -66,92 +35,139 @@ function WebAccordionRoot(props) {
|
|
|
66
35
|
* </AccordionItem>
|
|
67
36
|
* </Accordion>
|
|
68
37
|
*/
|
|
69
|
-
function Accordion(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
38
|
+
function Accordion(props) {
|
|
39
|
+
const { children, style, disabled = false } = props;
|
|
40
|
+
const isControlled = props.value !== undefined;
|
|
41
|
+
// Uncontrolled state — always stored as a string[] internally, projected to
|
|
42
|
+
// single/multiple at the boundary.
|
|
43
|
+
const [uncontrolled, setUncontrolled] = useState(() => {
|
|
44
|
+
if (props.type === "multiple")
|
|
45
|
+
return props.defaultValue ?? [];
|
|
46
|
+
return props.defaultValue ? [props.defaultValue] : [];
|
|
47
|
+
});
|
|
48
|
+
const expandedValues = useMemo(() => {
|
|
49
|
+
if (!isControlled)
|
|
50
|
+
return uncontrolled;
|
|
51
|
+
if (props.type === "multiple")
|
|
52
|
+
return props.value ?? [];
|
|
53
|
+
return props.value ? [props.value] : [];
|
|
54
|
+
}, [isControlled, uncontrolled, props]);
|
|
55
|
+
const isExpanded = useCallback((value) => expandedValues.includes(value), [expandedValues]);
|
|
56
|
+
const toggle = useCallback((value) => {
|
|
57
|
+
if (disabled)
|
|
58
|
+
return;
|
|
59
|
+
if (props.type === "multiple") {
|
|
60
|
+
const next = expandedValues.includes(value)
|
|
61
|
+
? expandedValues.filter((v) => v !== value)
|
|
62
|
+
: [...expandedValues, value];
|
|
63
|
+
if (!isControlled)
|
|
64
|
+
setUncontrolled(next);
|
|
65
|
+
props.onValueChange?.(next);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Single: open the pressed item; collapsible allows re-press to close.
|
|
69
|
+
const isOpen = expandedValues.includes(value);
|
|
70
|
+
const collapsible = props.collapsible ?? false;
|
|
71
|
+
const nextValue = isOpen && collapsible ? undefined : value;
|
|
72
|
+
if (!isControlled)
|
|
73
|
+
setUncontrolled(nextValue ? [nextValue] : []);
|
|
74
|
+
props.onValueChange?.(nextValue);
|
|
75
|
+
}, [disabled, expandedValues, isControlled, props]);
|
|
76
|
+
const contextValue = useMemo(() => ({ isExpanded, toggle, disabled }), [isExpanded, toggle, disabled]);
|
|
77
|
+
return (_jsx(AccordionContext.Provider, { value: contextValue, children: _jsx(html.div, { style: sanitizeWebStyle(style), children: children }) }));
|
|
74
78
|
}
|
|
79
|
+
const itemStyles = css.create({
|
|
80
|
+
base: (borderBottomColor) => ({
|
|
81
|
+
borderBottomWidth: 1,
|
|
82
|
+
borderBottomStyle: "solid",
|
|
83
|
+
borderBottomColor,
|
|
84
|
+
overflow: "hidden",
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
75
87
|
/**
|
|
76
88
|
* Accordion Item Component
|
|
77
|
-
* Individual accordion item with border
|
|
89
|
+
* Individual accordion item with a bottom border. Shares its expanded state
|
|
90
|
+
* with the Trigger (chevron) and Content via context.
|
|
78
91
|
*/
|
|
79
|
-
function AccordionItem({
|
|
92
|
+
function AccordionItem({ value, disabled: itemDisabled, children, style }) {
|
|
80
93
|
const { theme } = useTheme();
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
: []),
|
|
94
|
+
const { isExpanded, disabled: rootDisabled } = useAccordionContext();
|
|
95
|
+
const itemContext = useMemo(() => ({
|
|
96
|
+
value,
|
|
97
|
+
isExpanded: isExpanded(value),
|
|
98
|
+
disabled: !!itemDisabled || rootDisabled,
|
|
99
|
+
}), [value, isExpanded, itemDisabled, rootDisabled]);
|
|
100
|
+
return (_jsx(AccordionItemContext.Provider, { value: itemContext, children: _jsx(html.div, { style: [
|
|
101
|
+
itemStyles.base(theme.colors.border),
|
|
102
|
+
sanitizeWebStyle(style),
|
|
91
103
|
], children: children }) }));
|
|
92
104
|
}
|
|
93
|
-
const
|
|
105
|
+
const triggerStyles = css.create({
|
|
106
|
+
// gap (16) = spacing.md, borderRadius (6) = spacing.radiusMd, paddingVertical (16) = spacing.md.
|
|
107
|
+
base: {
|
|
108
|
+
display: "flex",
|
|
109
|
+
flexDirection: "row",
|
|
110
|
+
alignItems: "center",
|
|
111
|
+
justifyContent: "space-between",
|
|
112
|
+
gap: 16,
|
|
113
|
+
borderRadius: 6,
|
|
114
|
+
paddingTop: 16,
|
|
115
|
+
paddingBottom: 16,
|
|
116
|
+
margin: 0,
|
|
117
|
+
borderWidth: 0,
|
|
118
|
+
backgroundColor: "transparent",
|
|
119
|
+
appearance: "none",
|
|
120
|
+
cursor: "pointer",
|
|
121
|
+
userSelect: "none",
|
|
122
|
+
textAlign: "inherit",
|
|
123
|
+
width: "100%",
|
|
124
|
+
},
|
|
125
|
+
disabled: { cursor: "not-allowed" },
|
|
126
|
+
// Chevron rotates 0deg (closed) → 180deg (open). Transition gated on motion.
|
|
127
|
+
chevron: (rotate, animated) => ({
|
|
128
|
+
display: "flex",
|
|
129
|
+
transform: rotate,
|
|
130
|
+
transitionProperty: animated ? "transform" : "none",
|
|
131
|
+
transitionDuration: animated ? "0.2s" : "0s",
|
|
132
|
+
transitionTimingFunction: "ease",
|
|
133
|
+
}),
|
|
134
|
+
});
|
|
94
135
|
/**
|
|
95
136
|
* Accordion Trigger Component
|
|
96
|
-
* Clickable header that expands/collapses the
|
|
97
|
-
*
|
|
137
|
+
* Clickable header that expands/collapses the item. Includes an animated
|
|
138
|
+
* chevron that rotates with the expanded state.
|
|
98
139
|
*/
|
|
99
|
-
function AccordionTrigger({ children, style
|
|
140
|
+
function AccordionTrigger({ children, style }) {
|
|
100
141
|
const { theme } = useTheme();
|
|
101
142
|
const reduceMotion = useReducedMotion();
|
|
102
|
-
const {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
useNativeDriver: true,
|
|
110
|
-
}).start();
|
|
111
|
-
}, [isExpanded, reduceMotion, rotation]);
|
|
112
|
-
const chevronStyle = {
|
|
113
|
-
transform: [
|
|
114
|
-
{
|
|
115
|
-
rotate: rotation.interpolate({
|
|
116
|
-
inputRange: [0, 1],
|
|
117
|
-
outputRange: ["0deg", "180deg"],
|
|
118
|
-
}),
|
|
119
|
-
},
|
|
120
|
-
],
|
|
121
|
-
};
|
|
122
|
-
return (_jsx(TextClassContext.Provider, { value: "", children: _jsx(TextSelectabilityContext.Provider, { value: false, children: _jsx(AccordionPrimitive.Header, { children: _jsx(AccordionPrimitive.Trigger, { ...props, asChild: true, children: _jsxs(Trigger, { style: [
|
|
123
|
-
{
|
|
124
|
-
flexDirection: "row",
|
|
125
|
-
alignItems: "center",
|
|
126
|
-
justifyContent: "space-between",
|
|
127
|
-
gap: spacing.md,
|
|
128
|
-
borderRadius: spacing.radiusMd,
|
|
129
|
-
paddingVertical: spacing.md,
|
|
130
|
-
...(Platform.OS === "web" && {
|
|
131
|
-
cursor: "pointer",
|
|
132
|
-
userSelect: "none",
|
|
133
|
-
}),
|
|
134
|
-
},
|
|
135
|
-
// Spread array styles from primitives to prevent nested arrays on web
|
|
136
|
-
...(styleOverride && typeof styleOverride !== "function"
|
|
137
|
-
? (Array.isArray(styleOverride) ? styleOverride : [styleOverride])
|
|
138
|
-
: []),
|
|
139
|
-
], children: [_jsx(_Fragment, { children: children }), _jsx(Animated.View, { style: chevronStyle, children: _jsx(Icon, { name: "chevron-down", size: 16, color: theme.colors.textDim, decorative: true }) })] }) }) }) }) }));
|
|
143
|
+
const { toggle } = useAccordionContext();
|
|
144
|
+
const { value, isExpanded, disabled } = useAccordionItemContext();
|
|
145
|
+
return (_jsx(TextClassContext.Provider, { value: "", children: _jsx(TextSelectabilityContext.Provider, { value: false, children: _jsxs(html.button, { type: "button", "aria-expanded": isExpanded, "aria-disabled": disabled, disabled: disabled, onClick: () => !disabled && toggle(value), style: [
|
|
146
|
+
triggerStyles.base,
|
|
147
|
+
disabled ? triggerStyles.disabled : null,
|
|
148
|
+
sanitizeWebStyle(style),
|
|
149
|
+
], children: [_jsx(_Fragment, { children: children }), _jsx(html.span, { style: triggerStyles.chevron(isExpanded ? "rotate(180deg)" : "rotate(0deg)", !reduceMotion), children: _jsx(Icon, { name: "chevron-down", size: 16, color: theme.colors.textDim, decorative: true }) })] }) }) }));
|
|
140
150
|
}
|
|
151
|
+
const contentStyles = css.create({
|
|
152
|
+
// paddingBottom (8) = spacing.sm.
|
|
153
|
+
base: {
|
|
154
|
+
paddingBottom: 8,
|
|
155
|
+
overflow: "hidden",
|
|
156
|
+
},
|
|
157
|
+
hidden: { display: "none" },
|
|
158
|
+
});
|
|
141
159
|
/**
|
|
142
160
|
* Accordion Content Component
|
|
143
|
-
* Expandable content area
|
|
161
|
+
* Expandable content area. Unmounts when collapsed unless `forceMount` is set.
|
|
144
162
|
*/
|
|
145
|
-
function AccordionContent({ children, style
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
: []),
|
|
155
|
-
], children: children }) }) }));
|
|
163
|
+
function AccordionContent({ forceMount, children, style }) {
|
|
164
|
+
const { isExpanded } = useAccordionItemContext();
|
|
165
|
+
if (!isExpanded && !forceMount)
|
|
166
|
+
return null;
|
|
167
|
+
return (_jsx(TextClassContext.Provider, { value: "", children: _jsx(html.div, { style: [
|
|
168
|
+
contentStyles.base,
|
|
169
|
+
!isExpanded ? contentStyles.hidden : null,
|
|
170
|
+
sanitizeWebStyle(style),
|
|
171
|
+
], children: children }) }));
|
|
156
172
|
}
|
|
157
173
|
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { type LooseStyle } from "../lib/styles";
|
|
3
3
|
/**
|
|
4
4
|
* Animation type options
|
|
5
5
|
*/
|
|
6
6
|
export type AnimationType = "fade" | "fadeSlideUp" | "fadeSlideDown" | "scale";
|
|
7
|
-
interface AnimatedViewProps
|
|
7
|
+
export interface AnimatedViewProps {
|
|
8
8
|
children: React.ReactNode;
|
|
9
9
|
/**
|
|
10
10
|
* Type of animation to use
|
|
@@ -22,34 +22,23 @@ interface AnimatedViewProps extends ViewProps {
|
|
|
22
22
|
* @default 0
|
|
23
23
|
*/
|
|
24
24
|
delay?: number;
|
|
25
|
+
/** Custom style override */
|
|
26
|
+
style?: LooseStyle;
|
|
27
|
+
/** Test identifier (forwarded as data-testid on web) */
|
|
28
|
+
testID?: string;
|
|
25
29
|
}
|
|
26
30
|
/**
|
|
27
31
|
* Cross-Platform Animated View Component
|
|
28
|
-
* Uses React Native Animated for lightweight cross-platform animations
|
|
29
32
|
*
|
|
30
|
-
*
|
|
31
|
-
* -
|
|
32
|
-
* -
|
|
33
|
-
*
|
|
34
|
-
* - Respects reduced motion accessibility preference
|
|
33
|
+
* Plays a one-shot entrance animation via CSS keyframes on web. Respects the
|
|
34
|
+
* reduced-motion accessibility preference (renders statically when set). On
|
|
35
|
+
* native the keyframes are a no-op, so children appear immediately — the
|
|
36
|
+
* package ships no Reanimated, a documented animation gap.
|
|
35
37
|
*
|
|
36
38
|
* Usage:
|
|
37
39
|
* ```tsx
|
|
38
|
-
*
|
|
39
|
-
* <AnimatedView>
|
|
40
|
-
* {children}
|
|
41
|
-
* </AnimatedView>
|
|
42
|
-
*
|
|
43
|
-
* // Fade with slide up
|
|
44
|
-
* <AnimatedView type="fadeSlideUp">
|
|
45
|
-
* {children}
|
|
46
|
-
* </AnimatedView>
|
|
47
|
-
*
|
|
48
|
-
* // With delay (for staggered lists)
|
|
49
|
-
* <AnimatedView type="fadeSlideUp" delay={100}>
|
|
50
|
-
* {children}
|
|
51
|
-
* </AnimatedView>
|
|
40
|
+
* <AnimatedView>{children}</AnimatedView>
|
|
41
|
+
* <AnimatedView type="fadeSlideUp" delay={100}>{children}</AnimatedView>
|
|
52
42
|
* ```
|
|
53
43
|
*/
|
|
54
|
-
export declare function AnimatedView({ children, type, enterDuration, delay, style,
|
|
55
|
-
export {};
|
|
44
|
+
export declare function AnimatedView({ children, type, enterDuration, delay, style, testID, }: AnimatedViewProps): React.JSX.Element;
|
|
@@ -1,39 +1,80 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { css, html } from "react-strict-dom";
|
|
3
|
+
import { useReducedMotion } from "../hooks/useReduceMotion.js";
|
|
4
|
+
import { sanitizeWebStyle } from "../lib/styles.js";
|
|
5
|
+
// Entrance keyframes. Slide distance (8px) and initial scale (0.95) mirror the
|
|
6
|
+
// previous useStaggeredEntrance defaults. css.keyframes must be defined inline
|
|
7
|
+
// and unconditionally in the same file as the css.create that references them
|
|
8
|
+
// (StyleX can't fold a cross-module or ternary-gated keyframe name). On native
|
|
9
|
+
// css.keyframes is a no-op and animationName has no effect, so views appear
|
|
10
|
+
// instantly — documented animation fidelity gap (no Reanimated in the package).
|
|
11
|
+
const fadeFrames = css.keyframes({
|
|
12
|
+
"0%": { opacity: 0 },
|
|
13
|
+
"100%": { opacity: 1 },
|
|
14
|
+
});
|
|
15
|
+
const fadeSlideUpFrames = css.keyframes({
|
|
16
|
+
"0%": { opacity: 0, transform: "translateY(8px)" },
|
|
17
|
+
"100%": { opacity: 1, transform: "translateY(0)" },
|
|
18
|
+
});
|
|
19
|
+
const fadeSlideDownFrames = css.keyframes({
|
|
20
|
+
"0%": { opacity: 0, transform: "translateY(-8px)" },
|
|
21
|
+
"100%": { opacity: 1, transform: "translateY(0)" },
|
|
22
|
+
});
|
|
23
|
+
const scaleFrames = css.keyframes({
|
|
24
|
+
"0%": { opacity: 0, transform: "scale(0.95)" },
|
|
25
|
+
"100%": { opacity: 1, transform: "scale(1)" },
|
|
26
|
+
});
|
|
27
|
+
// Duration/delay are runtime props, so they flow in as function-rule args.
|
|
28
|
+
// animationFillMode:"both" holds the 0% state during the delay (so staggered
|
|
29
|
+
// items stay hidden until their turn) and the 100% state after completion.
|
|
30
|
+
const styles = css.create({
|
|
31
|
+
fade: (duration, delay) => ({
|
|
32
|
+
animationName: fadeFrames,
|
|
33
|
+
animationDuration: duration,
|
|
34
|
+
animationDelay: delay,
|
|
35
|
+
animationTimingFunction: "ease-out",
|
|
36
|
+
animationFillMode: "both",
|
|
37
|
+
}),
|
|
38
|
+
fadeSlideUp: (duration, delay) => ({
|
|
39
|
+
animationName: fadeSlideUpFrames,
|
|
40
|
+
animationDuration: duration,
|
|
41
|
+
animationDelay: delay,
|
|
42
|
+
animationTimingFunction: "ease-out",
|
|
43
|
+
animationFillMode: "both",
|
|
44
|
+
}),
|
|
45
|
+
fadeSlideDown: (duration, delay) => ({
|
|
46
|
+
animationName: fadeSlideDownFrames,
|
|
47
|
+
animationDuration: duration,
|
|
48
|
+
animationDelay: delay,
|
|
49
|
+
animationTimingFunction: "ease-out",
|
|
50
|
+
animationFillMode: "both",
|
|
51
|
+
}),
|
|
52
|
+
scale: (duration, delay) => ({
|
|
53
|
+
animationName: scaleFrames,
|
|
54
|
+
animationDuration: duration,
|
|
55
|
+
animationDelay: delay,
|
|
56
|
+
animationTimingFunction: "ease-out",
|
|
57
|
+
animationFillMode: "both",
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
4
60
|
/**
|
|
5
61
|
* Cross-Platform Animated View Component
|
|
6
|
-
* Uses React Native Animated for lightweight cross-platform animations
|
|
7
62
|
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
*
|
|
12
|
-
* - Respects reduced motion accessibility preference
|
|
63
|
+
* Plays a one-shot entrance animation via CSS keyframes on web. Respects the
|
|
64
|
+
* reduced-motion accessibility preference (renders statically when set). On
|
|
65
|
+
* native the keyframes are a no-op, so children appear immediately — the
|
|
66
|
+
* package ships no Reanimated, a documented animation gap.
|
|
13
67
|
*
|
|
14
68
|
* Usage:
|
|
15
69
|
* ```tsx
|
|
16
|
-
*
|
|
17
|
-
* <AnimatedView>
|
|
18
|
-
* {children}
|
|
19
|
-
* </AnimatedView>
|
|
20
|
-
*
|
|
21
|
-
* // Fade with slide up
|
|
22
|
-
* <AnimatedView type="fadeSlideUp">
|
|
23
|
-
* {children}
|
|
24
|
-
* </AnimatedView>
|
|
25
|
-
*
|
|
26
|
-
* // With delay (for staggered lists)
|
|
27
|
-
* <AnimatedView type="fadeSlideUp" delay={100}>
|
|
28
|
-
* {children}
|
|
29
|
-
* </AnimatedView>
|
|
70
|
+
* <AnimatedView>{children}</AnimatedView>
|
|
71
|
+
* <AnimatedView type="fadeSlideUp" delay={100}>{children}</AnimatedView>
|
|
30
72
|
* ```
|
|
31
73
|
*/
|
|
32
|
-
export function AnimatedView({ children, type = "fade", enterDuration = 200, delay = 0, style,
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
38
|
-
return (_jsx(Animated.View, { style: [style, entranceStyle], ...props, children: children }));
|
|
74
|
+
export function AnimatedView({ children, type = "fade", enterDuration = 200, delay = 0, style, testID, }) {
|
|
75
|
+
const reduceMotion = useReducedMotion();
|
|
76
|
+
const duration = `${enterDuration}ms`;
|
|
77
|
+
const delayMs = `${delay}ms`;
|
|
78
|
+
const animation = reduceMotion ? null : styles[type](duration, delayMs);
|
|
79
|
+
return (_jsx(html.div, { "data-testid": testID, style: [animation, sanitizeWebStyle(style)], children: children }));
|
|
39
80
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { type LooseStyle } from "../lib/styles";
|
|
3
3
|
export type BadgeVariant = "default" | "secondary" | "outline" | "destructive";
|
|
4
4
|
export interface BadgeProps {
|
|
5
5
|
children?: React.ReactNode;
|
|
6
6
|
text?: string;
|
|
7
7
|
variant?: BadgeVariant;
|
|
8
|
-
style?:
|
|
8
|
+
style?: LooseStyle;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* Badge Component
|