@yahoo/uds-mobile 2.5.0 → 2.6.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.
Files changed (51) hide show
  1. package/dist/bin/uds-mobile.mjs +10 -2
  2. package/dist/components/Banner/Banner.cjs +179 -0
  3. package/dist/components/Banner/Banner.d.cts +59 -0
  4. package/dist/components/Banner/Banner.d.cts.map +1 -0
  5. package/dist/components/Banner/Banner.d.ts +59 -0
  6. package/dist/components/Banner/Banner.d.ts.map +1 -0
  7. package/dist/components/Banner/Banner.js +178 -0
  8. package/dist/components/Banner/Banner.js.map +1 -0
  9. package/dist/components/Banner/BannerContent.cjs +26 -0
  10. package/dist/components/Banner/BannerContent.d.cts +16 -0
  11. package/dist/components/Banner/BannerContent.d.cts.map +1 -0
  12. package/dist/components/Banner/BannerContent.d.ts +16 -0
  13. package/dist/components/Banner/BannerContent.d.ts.map +1 -0
  14. package/dist/components/Banner/BannerContent.js +25 -0
  15. package/dist/components/Banner/BannerContent.js.map +1 -0
  16. package/dist/components/Banner/BannerDescription.cjs +46 -0
  17. package/dist/components/Banner/BannerDescription.d.cts +37 -0
  18. package/dist/components/Banner/BannerDescription.d.cts.map +1 -0
  19. package/dist/components/Banner/BannerDescription.d.ts +37 -0
  20. package/dist/components/Banner/BannerDescription.d.ts.map +1 -0
  21. package/dist/components/Banner/BannerDescription.js +45 -0
  22. package/dist/components/Banner/BannerDescription.js.map +1 -0
  23. package/dist/components/Banner/BannerTitle.cjs +44 -0
  24. package/dist/components/Banner/BannerTitle.d.cts +35 -0
  25. package/dist/components/Banner/BannerTitle.d.cts.map +1 -0
  26. package/dist/components/Banner/BannerTitle.d.ts +35 -0
  27. package/dist/components/Banner/BannerTitle.d.ts.map +1 -0
  28. package/dist/components/Banner/BannerTitle.js +43 -0
  29. package/dist/components/Banner/BannerTitle.js.map +1 -0
  30. package/dist/components/Banner/index.cjs +11 -0
  31. package/dist/components/Banner/index.d.cts +6 -0
  32. package/dist/components/Banner/index.d.ts +6 -0
  33. package/dist/components/Banner/index.js +7 -0
  34. package/dist/components/Banner/utils.cjs +56 -0
  35. package/dist/components/Banner/utils.d.cts +27 -0
  36. package/dist/components/Banner/utils.d.cts.map +1 -0
  37. package/dist/components/Banner/utils.d.ts +27 -0
  38. package/dist/components/Banner/utils.d.ts.map +1 -0
  39. package/dist/components/Banner/utils.js +53 -0
  40. package/dist/components/Banner/utils.js.map +1 -0
  41. package/dist/types/dist/index.d.cts +19 -1
  42. package/dist/types/dist/index.d.cts.map +1 -1
  43. package/dist/types/dist/index.d.ts +19 -1
  44. package/dist/types/dist/index.d.ts.map +1 -1
  45. package/fonts/index.cjs +213 -213
  46. package/fonts/index.mjs +213 -213
  47. package/generated/styles.cjs +72 -0
  48. package/generated/styles.d.ts +71 -4
  49. package/generated/styles.mjs +72 -0
  50. package/generated/unistyles.d.ts +124 -0
  51. package/package.json +11 -1
@@ -69,11 +69,19 @@ async function formatWithPrettier(content, filePath, prettierConfigPath) {
69
69
  }
70
70
  }
71
71
  /**
72
+ * Returns the base URL for the UDS config API based on the DATABASE env var.
73
+ */
74
+ function getConfigBaseUrl() {
75
+ if (process.env.DATABASE === "local") return "http://localhost:4001";
76
+ return "https://config.uds.build";
77
+ }
78
+ /**
72
79
  * Fetches a config from the UDS config API by ID.
73
80
  */
74
81
  async function fetchConfigById(configId) {
75
- log(`Fetching config: ${configId}`, "dim");
76
- const response = await fetch(`https://config.uds.build/api/config?id=${configId}`);
82
+ const baseUrl = getConfigBaseUrl();
83
+ log(`Fetching config: ${configId} from ${baseUrl}`, "dim");
84
+ const response = await fetch(`${baseUrl}/api/config?id=${configId}`);
77
85
  if (!response.ok) throw new Error(`Failed to fetch config: ${response.status} ${response.statusText}`);
78
86
  const data = await response.json();
79
87
  if (!data.config) throw new Error(`No config found for ID: ${configId}`);
@@ -0,0 +1,179 @@
1
+ /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
+ const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
4
+ const require_components_IconSlot = require('../IconSlot.cjs');
5
+ const require_components_Text = require('../Text.cjs');
6
+ const require_components_IconButton = require('../IconButton.cjs');
7
+ const require_components_Banner_utils = require('./utils.cjs');
8
+ let react = require("react");
9
+ let react_native = require("react-native");
10
+ let react_jsx_runtime = require("react/jsx-runtime");
11
+ let generated_styles = require("../../../generated/styles");
12
+
13
+ //#region src/components/Banner/Banner.tsx
14
+ /**
15
+ * Inject button variants on Button children that don't have an explicit
16
+ * variant set. The last unset Button gets the banner-mapped "primary"
17
+ * variant; any preceding unset Buttons get "secondary".
18
+ * When stacked (3+ actions), buttons get full width.
19
+ */
20
+ function bindActionVariants(actions, bannerVariant, stacked) {
21
+ const primaryVariant = require_components_Banner_utils.BANNER_TO_BUTTON_VARIANT[bannerVariant];
22
+ const unsetIndices = [];
23
+ actions.forEach((child, i) => {
24
+ if (require_components_Banner_utils.hasDisplayName(child, "Button") && (0, react.isValidElement)(child) && child.props.variant === void 0) unsetIndices.push(i);
25
+ });
26
+ return actions.map((child, i) => {
27
+ const extraProps = {};
28
+ if (unsetIndices.includes(i)) extraProps.variant = i === unsetIndices[unsetIndices.length - 1] ? primaryVariant : "secondary";
29
+ if (stacked && !require_components_Banner_utils.hasDisplayName(child, "Button") && (0, react.isValidElement)(child)) extraProps.style = [child.props.style, { alignSelf: "flex-start" }];
30
+ if (Object.keys(extraProps).length === 0) return child;
31
+ return (0, react.cloneElement)(child, {
32
+ key: child.key ?? i,
33
+ ...extraProps
34
+ });
35
+ });
36
+ }
37
+ /**
38
+ * **An inline notification banner for contextual messages with optional actions.**
39
+ *
40
+ * @description
41
+ * Banner is an inline, non-floating notification component that sits in normal document flow.
42
+ * It supports 12 color variants, an optional icon, title, description (truncated to 3 lines),
43
+ * composable actions via children, and an optional dismiss button.
44
+ *
45
+ * On mobile the layout is always column: content stacks above actions.
46
+ *
47
+ * @category Display
48
+ * @platform mobile
49
+ *
50
+ * @example
51
+ * ```tsx
52
+ * import { Banner, BannerContent, BannerTitle, BannerDescription } from '@yahoo/uds-mobile/Banner';
53
+ * import { Button } from '@yahoo/uds-mobile/Button';
54
+ * import { Link } from '@yahoo/uds-mobile/Link';
55
+ *
56
+ * // Simple
57
+ * <Banner variant="info" startIcon="Info" title="Update available" />
58
+ *
59
+ * // With actions
60
+ * <Banner variant="brand" startIcon="Megaphone" title="Notification"
61
+ * description="Description text." onDismiss={() => {}}>
62
+ * <Link>Learn more</Link>
63
+ * <Button size="sm">Primary</Button>
64
+ * </Banner>
65
+ *
66
+ * // Rich content
67
+ * <Banner variant="alert" startIcon="Error" onDismiss={() => {}}>
68
+ * <BannerContent>
69
+ * <BannerTitle>Error occurred</BannerTitle>
70
+ * <BannerDescription>Something went wrong.</BannerDescription>
71
+ * </BannerContent>
72
+ * <Button size="sm">Retry</Button>
73
+ * </Banner>
74
+ * ```
75
+ *
76
+ * @see {@link Badge} for status indicators
77
+ */
78
+ const Banner = (0, react.memo)(function Banner({ variant = "primary", startIcon, title, description, onDismiss, dismissAccessibilityLabel = "Dismiss", children, style, ref, ...rest }) {
79
+ const hasTitle = !!(typeof title === "string" ? title.trim() : title);
80
+ const hasDescription = !!(typeof description === "string" ? description.trim() : description);
81
+ generated_styles.bannerStyles.useVariants({ variant });
82
+ const rootGap = generated_styles.bannerStyles.root.gap ?? 0;
83
+ const closeIconSize = generated_styles.bannerStyles.close.iconSizeToken ?? "xs";
84
+ const { content: bannerContent, actions: rawActions } = require_components_Banner_utils.separateChildren(children);
85
+ const stacked = rawActions.length >= 3;
86
+ const actions = bindActionVariants(rawActions, variant, stacked);
87
+ const hasActions = actions.length > 0;
88
+ const contentArea = bannerContent ?? (hasTitle || hasDescription ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
89
+ style: internalStyles.contentArea,
90
+ children: [hasTitle && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_Text.Text, {
91
+ numberOfLines: 1,
92
+ style: generated_styles.bannerStyles.title,
93
+ children: title
94
+ }), hasDescription && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_Text.Text, {
95
+ numberOfLines: 3,
96
+ style: generated_styles.bannerStyles.description,
97
+ children: description
98
+ })]
99
+ }) : null);
100
+ const isSingleLine = !bannerContent && hasTitle !== hasDescription;
101
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
102
+ ref,
103
+ style: (0, react.useMemo)(() => [
104
+ generated_styles.bannerStyles.root,
105
+ internalStyles.root,
106
+ style
107
+ ], [generated_styles.bannerStyles.root, style]),
108
+ ...rest,
109
+ children: [
110
+ startIcon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_IconSlot.IconSlot, {
111
+ icon: startIcon,
112
+ variant: "fill",
113
+ style: [
114
+ generated_styles.bannerStyles.icon,
115
+ internalStyles.iconShrink,
116
+ isSingleLine ? internalStyles.alignCenter : internalStyles.alignStart
117
+ ]
118
+ }),
119
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
120
+ style: [
121
+ internalStyles.innerWrapper,
122
+ { rowGap: rootGap },
123
+ isSingleLine ? internalStyles.alignCenter : void 0
124
+ ],
125
+ children: [contentArea, hasActions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
126
+ style: stacked ? internalStyles.actionsStacked : internalStyles.actionsRow,
127
+ children: actions
128
+ })]
129
+ }),
130
+ onDismiss && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_IconButton.IconButton, {
131
+ name: "Cross",
132
+ variant: "tertiary",
133
+ size: closeIconSize,
134
+ accessibilityLabel: dismissAccessibilityLabel,
135
+ onPress: onDismiss,
136
+ style: [internalStyles.dismissButton, isSingleLine ? internalStyles.alignCenter : internalStyles.alignStart],
137
+ hitSlop: 12,
138
+ disableEffects: true
139
+ })
140
+ ]
141
+ });
142
+ });
143
+ Banner.displayName = "Banner";
144
+ const internalStyles = react_native.StyleSheet.create({
145
+ root: {
146
+ flexDirection: "row",
147
+ minWidth: 300,
148
+ boxShadow: "inset 0px -20px 20px -10px rgba(31,31,31,0.05)"
149
+ },
150
+ alignCenter: { alignSelf: "center" },
151
+ innerWrapper: {
152
+ flex: 1,
153
+ minWidth: 0,
154
+ flexDirection: "column",
155
+ alignItems: "flex-start"
156
+ },
157
+ contentArea: {
158
+ minWidth: 0,
159
+ rowGap: 2
160
+ },
161
+ actionsRow: {
162
+ flexDirection: "row",
163
+ alignItems: "center",
164
+ alignSelf: "stretch",
165
+ columnGap: 6
166
+ },
167
+ actionsStacked: {
168
+ flexDirection: "column",
169
+ alignItems: "stretch",
170
+ alignSelf: "stretch",
171
+ rowGap: 6
172
+ },
173
+ iconShrink: { flexShrink: 0 },
174
+ dismissButton: { flexShrink: 0 },
175
+ alignStart: { alignSelf: "flex-start" }
176
+ });
177
+
178
+ //#endregion
179
+ exports.Banner = Banner;
@@ -0,0 +1,59 @@
1
+
2
+ import { UniversalBannerProps } from "../../types/dist/index.cjs";
3
+ import { IconSlotType } from "../IconSlot.cjs";
4
+ import * as react from "react";
5
+ import { Ref } from "react";
6
+ import { View, ViewProps } from "react-native";
7
+
8
+ //#region src/components/Banner/Banner.d.ts
9
+ interface BannerProps extends ViewProps, UniversalBannerProps<IconSlotType> {
10
+ /** Accessible label for the dismiss button. @default "Dismiss" */
11
+ dismissAccessibilityLabel?: string;
12
+ /** Ref to the underlying View. */
13
+ ref?: Ref<View>;
14
+ }
15
+ /**
16
+ * **An inline notification banner for contextual messages with optional actions.**
17
+ *
18
+ * @description
19
+ * Banner is an inline, non-floating notification component that sits in normal document flow.
20
+ * It supports 12 color variants, an optional icon, title, description (truncated to 3 lines),
21
+ * composable actions via children, and an optional dismiss button.
22
+ *
23
+ * On mobile the layout is always column: content stacks above actions.
24
+ *
25
+ * @category Display
26
+ * @platform mobile
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * import { Banner, BannerContent, BannerTitle, BannerDescription } from '@yahoo/uds-mobile/Banner';
31
+ * import { Button } from '@yahoo/uds-mobile/Button';
32
+ * import { Link } from '@yahoo/uds-mobile/Link';
33
+ *
34
+ * // Simple
35
+ * <Banner variant="info" startIcon="Info" title="Update available" />
36
+ *
37
+ * // With actions
38
+ * <Banner variant="brand" startIcon="Megaphone" title="Notification"
39
+ * description="Description text." onDismiss={() => {}}>
40
+ * <Link>Learn more</Link>
41
+ * <Button size="sm">Primary</Button>
42
+ * </Banner>
43
+ *
44
+ * // Rich content
45
+ * <Banner variant="alert" startIcon="Error" onDismiss={() => {}}>
46
+ * <BannerContent>
47
+ * <BannerTitle>Error occurred</BannerTitle>
48
+ * <BannerDescription>Something went wrong.</BannerDescription>
49
+ * </BannerContent>
50
+ * <Button size="sm">Retry</Button>
51
+ * </Banner>
52
+ * ```
53
+ *
54
+ * @see {@link Badge} for status indicators
55
+ */
56
+ declare const Banner: react.NamedExoticComponent<BannerProps>;
57
+ //#endregion
58
+ export { Banner, type BannerProps };
59
+ //# sourceMappingURL=Banner.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Banner.d.cts","names":[],"sources":["../../../src/components/Banner/Banner.tsx"],"mappings":";;;;;;;;UAkEU,WAAA,SAAoB,SAAA,EAAW,oBAAA,CAAqB,YAAA;;EAE5D,yBAAA;EAFQ;EAIR,GAAA,GAAM,GAAA,CAAI,IAAA;AAAA;;;;;;;;;;;;;;;;;AAAI;;;;;;;;;;;;;;;;;;;;;;;;;cA4CV,MAAA,EAAM,KAAA,CAAA,oBAAA,CAAA,WAAA"}
@@ -0,0 +1,59 @@
1
+
2
+ import { UniversalBannerProps } from "../../types/dist/index.js";
3
+ import { IconSlotType } from "../IconSlot.js";
4
+ import * as react from "react";
5
+ import { Ref } from "react";
6
+ import { View, ViewProps } from "react-native";
7
+
8
+ //#region src/components/Banner/Banner.d.ts
9
+ interface BannerProps extends ViewProps, UniversalBannerProps<IconSlotType> {
10
+ /** Accessible label for the dismiss button. @default "Dismiss" */
11
+ dismissAccessibilityLabel?: string;
12
+ /** Ref to the underlying View. */
13
+ ref?: Ref<View>;
14
+ }
15
+ /**
16
+ * **An inline notification banner for contextual messages with optional actions.**
17
+ *
18
+ * @description
19
+ * Banner is an inline, non-floating notification component that sits in normal document flow.
20
+ * It supports 12 color variants, an optional icon, title, description (truncated to 3 lines),
21
+ * composable actions via children, and an optional dismiss button.
22
+ *
23
+ * On mobile the layout is always column: content stacks above actions.
24
+ *
25
+ * @category Display
26
+ * @platform mobile
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * import { Banner, BannerContent, BannerTitle, BannerDescription } from '@yahoo/uds-mobile/Banner';
31
+ * import { Button } from '@yahoo/uds-mobile/Button';
32
+ * import { Link } from '@yahoo/uds-mobile/Link';
33
+ *
34
+ * // Simple
35
+ * <Banner variant="info" startIcon="Info" title="Update available" />
36
+ *
37
+ * // With actions
38
+ * <Banner variant="brand" startIcon="Megaphone" title="Notification"
39
+ * description="Description text." onDismiss={() => {}}>
40
+ * <Link>Learn more</Link>
41
+ * <Button size="sm">Primary</Button>
42
+ * </Banner>
43
+ *
44
+ * // Rich content
45
+ * <Banner variant="alert" startIcon="Error" onDismiss={() => {}}>
46
+ * <BannerContent>
47
+ * <BannerTitle>Error occurred</BannerTitle>
48
+ * <BannerDescription>Something went wrong.</BannerDescription>
49
+ * </BannerContent>
50
+ * <Button size="sm">Retry</Button>
51
+ * </Banner>
52
+ * ```
53
+ *
54
+ * @see {@link Badge} for status indicators
55
+ */
56
+ declare const Banner: react.NamedExoticComponent<BannerProps>;
57
+ //#endregion
58
+ export { Banner, type BannerProps };
59
+ //# sourceMappingURL=Banner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Banner.d.ts","names":[],"sources":["../../../src/components/Banner/Banner.tsx"],"mappings":";;;;;;;;UAkEU,WAAA,SAAoB,SAAA,EAAW,oBAAA,CAAqB,YAAA;;EAE5D,yBAAA;EAFQ;EAIR,GAAA,GAAM,GAAA,CAAI,IAAA;AAAA;;;;;;;;;;;;;;;;;AAAI;;;;;;;;;;;;;;;;;;;;;;;;;cA4CV,MAAA,EAAM,KAAA,CAAA,oBAAA,CAAA,WAAA"}
@@ -0,0 +1,178 @@
1
+ /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
+ import { IconSlot } from "../IconSlot.js";
3
+ import { Text as Text$1 } from "../Text.js";
4
+ import { IconButton } from "../IconButton.js";
5
+ import { BANNER_TO_BUTTON_VARIANT, hasDisplayName, separateChildren } from "./utils.js";
6
+ import { cloneElement, isValidElement, memo, useMemo } from "react";
7
+ import { StyleSheet, View } from "react-native";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { bannerStyles } from "../../../generated/styles";
10
+
11
+ //#region src/components/Banner/Banner.tsx
12
+ /**
13
+ * Inject button variants on Button children that don't have an explicit
14
+ * variant set. The last unset Button gets the banner-mapped "primary"
15
+ * variant; any preceding unset Buttons get "secondary".
16
+ * When stacked (3+ actions), buttons get full width.
17
+ */
18
+ function bindActionVariants(actions, bannerVariant, stacked) {
19
+ const primaryVariant = BANNER_TO_BUTTON_VARIANT[bannerVariant];
20
+ const unsetIndices = [];
21
+ actions.forEach((child, i) => {
22
+ if (hasDisplayName(child, "Button") && isValidElement(child) && child.props.variant === void 0) unsetIndices.push(i);
23
+ });
24
+ return actions.map((child, i) => {
25
+ const extraProps = {};
26
+ if (unsetIndices.includes(i)) extraProps.variant = i === unsetIndices[unsetIndices.length - 1] ? primaryVariant : "secondary";
27
+ if (stacked && !hasDisplayName(child, "Button") && isValidElement(child)) extraProps.style = [child.props.style, { alignSelf: "flex-start" }];
28
+ if (Object.keys(extraProps).length === 0) return child;
29
+ return cloneElement(child, {
30
+ key: child.key ?? i,
31
+ ...extraProps
32
+ });
33
+ });
34
+ }
35
+ /**
36
+ * **An inline notification banner for contextual messages with optional actions.**
37
+ *
38
+ * @description
39
+ * Banner is an inline, non-floating notification component that sits in normal document flow.
40
+ * It supports 12 color variants, an optional icon, title, description (truncated to 3 lines),
41
+ * composable actions via children, and an optional dismiss button.
42
+ *
43
+ * On mobile the layout is always column: content stacks above actions.
44
+ *
45
+ * @category Display
46
+ * @platform mobile
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * import { Banner, BannerContent, BannerTitle, BannerDescription } from '@yahoo/uds-mobile/Banner';
51
+ * import { Button } from '@yahoo/uds-mobile/Button';
52
+ * import { Link } from '@yahoo/uds-mobile/Link';
53
+ *
54
+ * // Simple
55
+ * <Banner variant="info" startIcon="Info" title="Update available" />
56
+ *
57
+ * // With actions
58
+ * <Banner variant="brand" startIcon="Megaphone" title="Notification"
59
+ * description="Description text." onDismiss={() => {}}>
60
+ * <Link>Learn more</Link>
61
+ * <Button size="sm">Primary</Button>
62
+ * </Banner>
63
+ *
64
+ * // Rich content
65
+ * <Banner variant="alert" startIcon="Error" onDismiss={() => {}}>
66
+ * <BannerContent>
67
+ * <BannerTitle>Error occurred</BannerTitle>
68
+ * <BannerDescription>Something went wrong.</BannerDescription>
69
+ * </BannerContent>
70
+ * <Button size="sm">Retry</Button>
71
+ * </Banner>
72
+ * ```
73
+ *
74
+ * @see {@link Badge} for status indicators
75
+ */
76
+ const Banner = memo(function Banner({ variant = "primary", startIcon, title, description, onDismiss, dismissAccessibilityLabel = "Dismiss", children, style, ref, ...rest }) {
77
+ const hasTitle = !!(typeof title === "string" ? title.trim() : title);
78
+ const hasDescription = !!(typeof description === "string" ? description.trim() : description);
79
+ bannerStyles.useVariants({ variant });
80
+ const rootGap = bannerStyles.root.gap ?? 0;
81
+ const closeIconSize = bannerStyles.close.iconSizeToken ?? "xs";
82
+ const { content: bannerContent, actions: rawActions } = separateChildren(children);
83
+ const stacked = rawActions.length >= 3;
84
+ const actions = bindActionVariants(rawActions, variant, stacked);
85
+ const hasActions = actions.length > 0;
86
+ const contentArea = bannerContent ?? (hasTitle || hasDescription ? /* @__PURE__ */ jsxs(View, {
87
+ style: internalStyles.contentArea,
88
+ children: [hasTitle && /* @__PURE__ */ jsx(Text$1, {
89
+ numberOfLines: 1,
90
+ style: bannerStyles.title,
91
+ children: title
92
+ }), hasDescription && /* @__PURE__ */ jsx(Text$1, {
93
+ numberOfLines: 3,
94
+ style: bannerStyles.description,
95
+ children: description
96
+ })]
97
+ }) : null);
98
+ const isSingleLine = !bannerContent && hasTitle !== hasDescription;
99
+ return /* @__PURE__ */ jsxs(View, {
100
+ ref,
101
+ style: useMemo(() => [
102
+ bannerStyles.root,
103
+ internalStyles.root,
104
+ style
105
+ ], [bannerStyles.root, style]),
106
+ ...rest,
107
+ children: [
108
+ startIcon && /* @__PURE__ */ jsx(IconSlot, {
109
+ icon: startIcon,
110
+ variant: "fill",
111
+ style: [
112
+ bannerStyles.icon,
113
+ internalStyles.iconShrink,
114
+ isSingleLine ? internalStyles.alignCenter : internalStyles.alignStart
115
+ ]
116
+ }),
117
+ /* @__PURE__ */ jsxs(View, {
118
+ style: [
119
+ internalStyles.innerWrapper,
120
+ { rowGap: rootGap },
121
+ isSingleLine ? internalStyles.alignCenter : void 0
122
+ ],
123
+ children: [contentArea, hasActions && /* @__PURE__ */ jsx(View, {
124
+ style: stacked ? internalStyles.actionsStacked : internalStyles.actionsRow,
125
+ children: actions
126
+ })]
127
+ }),
128
+ onDismiss && /* @__PURE__ */ jsx(IconButton, {
129
+ name: "Cross",
130
+ variant: "tertiary",
131
+ size: closeIconSize,
132
+ accessibilityLabel: dismissAccessibilityLabel,
133
+ onPress: onDismiss,
134
+ style: [internalStyles.dismissButton, isSingleLine ? internalStyles.alignCenter : internalStyles.alignStart],
135
+ hitSlop: 12,
136
+ disableEffects: true
137
+ })
138
+ ]
139
+ });
140
+ });
141
+ Banner.displayName = "Banner";
142
+ const internalStyles = StyleSheet.create({
143
+ root: {
144
+ flexDirection: "row",
145
+ minWidth: 300,
146
+ boxShadow: "inset 0px -20px 20px -10px rgba(31,31,31,0.05)"
147
+ },
148
+ alignCenter: { alignSelf: "center" },
149
+ innerWrapper: {
150
+ flex: 1,
151
+ minWidth: 0,
152
+ flexDirection: "column",
153
+ alignItems: "flex-start"
154
+ },
155
+ contentArea: {
156
+ minWidth: 0,
157
+ rowGap: 2
158
+ },
159
+ actionsRow: {
160
+ flexDirection: "row",
161
+ alignItems: "center",
162
+ alignSelf: "stretch",
163
+ columnGap: 6
164
+ },
165
+ actionsStacked: {
166
+ flexDirection: "column",
167
+ alignItems: "stretch",
168
+ alignSelf: "stretch",
169
+ rowGap: 6
170
+ },
171
+ iconShrink: { flexShrink: 0 },
172
+ dismissButton: { flexShrink: 0 },
173
+ alignStart: { alignSelf: "flex-start" }
174
+ });
175
+
176
+ //#endregion
177
+ export { Banner };
178
+ //# sourceMappingURL=Banner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Banner.js","names":["RNView","Text"],"sources":["../../../src/components/Banner/Banner.tsx"],"sourcesContent":["import type { BannerVariant, UniversalBannerProps } from '@yahoo/uds-types';\nimport type { ReactNode, Ref } from 'react';\nimport { cloneElement, isValidElement, memo, useMemo } from 'react';\nimport type { View, ViewProps } from 'react-native';\nimport { StyleSheet, View as RNView } from 'react-native';\n\nimport { bannerStyles } from '../../../generated/styles';\nimport { IconButton } from '../IconButton';\nimport type { IconSlotType } from '../IconSlot';\nimport { IconSlot } from '../IconSlot';\nimport { Text } from '../Text';\nimport { BANNER_TO_BUTTON_VARIANT, hasDisplayName, separateChildren } from './utils';\n\n/**\n * Inject button variants on Button children that don't have an explicit\n * variant set. The last unset Button gets the banner-mapped \"primary\"\n * variant; any preceding unset Buttons get \"secondary\".\n * When stacked (3+ actions), buttons get full width.\n */\nfunction bindActionVariants(\n actions: ReactNode[],\n bannerVariant: BannerVariant,\n stacked: boolean,\n): ReactNode[] {\n const primaryVariant = BANNER_TO_BUTTON_VARIANT[bannerVariant];\n\n const unsetIndices: number[] = [];\n actions.forEach((child, i) => {\n if (\n hasDisplayName(child, 'Button') &&\n isValidElement<{ variant?: string }>(child) &&\n child.props.variant === undefined\n ) {\n unsetIndices.push(i);\n }\n });\n\n return actions.map((child, i) => {\n const extraProps: Record<string, unknown> = {};\n\n // Auto-bind variant on Buttons without explicit variant\n if (unsetIndices.includes(i)) {\n const isLast = i === unsetIndices[unsetIndices.length - 1];\n extraProps.variant = isLast ? primaryVariant : 'secondary';\n }\n\n // When stacked, non-Button children (e.g. Link) should not stretch full width\n if (stacked && !hasDisplayName(child, 'Button') && isValidElement<ViewProps>(child)) {\n extraProps.style = [child.props.style, { alignSelf: 'flex-start' as const }];\n }\n\n if (Object.keys(extraProps).length === 0) {\n return child;\n }\n\n return cloneElement(child as React.ReactElement, {\n key: (child as React.ReactElement).key ?? i,\n ...extraProps,\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Banner\n// ---------------------------------------------------------------------------\n\ninterface BannerProps extends ViewProps, UniversalBannerProps<IconSlotType> {\n /** Accessible label for the dismiss button. @default \"Dismiss\" */\n dismissAccessibilityLabel?: string;\n /** Ref to the underlying View. */\n ref?: Ref<View>;\n}\n\n/**\n * **An inline notification banner for contextual messages with optional actions.**\n *\n * @description\n * Banner is an inline, non-floating notification component that sits in normal document flow.\n * It supports 12 color variants, an optional icon, title, description (truncated to 3 lines),\n * composable actions via children, and an optional dismiss button.\n *\n * On mobile the layout is always column: content stacks above actions.\n *\n * @category Display\n * @platform mobile\n *\n * @example\n * ```tsx\n * import { Banner, BannerContent, BannerTitle, BannerDescription } from '@yahoo/uds-mobile/Banner';\n * import { Button } from '@yahoo/uds-mobile/Button';\n * import { Link } from '@yahoo/uds-mobile/Link';\n *\n * // Simple\n * <Banner variant=\"info\" startIcon=\"Info\" title=\"Update available\" />\n *\n * // With actions\n * <Banner variant=\"brand\" startIcon=\"Megaphone\" title=\"Notification\"\n * description=\"Description text.\" onDismiss={() => {}}>\n * <Link>Learn more</Link>\n * <Button size=\"sm\">Primary</Button>\n * </Banner>\n *\n * // Rich content\n * <Banner variant=\"alert\" startIcon=\"Error\" onDismiss={() => {}}>\n * <BannerContent>\n * <BannerTitle>Error occurred</BannerTitle>\n * <BannerDescription>Something went wrong.</BannerDescription>\n * </BannerContent>\n * <Button size=\"sm\">Retry</Button>\n * </Banner>\n * ```\n *\n * @see {@link Badge} for status indicators\n */\nconst Banner = memo(function Banner({\n variant = 'primary',\n startIcon,\n title,\n description,\n onDismiss,\n dismissAccessibilityLabel = 'Dismiss',\n children,\n style,\n ref,\n ...rest\n}: BannerProps) {\n const hasTitle = !!(typeof title === 'string' ? title.trim() : title);\n const hasDescription = !!(typeof description === 'string' ? description.trim() : description);\n\n bannerStyles.useVariants({ variant });\n\n const rootGap = bannerStyles.root.gap ?? 0;\n const closeIconSize = bannerStyles.close.iconSizeToken ?? 'xs';\n\n // Separate BannerContent from action children, bind button variants\n const { content: bannerContent, actions: rawActions } = separateChildren(children);\n const stacked = rawActions.length >= 3;\n const actions = bindActionVariants(rawActions, variant, stacked);\n const hasActions = actions.length > 0;\n\n // Build the content area: either explicit BannerContent or auto-generated from props\n const contentArea =\n bannerContent ??\n (hasTitle || hasDescription ? (\n <RNView style={internalStyles.contentArea}>\n {hasTitle && (\n <Text numberOfLines={1} style={bannerStyles.title}>\n {title}\n </Text>\n )}\n {hasDescription && (\n <Text numberOfLines={3} style={bannerStyles.description}>\n {description}\n </Text>\n )}\n </RNView>\n ) : null);\n\n // Center icon/dismiss when content is single-line (title-only or description-only).\n // BannerContent is excluded — we can't inspect its children to know the line count.\n const isSingleLine = !bannerContent && hasTitle !== hasDescription;\n\n const rootStyles = useMemo(\n () => [bannerStyles.root, internalStyles.root, style],\n [bannerStyles.root, style],\n );\n\n return (\n <RNView ref={ref} style={rootStyles} {...rest}>\n {startIcon && (\n <IconSlot\n icon={startIcon}\n variant=\"fill\"\n style={[\n bannerStyles.icon,\n internalStyles.iconShrink,\n isSingleLine ? internalStyles.alignCenter : internalStyles.alignStart,\n ]}\n />\n )}\n\n <RNView\n style={[\n internalStyles.innerWrapper,\n { rowGap: rootGap },\n isSingleLine ? internalStyles.alignCenter : undefined,\n ]}\n >\n {contentArea}\n\n {hasActions && (\n <RNView style={stacked ? internalStyles.actionsStacked : internalStyles.actionsRow}>\n {actions}\n </RNView>\n )}\n </RNView>\n\n {onDismiss && (\n <IconButton\n name=\"Cross\"\n variant=\"tertiary\"\n size={closeIconSize}\n accessibilityLabel={dismissAccessibilityLabel}\n onPress={onDismiss}\n style={[\n internalStyles.dismissButton,\n isSingleLine ? internalStyles.alignCenter : internalStyles.alignStart,\n ]}\n hitSlop={12}\n disableEffects\n />\n )}\n </RNView>\n );\n});\n\nBanner.displayName = 'Banner';\n\nconst internalStyles = StyleSheet.create({\n root: {\n flexDirection: 'row',\n minWidth: 300,\n boxShadow: 'inset 0px -20px 20px -10px rgba(31,31,31,0.05)',\n },\n alignCenter: {\n alignSelf: 'center',\n },\n innerWrapper: {\n flex: 1,\n minWidth: 0,\n flexDirection: 'column',\n alignItems: 'flex-start',\n },\n contentArea: {\n minWidth: 0,\n rowGap: 2,\n },\n actionsRow: {\n flexDirection: 'row',\n alignItems: 'center',\n alignSelf: 'stretch',\n columnGap: 6,\n },\n actionsStacked: {\n flexDirection: 'column',\n alignItems: 'stretch',\n alignSelf: 'stretch',\n rowGap: 6,\n },\n iconShrink: {\n flexShrink: 0,\n },\n dismissButton: {\n flexShrink: 0,\n },\n alignStart: {\n alignSelf: 'flex-start',\n },\n});\n\nexport { Banner, type BannerProps };\n"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
+ const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
4
+ let react = require("react");
5
+ let react_native = require("react-native");
6
+ let react_jsx_runtime = require("react/jsx-runtime");
7
+
8
+ //#region src/components/Banner/BannerContent.tsx
9
+ /**
10
+ * Container for rich banner content using BannerTitle and BannerDescription.
11
+ * When used as a child of Banner, replaces the auto-generated title/description area.
12
+ */
13
+ const BannerContent = (0, react.memo)(function BannerContent({ children }) {
14
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
15
+ style: {
16
+ flex: 1,
17
+ minWidth: 0,
18
+ rowGap: 2
19
+ },
20
+ children
21
+ });
22
+ });
23
+ BannerContent.displayName = "BannerContent";
24
+
25
+ //#endregion
26
+ exports.BannerContent = BannerContent;
@@ -0,0 +1,16 @@
1
+
2
+ import * as react from "react";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/components/Banner/BannerContent.d.ts
6
+ interface BannerContentProps {
7
+ children: ReactNode;
8
+ }
9
+ /**
10
+ * Container for rich banner content using BannerTitle and BannerDescription.
11
+ * When used as a child of Banner, replaces the auto-generated title/description area.
12
+ */
13
+ declare const BannerContent: react.NamedExoticComponent<BannerContentProps>;
14
+ //#endregion
15
+ export { BannerContent, type BannerContentProps };
16
+ //# sourceMappingURL=BannerContent.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BannerContent.d.cts","names":[],"sources":["../../../src/components/Banner/BannerContent.tsx"],"mappings":";;;;;UAIU,kBAAA;EACR,QAAA,EAAU,SAAA;AAAA;AAL2B;;;;AAAA,cAYjC,aAAA,EAAa,KAAA,CAAA,oBAAA,CAAA,kBAAA"}
@@ -0,0 +1,16 @@
1
+
2
+ import * as react from "react";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/components/Banner/BannerContent.d.ts
6
+ interface BannerContentProps {
7
+ children: ReactNode;
8
+ }
9
+ /**
10
+ * Container for rich banner content using BannerTitle and BannerDescription.
11
+ * When used as a child of Banner, replaces the auto-generated title/description area.
12
+ */
13
+ declare const BannerContent: react.NamedExoticComponent<BannerContentProps>;
14
+ //#endregion
15
+ export { BannerContent, type BannerContentProps };
16
+ //# sourceMappingURL=BannerContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BannerContent.d.ts","names":[],"sources":["../../../src/components/Banner/BannerContent.tsx"],"mappings":";;;;;UAIU,kBAAA;EACR,QAAA,EAAU,SAAA;AAAA;AAL2B;;;;AAAA,cAYjC,aAAA,EAAa,KAAA,CAAA,oBAAA,CAAA,kBAAA"}
@@ -0,0 +1,25 @@
1
+ /*! © 2026 Yahoo, Inc. UDS Mobile v0.0.0-development */
2
+ import { memo } from "react";
3
+ import { View } from "react-native";
4
+ import { jsx } from "react/jsx-runtime";
5
+
6
+ //#region src/components/Banner/BannerContent.tsx
7
+ /**
8
+ * Container for rich banner content using BannerTitle and BannerDescription.
9
+ * When used as a child of Banner, replaces the auto-generated title/description area.
10
+ */
11
+ const BannerContent = memo(function BannerContent({ children }) {
12
+ return /* @__PURE__ */ jsx(View, {
13
+ style: {
14
+ flex: 1,
15
+ minWidth: 0,
16
+ rowGap: 2
17
+ },
18
+ children
19
+ });
20
+ });
21
+ BannerContent.displayName = "BannerContent";
22
+
23
+ //#endregion
24
+ export { BannerContent };
25
+ //# sourceMappingURL=BannerContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BannerContent.js","names":[],"sources":["../../../src/components/Banner/BannerContent.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { memo } from 'react';\nimport { View } from 'react-native';\n\ninterface BannerContentProps {\n children: ReactNode;\n}\n\n/**\n * Container for rich banner content using BannerTitle and BannerDescription.\n * When used as a child of Banner, replaces the auto-generated title/description area.\n */\nconst BannerContent = memo(function BannerContent({ children }: BannerContentProps) {\n return <View style={{ flex: 1, minWidth: 0, rowGap: 2 }}>{children}</View>;\n});\n\nBannerContent.displayName = 'BannerContent';\n\nexport { BannerContent, type BannerContentProps };\n"],"mappings":";;;;;;;;;;AAYA,MAAM,gBAAgB,KAAK,SAAS,cAAc,EAAE,YAAgC;AAClF,QAAO,oBAAC;EAAK,OAAO;GAAE,MAAM;GAAG,UAAU;GAAG,QAAQ;GAAG;EAAG;GAAgB;EAC1E;AAEF,cAAc,cAAc"}