@cdx-ui/components 0.3.1 → 0.3.3
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 +2 -2
- package/coverage.svg +1 -1
- package/docs/components/bottom-sheet/content.md +2 -2
- package/docs/components/content.md +2 -0
- package/docs/components/currency-input/content.md +94 -5
- package/docs/components/data-grid/content.md +125 -1
- package/docs/components/insight/content.md +644 -0
- package/docs/components/insight-stack/content.md +231 -0
- package/docs/foundations/styles/tokens/all-tokens/content.md +23 -3
- package/docs/llms.txt +4 -0
- package/docs/patterns/forms/content.md +255 -0
- package/docs/resources/release-notes/0.3.1/content.md +13 -0
- package/docs/resources/release-notes/0.3.2/content.md +17 -0
- package/docs/resources/release-notes/content.md +2 -0
- package/lib/commonjs/components/BottomSheet/index.js +63 -16
- package/lib/commonjs/components/BottomSheet/index.js.map +1 -1
- package/lib/commonjs/components/CurrencyInput/index.js +35 -10
- package/lib/commonjs/components/CurrencyInput/index.js.map +1 -1
- package/lib/commonjs/components/CurrencyInput/styles.js +40 -3
- package/lib/commonjs/components/CurrencyInput/styles.js.map +1 -1
- package/lib/commonjs/components/Insight/index.js +438 -0
- package/lib/commonjs/components/Insight/index.js.map +1 -0
- package/lib/commonjs/components/Insight/insetRadius.js +35 -0
- package/lib/commonjs/components/Insight/insetRadius.js.map +1 -0
- package/lib/commonjs/components/Insight/styles.js +186 -0
- package/lib/commonjs/components/Insight/styles.js.map +1 -0
- package/lib/commonjs/components/InsightStack/index.js +93 -0
- package/lib/commonjs/components/InsightStack/index.js.map +1 -0
- package/lib/commonjs/components/InsightStack/styles.js +61 -0
- package/lib/commonjs/components/InsightStack/styles.js.map +1 -0
- package/lib/commonjs/components/index.js +24 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/figma/CurrencyInput.figma.js +8 -8
- package/lib/commonjs/figma/CurrencyInput.figma.js.map +1 -1
- package/lib/commonjs/figma/Insight.figma.js +73 -0
- package/lib/commonjs/figma/Insight.figma.js.map +1 -0
- package/lib/commonjs/figma/InsightStack.figma.js +39 -0
- package/lib/commonjs/figma/InsightStack.figma.js.map +1 -0
- package/lib/module/components/BottomSheet/index.js +64 -17
- package/lib/module/components/BottomSheet/index.js.map +1 -1
- package/lib/module/components/CurrencyInput/index.js +37 -12
- package/lib/module/components/CurrencyInput/index.js.map +1 -1
- package/lib/module/components/CurrencyInput/styles.js +38 -3
- package/lib/module/components/CurrencyInput/styles.js.map +1 -1
- package/lib/module/components/Insight/index.js +433 -0
- package/lib/module/components/Insight/index.js.map +1 -0
- package/lib/module/components/Insight/insetRadius.js +30 -0
- package/lib/module/components/Insight/insetRadius.js.map +1 -0
- package/lib/module/components/Insight/styles.js +183 -0
- package/lib/module/components/Insight/styles.js.map +1 -0
- package/lib/module/components/InsightStack/index.js +89 -0
- package/lib/module/components/InsightStack/index.js.map +1 -0
- package/lib/module/components/InsightStack/styles.js +58 -0
- package/lib/module/components/InsightStack/styles.js.map +1 -0
- package/lib/module/components/index.js +2 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/figma/CurrencyInput.figma.js +8 -8
- package/lib/module/figma/CurrencyInput.figma.js.map +1 -1
- package/lib/module/figma/Insight.figma.js +67 -0
- package/lib/module/figma/Insight.figma.js.map +1 -0
- package/lib/module/figma/InsightStack.figma.js +33 -0
- package/lib/module/figma/InsightStack.figma.js.map +1 -0
- package/lib/typescript/components/BottomSheet/index.d.ts.map +1 -1
- package/lib/typescript/components/CurrencyInput/index.d.ts +4 -1
- package/lib/typescript/components/CurrencyInput/index.d.ts.map +1 -1
- package/lib/typescript/components/CurrencyInput/styles.d.ts +17 -6
- package/lib/typescript/components/CurrencyInput/styles.d.ts.map +1 -1
- package/lib/typescript/components/Insight/index.d.ts +87 -0
- package/lib/typescript/components/Insight/index.d.ts.map +1 -0
- package/lib/typescript/components/Insight/insetRadius.d.ts +8 -0
- package/lib/typescript/components/Insight/insetRadius.d.ts.map +1 -0
- package/lib/typescript/components/Insight/styles.d.ts +33 -0
- package/lib/typescript/components/Insight/styles.d.ts.map +1 -0
- package/lib/typescript/components/InsightStack/index.d.ts +21 -0
- package/lib/typescript/components/InsightStack/index.d.ts.map +1 -0
- package/lib/typescript/components/InsightStack/styles.d.ts +11 -0
- package/lib/typescript/components/InsightStack/styles.d.ts.map +1 -0
- package/lib/typescript/components/index.d.ts +2 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/lib/typescript/figma/CurrencyInput.figma.d.ts.map +1 -1
- package/lib/typescript/figma/Insight.figma.d.ts +8 -0
- package/lib/typescript/figma/Insight.figma.d.ts.map +1 -0
- package/lib/typescript/figma/InsightStack.figma.d.ts +8 -0
- package/lib/typescript/figma/InsightStack.figma.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/components/BottomSheet/index.tsx +88 -13
- package/src/components/CurrencyInput/index.tsx +36 -12
- package/src/components/CurrencyInput/styles.ts +51 -4
- package/src/components/Insight/index.tsx +531 -0
- package/src/components/Insight/insetRadius.ts +30 -0
- package/src/components/Insight/styles.ts +193 -0
- package/src/components/InsightStack/index.tsx +86 -0
- package/src/components/InsightStack/styles.ts +61 -0
- package/src/components/index.ts +2 -0
|
@@ -34,6 +34,8 @@ export * from './Field';
|
|
|
34
34
|
export * from './Form';
|
|
35
35
|
export * from './FullScreenDialog';
|
|
36
36
|
export * from './Image';
|
|
37
|
+
export * from './Insight';
|
|
38
|
+
export * from './InsightStack';
|
|
37
39
|
export * from './InsuranceDisclosure';
|
|
38
40
|
export * from './Input';
|
|
39
41
|
export * from './OtpInput';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACjG,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC;AACnC,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,yBAAyB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACjG,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC;AACnC,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,yBAAyB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CurrencyInput.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/CurrencyInput.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;
|
|
1
|
+
{"version":3,"file":"CurrencyInput.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/CurrencyInput.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;AA2C1B,wBASE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Insight.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/Insight.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;AAsD1B,wBAwBE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InsightStack.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/InsightStack.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;AAqB1B,wBAWE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdx-ui/components",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -106,10 +106,10 @@
|
|
|
106
106
|
"@marceloterreiro/flash-calendar": "2.0.0",
|
|
107
107
|
"react-native-reanimated-carousel": "5.0.0-beta.5",
|
|
108
108
|
"uniwind": "1.10.0",
|
|
109
|
-
"@cdx-ui/formatters": "0.3.
|
|
110
|
-
"@cdx-ui/icons": "0.3.
|
|
111
|
-
"@cdx-ui/primitives": "0.3.
|
|
112
|
-
"@cdx-ui/utils": "0.3.
|
|
109
|
+
"@cdx-ui/formatters": "0.3.3",
|
|
110
|
+
"@cdx-ui/icons": "0.3.3",
|
|
111
|
+
"@cdx-ui/primitives": "0.3.3",
|
|
112
|
+
"@cdx-ui/utils": "0.3.3"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
115
115
|
"@dnd-kit/core": "6.3.1",
|
|
@@ -10,7 +10,14 @@ import React, {
|
|
|
10
10
|
useState,
|
|
11
11
|
type ReactNode,
|
|
12
12
|
} from 'react';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
BackHandler,
|
|
15
|
+
Dimensions,
|
|
16
|
+
Platform,
|
|
17
|
+
View,
|
|
18
|
+
ViewStyle,
|
|
19
|
+
type LayoutChangeEvent,
|
|
20
|
+
} from 'react-native';
|
|
14
21
|
import { SafeAreaInsetsContext, type EdgeInsets } from 'react-native-safe-area-context';
|
|
15
22
|
import { useResolveClassNames } from 'uniwind';
|
|
16
23
|
import {
|
|
@@ -38,8 +45,43 @@ import {
|
|
|
38
45
|
|
|
39
46
|
const SCOPE = 'BOTTOM_SHEET';
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
interface BottomSheetScopeContext extends BottomSheetContentVariantProps {
|
|
49
|
+
hasFooter?: boolean;
|
|
50
|
+
/** Web only: height of the `footer` prop, measured by `BottomSheet.Modal`. */
|
|
51
|
+
footerHeight?: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const useBottomSheetScopeContext = () =>
|
|
55
|
+
useStyleContext(SCOPE) as BottomSheetScopeContext | undefined;
|
|
56
|
+
|
|
57
|
+
const useBottomSheetStyleContext = (): BottomSheetContentVariantProps =>
|
|
58
|
+
useBottomSheetScopeContext() ?? {};
|
|
59
|
+
|
|
60
|
+
const IS_WEB = Platform.OS === 'web';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Resolves how a content wrapper reserves room for the footer.
|
|
64
|
+
*
|
|
65
|
+
* gorhom's footer margin adjustment is unsound on web: its reaction first runs with the
|
|
66
|
+
* unmeasured footer sentinel (-999) and adds it to `contentHeight`, then never adds the real
|
|
67
|
+
* footer height. Depending on whether content measures first, a dynamically sized sheet either
|
|
68
|
+
* parks below its container or opens with the footer covering its content. It cannot be fixed
|
|
69
|
+
* with padding because react-native-web only re-reports layout when the content box resizes.
|
|
70
|
+
*
|
|
71
|
+
* So on web, when the sheet's `footer` prop is measured here, a spacer child of the footer's
|
|
72
|
+
* height replaces gorhom's adjustment; its layout lands in the content measurement in any
|
|
73
|
+
* order. With no footer there is nothing to adjust. Otherwise (native, a raw gorhom
|
|
74
|
+
* `footerComponent`, or outside a `BottomSheet.Modal`) gorhom's adjustment is kept.
|
|
75
|
+
*/
|
|
76
|
+
function useFooterMargin(enableFooterMarginAdjustment: boolean | undefined) {
|
|
77
|
+
const scope = useBottomSheetScopeContext();
|
|
78
|
+
const enabled = enableFooterMarginAdjustment ?? scope?.hasFooter ?? true;
|
|
79
|
+
const spacerHeight = enabled && IS_WEB ? scope?.footerHeight : undefined;
|
|
80
|
+
return {
|
|
81
|
+
enableFooterMarginAdjustment: enabled && spacerHeight === undefined,
|
|
82
|
+
spacer: spacerHeight ? <View style={{ height: spacerHeight }} pointerEvents="none" /> : null,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
43
85
|
|
|
44
86
|
const ZERO_INSETS: EdgeInsets = { top: 0, bottom: 0, left: 0, right: 0 };
|
|
45
87
|
|
|
@@ -209,13 +251,35 @@ const BottomSheetModalStyled = forwardRef<
|
|
|
209
251
|
ref,
|
|
210
252
|
) => {
|
|
211
253
|
const parent = useParentContext();
|
|
212
|
-
const
|
|
254
|
+
const hasFooter = footer != null || rest.footerComponent != null;
|
|
255
|
+
const measuresFooter = IS_WEB && footer != null;
|
|
256
|
+
const [measuredFooterHeight, setMeasuredFooterHeight] = useState(0);
|
|
257
|
+
const footerHeight = measuresFooter ? measuredFooterHeight : undefined;
|
|
258
|
+
const ctx = useMemo(
|
|
259
|
+
() => ({
|
|
260
|
+
...parent,
|
|
261
|
+
[SCOPE]: { fullBleed, hasFooter, footerHeight } satisfies BottomSheetScopeContext,
|
|
262
|
+
}),
|
|
263
|
+
[parent, fullBleed, hasFooter, footerHeight],
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const handleFooterLayout = useCallback((event: LayoutChangeEvent) => {
|
|
267
|
+
setMeasuredFooterHeight(event.nativeEvent.layout.height);
|
|
268
|
+
}, []);
|
|
213
269
|
|
|
214
270
|
const renderFooter = useCallback(
|
|
215
271
|
(props: GorhomBottomSheetFooterProps) => (
|
|
216
|
-
<GorhomBottomSheetFooter {...props}>
|
|
272
|
+
<GorhomBottomSheetFooter {...props}>
|
|
273
|
+
{measuresFooter ? (
|
|
274
|
+
<View onLayout={handleFooterLayout} pointerEvents="box-none">
|
|
275
|
+
{footer}
|
|
276
|
+
</View>
|
|
277
|
+
) : (
|
|
278
|
+
footer
|
|
279
|
+
)}
|
|
280
|
+
</GorhomBottomSheetFooter>
|
|
217
281
|
),
|
|
218
|
-
[footer],
|
|
282
|
+
[footer, handleFooterLayout, measuresFooter],
|
|
219
283
|
);
|
|
220
284
|
|
|
221
285
|
const modalRef = useRef<BottomSheetModalRef | null>(null);
|
|
@@ -370,17 +434,22 @@ const BottomSheetModalStyled = forwardRef<
|
|
|
370
434
|
BottomSheetModalStyled.displayName = 'BottomSheet.Modal';
|
|
371
435
|
|
|
372
436
|
// =============================================================================
|
|
373
|
-
// SCROLLVIEW WRAPPER (
|
|
437
|
+
// SCROLLVIEW WRAPPER (reserves room for the sheet's footer by default)
|
|
374
438
|
// =============================================================================
|
|
375
439
|
|
|
376
440
|
function BottomSheetScrollViewStyled({
|
|
377
|
-
enableFooterMarginAdjustment
|
|
441
|
+
enableFooterMarginAdjustment,
|
|
378
442
|
children,
|
|
379
443
|
...rest
|
|
380
444
|
}: React.ComponentPropsWithoutRef<typeof BottomSheetScrollView>) {
|
|
445
|
+
const footerMargin = useFooterMargin(enableFooterMarginAdjustment);
|
|
381
446
|
return (
|
|
382
|
-
<BottomSheetScrollView
|
|
447
|
+
<BottomSheetScrollView
|
|
448
|
+
enableFooterMarginAdjustment={footerMargin.enableFooterMarginAdjustment}
|
|
449
|
+
{...rest}
|
|
450
|
+
>
|
|
383
451
|
{children}
|
|
452
|
+
{footerMargin.spacer}
|
|
384
453
|
</BottomSheetScrollView>
|
|
385
454
|
);
|
|
386
455
|
}
|
|
@@ -388,17 +457,22 @@ function BottomSheetScrollViewStyled({
|
|
|
388
457
|
BottomSheetScrollViewStyled.displayName = 'BottomSheet.ScrollView';
|
|
389
458
|
|
|
390
459
|
// =============================================================================
|
|
391
|
-
// VIEW WRAPPER (
|
|
460
|
+
// VIEW WRAPPER (reserves room for the sheet's footer by default)
|
|
392
461
|
// =============================================================================
|
|
393
462
|
|
|
394
463
|
function BottomSheetViewStyled({
|
|
395
|
-
enableFooterMarginAdjustment
|
|
464
|
+
enableFooterMarginAdjustment,
|
|
396
465
|
children,
|
|
397
466
|
...rest
|
|
398
467
|
}: React.ComponentPropsWithoutRef<typeof BottomSheetView>) {
|
|
468
|
+
const footerMargin = useFooterMargin(enableFooterMarginAdjustment);
|
|
399
469
|
return (
|
|
400
|
-
<BottomSheetView
|
|
470
|
+
<BottomSheetView
|
|
471
|
+
enableFooterMarginAdjustment={footerMargin.enableFooterMarginAdjustment}
|
|
472
|
+
{...rest}
|
|
473
|
+
>
|
|
401
474
|
{children}
|
|
475
|
+
{footerMargin.spacer}
|
|
402
476
|
</BottomSheetView>
|
|
403
477
|
);
|
|
404
478
|
}
|
|
@@ -466,5 +540,6 @@ export function useBottomSheet() {
|
|
|
466
540
|
* ```
|
|
467
541
|
*/
|
|
468
542
|
export function useBottomSheetScrollable() {
|
|
469
|
-
|
|
543
|
+
const enableFooterMarginAdjustment = useBottomSheetScopeContext()?.hasFooter ?? true;
|
|
544
|
+
return useBottomSheetScrollableCreator({ enableFooterMarginAdjustment });
|
|
470
545
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { forwardRef, useState } from 'react';
|
|
2
|
-
import { type TextInput, type TextInputProps, type ViewProps } from 'react-native';
|
|
2
|
+
import { Text, type TextInput, type TextInputProps, type ViewProps } from 'react-native';
|
|
3
3
|
import {
|
|
4
4
|
InputField as InputFieldPrimitive,
|
|
5
5
|
InputRoot as InputRootPrimitive,
|
|
@@ -10,6 +10,7 @@ import { cn } from '@cdx-ui/utils';
|
|
|
10
10
|
import {
|
|
11
11
|
type CurrencyInputVariantProps,
|
|
12
12
|
currencyInputFieldVariants,
|
|
13
|
+
currencyInputPrefixVariants,
|
|
13
14
|
currencyInputRootVariants,
|
|
14
15
|
} from './styles';
|
|
15
16
|
|
|
@@ -44,7 +45,10 @@ export interface CurrencyInputProps
|
|
|
44
45
|
value?: number;
|
|
45
46
|
/** Called with the parsed amount in major currency units, not cents, when the user edits the field. */
|
|
46
47
|
onChangeValue?: (value: number) => void;
|
|
47
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Currency symbol shown before the amount. Defaults to `"$"`. Part of the field text in
|
|
50
|
+
* `ghost`; a separate, non-editable prefix in `outline`.
|
|
51
|
+
*/
|
|
48
52
|
currencySymbol?: string;
|
|
49
53
|
className?: string;
|
|
50
54
|
style?: ViewProps['style'];
|
|
@@ -56,6 +60,7 @@ export const CurrencyInput = forwardRef<TextInput, CurrencyInputProps>(
|
|
|
56
60
|
value,
|
|
57
61
|
onChangeValue,
|
|
58
62
|
currencySymbol = '$',
|
|
63
|
+
variant = 'ghost',
|
|
59
64
|
size = 'default',
|
|
60
65
|
isDisabled,
|
|
61
66
|
isInvalid,
|
|
@@ -90,17 +95,25 @@ export const CurrencyInput = forwardRef<TextInput, CurrencyInputProps>(
|
|
|
90
95
|
type BlurHandler = NonNullable<TextInputProps['onBlur']>;
|
|
91
96
|
type SelectionChangeHandler = NonNullable<TextInputProps['onSelectionChange']>;
|
|
92
97
|
|
|
98
|
+
const isOutline = variant === 'outline';
|
|
99
|
+
|
|
100
|
+
// `outline` renders the symbol as a separate prefix, so the TextInput holds only the
|
|
101
|
+
// amount. Every caret index is measured against this field text, never the full display.
|
|
102
|
+
const fieldTextFor = (cents: number) => {
|
|
103
|
+
const amount = centsToAmountDisplay(cents);
|
|
104
|
+
return isOutline ? amount : `${currencySymbol}${amount}`;
|
|
105
|
+
};
|
|
106
|
+
|
|
93
107
|
const displayCents = editingCents !== null ? editingCents : valueToCents(value);
|
|
94
|
-
const
|
|
95
|
-
const
|
|
108
|
+
const fullDisplay = `${currencySymbol}${centsToAmountDisplay(displayCents)}`;
|
|
109
|
+
const fieldText = fieldTextFor(displayCents);
|
|
96
110
|
const isEmpty = displayCents === 0;
|
|
97
111
|
|
|
98
|
-
// Index just past the last character of the
|
|
99
|
-
// Computed from `cents` (not the render-closure `
|
|
112
|
+
// Index just past the last character of the field text for a given cents.
|
|
113
|
+
// Computed from `cents` (not the render-closure `fieldText`) so the caret is
|
|
100
114
|
// correct in the same commit as a value change, even when a reformat adds or
|
|
101
115
|
// removes a grouping comma (e.g. 444.44 → 3,444.44) and changes the length.
|
|
102
|
-
const caretIndexFor = (cents: number) =>
|
|
103
|
-
`${currencySymbol}${centsToAmountDisplay(cents)}`.length;
|
|
116
|
+
const caretIndexFor = (cents: number) => fieldTextFor(cents).length;
|
|
104
117
|
|
|
105
118
|
const pinCaret = (end: number) => setSelection({ start: end, end });
|
|
106
119
|
|
|
@@ -147,7 +160,7 @@ export const CurrencyInput = forwardRef<TextInput, CurrencyInputProps>(
|
|
|
147
160
|
if (editingCents === null) {
|
|
148
161
|
return;
|
|
149
162
|
}
|
|
150
|
-
const end =
|
|
163
|
+
const end = fieldText.length;
|
|
151
164
|
const { selection: current } = e.nativeEvent;
|
|
152
165
|
if (current.end < end) {
|
|
153
166
|
pinCaret(end);
|
|
@@ -163,13 +176,24 @@ export const CurrencyInput = forwardRef<TextInput, CurrencyInputProps>(
|
|
|
163
176
|
isFocused={isFocused}
|
|
164
177
|
isHovered={isHovered}
|
|
165
178
|
isFullWidth={isFullWidth}
|
|
166
|
-
className={cn(currencyInputRootVariants({ size }), className)}
|
|
179
|
+
className={cn(currencyInputRootVariants({ variant, size }), className)}
|
|
167
180
|
style={style}
|
|
168
181
|
{...dataAttributes({ slot: 'currency-input' })}
|
|
169
182
|
>
|
|
183
|
+
{isOutline ? (
|
|
184
|
+
// Hidden from assistive tech: `accessibilityValue` already announces the symbol.
|
|
185
|
+
<Text
|
|
186
|
+
className={currencyInputPrefixVariants({ size })}
|
|
187
|
+
aria-hidden
|
|
188
|
+
importantForAccessibility="no-hide-descendants"
|
|
189
|
+
{...dataAttributes({ slot: 'currency-input-prefix' })}
|
|
190
|
+
>
|
|
191
|
+
{currencySymbol}
|
|
192
|
+
</Text>
|
|
193
|
+
) : null}
|
|
170
194
|
<InputFieldPrimitive
|
|
171
195
|
ref={ref}
|
|
172
|
-
value={
|
|
196
|
+
value={fieldText}
|
|
173
197
|
selection={selection}
|
|
174
198
|
onChangeText={handleChangeText}
|
|
175
199
|
onSelectionChange={handleSelectionChange}
|
|
@@ -182,7 +206,7 @@ export const CurrencyInput = forwardRef<TextInput, CurrencyInputProps>(
|
|
|
182
206
|
onFocus={handleFocus}
|
|
183
207
|
onBlur={handleBlur}
|
|
184
208
|
className={cn(
|
|
185
|
-
currencyInputFieldVariants({ size }),
|
|
209
|
+
currencyInputFieldVariants({ variant, size }),
|
|
186
210
|
isEmpty ? 'text-content-tertiary' : 'text-content-primary',
|
|
187
211
|
)}
|
|
188
212
|
/>
|
|
@@ -1,7 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn, cva } from '@cdx-ui/utils';
|
|
2
2
|
import { DISABLED_CURSOR } from '../../styles/constants';
|
|
3
|
+
import { inputFieldVariants, inputRootVariants } from '../Input/styles';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
+
export interface CurrencyInputVariantProps {
|
|
6
|
+
/**
|
|
7
|
+
* Visual style. `ghost` is the large, centered, borderless amount entry; `outline` renders
|
|
8
|
+
* the bordered `Input` shell with a leading currency-symbol prefix, for amounts that sit
|
|
9
|
+
* alongside other form fields.
|
|
10
|
+
* @default 'ghost'
|
|
11
|
+
*/
|
|
12
|
+
variant?: 'ghost' | 'outline';
|
|
13
|
+
/**
|
|
14
|
+
* Height, padding, and text size.
|
|
15
|
+
* @default 'default'
|
|
16
|
+
*/
|
|
17
|
+
size?: 'default' | 'small';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const currencyInputGhostRootVariants = cva(
|
|
5
21
|
[
|
|
6
22
|
'w-full items-center justify-center',
|
|
7
23
|
'data-[disabled=true]:opacity-[var(--opacity-disabled)]',
|
|
@@ -21,7 +37,7 @@ export const currencyInputRootVariants = cva(
|
|
|
21
37
|
},
|
|
22
38
|
);
|
|
23
39
|
|
|
24
|
-
|
|
40
|
+
const currencyInputGhostFieldVariants = cva(
|
|
25
41
|
[
|
|
26
42
|
'w-full bg-transparent p-0 text-center',
|
|
27
43
|
'placeholder:text-content-tertiary',
|
|
@@ -41,4 +57,35 @@ export const currencyInputFieldVariants = cva(
|
|
|
41
57
|
},
|
|
42
58
|
);
|
|
43
59
|
|
|
44
|
-
|
|
60
|
+
// `outline` delegates to the Input shell so border, focus, invalid, disabled, and read-only
|
|
61
|
+
// treatments (including the native `data-[field-state=...]` focus selectors) stay in one place.
|
|
62
|
+
// Figma `outlined` spaces the symbol 8px from the amount, tighter than Input's 16px slot gap.
|
|
63
|
+
export const currencyInputRootVariants = ({
|
|
64
|
+
variant = 'ghost',
|
|
65
|
+
size = 'default',
|
|
66
|
+
}: CurrencyInputVariantProps = {}): string =>
|
|
67
|
+
variant === 'outline'
|
|
68
|
+
? cn(inputRootVariants({ variant: 'outline', size }), size === 'default' && 'gap-2')
|
|
69
|
+
: currencyInputGhostRootVariants({ size });
|
|
70
|
+
|
|
71
|
+
export const currencyInputFieldVariants = ({
|
|
72
|
+
variant = 'ghost',
|
|
73
|
+
size = 'default',
|
|
74
|
+
}: CurrencyInputVariantProps = {}): string =>
|
|
75
|
+
variant === 'outline' ? inputFieldVariants({ size }) : currencyInputGhostFieldVariants({ size });
|
|
76
|
+
|
|
77
|
+
// Figma keeps the symbol at body-md on every viewport; only the amount grows to 16px on web <600px.
|
|
78
|
+
export const currencyInputPrefixVariants = cva(
|
|
79
|
+
['shrink-0 font-medium text-content-secondary tracking-normal'],
|
|
80
|
+
{
|
|
81
|
+
variants: {
|
|
82
|
+
size: {
|
|
83
|
+
default: 'text-[0.875rem]',
|
|
84
|
+
small: 'text-[0.75rem]',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
defaultVariants: {
|
|
88
|
+
size: 'default',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
);
|