@cdx-ui/components 0.0.1-beta.71 → 0.0.1-beta.73

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 (60) hide show
  1. package/README.md +1 -1
  2. package/lib/commonjs/components/Alert/index.js +263 -0
  3. package/lib/commonjs/components/Alert/index.js.map +1 -0
  4. package/lib/commonjs/components/Alert/styles.js +87 -0
  5. package/lib/commonjs/components/Alert/styles.js.map +1 -0
  6. package/lib/commonjs/components/CLAUDE.md +1 -1
  7. package/lib/commonjs/components/index.js +12 -0
  8. package/lib/commonjs/components/index.js.map +1 -1
  9. package/lib/commonjs/figma/Alert.Button.figma.js +31 -0
  10. package/lib/commonjs/figma/Alert.Button.figma.js.map +1 -0
  11. package/lib/commonjs/figma/Alert.Close.figma.js +24 -0
  12. package/lib/commonjs/figma/Alert.Close.figma.js.map +1 -0
  13. package/lib/commonjs/figma/Alert.Description.figma.js +20 -0
  14. package/lib/commonjs/figma/Alert.Description.figma.js.map +1 -0
  15. package/lib/commonjs/figma/Alert.Title.figma.js +20 -0
  16. package/lib/commonjs/figma/Alert.Title.figma.js.map +1 -0
  17. package/lib/commonjs/figma/Alert.figma.js +42 -0
  18. package/lib/commonjs/figma/Alert.figma.js.map +1 -0
  19. package/lib/module/components/Alert/index.js +259 -0
  20. package/lib/module/components/Alert/index.js.map +1 -0
  21. package/lib/module/components/Alert/styles.js +84 -0
  22. package/lib/module/components/Alert/styles.js.map +1 -0
  23. package/lib/module/components/CLAUDE.md +1 -1
  24. package/lib/module/components/index.js +1 -0
  25. package/lib/module/components/index.js.map +1 -1
  26. package/lib/module/figma/Alert.Button.figma.js +25 -0
  27. package/lib/module/figma/Alert.Button.figma.js.map +1 -0
  28. package/lib/module/figma/Alert.Close.figma.js +18 -0
  29. package/lib/module/figma/Alert.Close.figma.js.map +1 -0
  30. package/lib/module/figma/Alert.Description.figma.js +14 -0
  31. package/lib/module/figma/Alert.Description.figma.js.map +1 -0
  32. package/lib/module/figma/Alert.Title.figma.js +14 -0
  33. package/lib/module/figma/Alert.Title.figma.js.map +1 -0
  34. package/lib/module/figma/Alert.figma.js +36 -0
  35. package/lib/module/figma/Alert.figma.js.map +1 -0
  36. package/lib/typescript/components/Alert/index.d.ts +67 -0
  37. package/lib/typescript/components/Alert/index.d.ts.map +1 -0
  38. package/lib/typescript/components/Alert/styles.d.ts +19 -0
  39. package/lib/typescript/components/Alert/styles.d.ts.map +1 -0
  40. package/lib/typescript/components/Button/styles.d.ts +4 -4
  41. package/lib/typescript/components/Chip/styles.d.ts +3 -3
  42. package/lib/typescript/components/IconButton/styles.d.ts +2 -2
  43. package/lib/typescript/components/Tile/styles.d.ts +1 -1
  44. package/lib/typescript/components/index.d.ts +1 -0
  45. package/lib/typescript/components/index.d.ts.map +1 -1
  46. package/lib/typescript/figma/Alert.Button.figma.d.ts +11 -0
  47. package/lib/typescript/figma/Alert.Button.figma.d.ts.map +1 -0
  48. package/lib/typescript/figma/Alert.Close.figma.d.ts +11 -0
  49. package/lib/typescript/figma/Alert.Close.figma.d.ts.map +1 -0
  50. package/lib/typescript/figma/Alert.Description.figma.d.ts +8 -0
  51. package/lib/typescript/figma/Alert.Description.figma.d.ts.map +1 -0
  52. package/lib/typescript/figma/Alert.Title.figma.d.ts +8 -0
  53. package/lib/typescript/figma/Alert.Title.figma.d.ts.map +1 -0
  54. package/lib/typescript/figma/Alert.figma.d.ts +8 -0
  55. package/lib/typescript/figma/Alert.figma.d.ts.map +1 -0
  56. package/package.json +4 -4
  57. package/src/components/Alert/index.tsx +318 -0
  58. package/src/components/Alert/styles.ts +88 -0
  59. package/src/components/CLAUDE.md +1 -1
  60. package/src/components/index.ts +1 -0
@@ -1,19 +1,19 @@
1
1
  import { type VariantProps } from 'class-variance-authority';
2
2
  export declare const buttonRootVariants: (props?: ({
3
3
  variant?: "solid" | "outline" | "ghost" | null | undefined;
4
- color?: "action" | "danger" | "warning" | "success" | "info" | null | undefined;
4
+ color?: "danger" | "warning" | "success" | "info" | "action" | null | undefined;
5
5
  size?: "small" | "default" | null | undefined;
6
6
  fullWidth?: boolean | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  export declare const buttonTextVariants: (props?: ({
9
9
  variant?: "solid" | "outline" | "ghost" | null | undefined;
10
- color?: "action" | "danger" | "warning" | "success" | "info" | null | undefined;
10
+ color?: "danger" | "warning" | "success" | "info" | "action" | null | undefined;
11
11
  size?: "small" | "default" | null | undefined;
12
12
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
13
13
  export declare const buttonSpinnerVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
14
14
  export declare const buttonSpinnerColorVariants: (props?: ({
15
15
  variant?: "solid" | "outline" | "ghost" | null | undefined;
16
- color?: "action" | "danger" | "warning" | "success" | "info" | null | undefined;
16
+ color?: "danger" | "warning" | "success" | "info" | "action" | null | undefined;
17
17
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
18
18
  export declare const buttonGroupVariants: (props?: ({
19
19
  flexDirection?: "row" | "column" | "row-reverse" | "column-reverse" | null | undefined;
@@ -21,7 +21,7 @@ export declare const buttonGroupVariants: (props?: ({
21
21
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
22
22
  export declare const buttonIconVariants: (props?: ({
23
23
  variant?: "solid" | "outline" | "ghost" | null | undefined;
24
- color?: "action" | "danger" | "warning" | "success" | "info" | null | undefined;
24
+ color?: "danger" | "warning" | "success" | "info" | "action" | null | undefined;
25
25
  size?: "small" | "default" | null | undefined;
26
26
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
27
27
  export type ButtonVariantProps = VariantProps<typeof buttonRootVariants>;
@@ -1,17 +1,17 @@
1
1
  import { type VariantProps } from 'class-variance-authority';
2
2
  export declare const chipRootVariants: (props?: ({
3
3
  variant?: "outline" | "tint" | null | undefined;
4
- color?: "action" | "danger" | "warning" | "success" | "info" | "default" | null | undefined;
4
+ color?: "danger" | "warning" | "success" | "info" | "default" | "action" | null | undefined;
5
5
  size?: "small" | "default" | "xsmall" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  export declare const chipLabelVariants: (props?: ({
8
8
  variant?: "outline" | "tint" | null | undefined;
9
- color?: "action" | "danger" | "warning" | "success" | "info" | "default" | null | undefined;
9
+ color?: "danger" | "warning" | "success" | "info" | "default" | "action" | null | undefined;
10
10
  size?: "small" | "default" | "xsmall" | null | undefined;
11
11
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
12
12
  export declare const chipIconVariants: (props?: ({
13
13
  size?: "small" | "default" | "xsmall" | null | undefined;
14
- color?: "action" | "danger" | "warning" | "success" | "info" | "default" | null | undefined;
14
+ color?: "danger" | "warning" | "success" | "info" | "default" | "action" | null | undefined;
15
15
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
16
16
  export declare const chipAvatarVariants: (props?: ({
17
17
  size?: "small" | "default" | "xsmall" | null | undefined;
@@ -1,7 +1,7 @@
1
1
  import { type VariantProps } from 'class-variance-authority';
2
2
  export declare const iconButtonRootVariants: (props?: ({
3
3
  variant?: "solid" | "ghost" | "tint" | null | undefined;
4
- color?: "action" | "danger" | "neutral" | null | undefined;
4
+ color?: "danger" | "action" | "neutral" | null | undefined;
5
5
  size?: "small" | "default" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  export declare const iconButtonGlyphVariants: (props?: ({
@@ -9,7 +9,7 @@ export declare const iconButtonGlyphVariants: (props?: ({
9
9
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
10
10
  export declare const iconButtonIconColorVariants: (props?: ({
11
11
  variant?: "solid" | "ghost" | "tint" | null | undefined;
12
- color?: "action" | "danger" | "neutral" | null | undefined;
12
+ color?: "danger" | "action" | "neutral" | null | undefined;
13
13
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
14
14
  export type IconButtonVariantProps = VariantProps<typeof iconButtonRootVariants>;
15
15
  //# sourceMappingURL=styles.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { type VariantProps } from 'class-variance-authority';
2
2
  export declare const tileGroupVariants: (props?: ({
3
3
  direction?: "row" | "column" | null | undefined;
4
- spacing?: "default" | "none" | null | undefined;
4
+ spacing?: "none" | "default" | null | undefined;
5
5
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
6
  export type TileGroupVariantProps = VariantProps<typeof tileGroupVariants>;
7
7
  export declare const tileRootVariants: (props?: ({
@@ -1,3 +1,4 @@
1
+ export * from './Alert';
1
2
  export * from './AlertDialog';
2
3
  export * from './Avatar';
3
4
  export * from './BottomSheet';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,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,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,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"}
@@ -0,0 +1,11 @@
1
+ import figma from 'figma';
2
+ declare const _default: {
3
+ id: string;
4
+ imports: string[];
5
+ metadata: {
6
+ nestable: boolean;
7
+ };
8
+ example: figma.ResultSection[] | figma.TemplateStringResult | null;
9
+ };
10
+ export default _default;
11
+ //# sourceMappingURL=Alert.Button.figma.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.Button.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/Alert.Button.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;;;;AAa1B,wBAYE"}
@@ -0,0 +1,11 @@
1
+ import figma from 'figma';
2
+ declare const _default: {
3
+ id: string;
4
+ imports: string[];
5
+ metadata: {
6
+ nestable: boolean;
7
+ };
8
+ example: figma.ResultSection[] | figma.TemplateStringResult;
9
+ };
10
+ export default _default;
11
+ //# sourceMappingURL=Alert.Close.figma.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.Close.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/Alert.Close.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;;;;AAQ1B,wBAUE"}
@@ -0,0 +1,8 @@
1
+ import figma from 'figma';
2
+ declare const _default: {
3
+ id: string;
4
+ imports: string[];
5
+ example: figma.TemplateStringResult;
6
+ };
7
+ export default _default;
8
+ //# sourceMappingURL=Alert.Description.figma.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.Description.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/Alert.Description.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;AAM1B,wBAIE"}
@@ -0,0 +1,8 @@
1
+ import figma from 'figma';
2
+ declare const _default: {
3
+ id: string;
4
+ imports: string[];
5
+ example: figma.TemplateStringResult;
6
+ };
7
+ export default _default;
8
+ //# sourceMappingURL=Alert.Title.figma.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.Title.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/Alert.Title.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;AAM1B,wBAIE"}
@@ -0,0 +1,8 @@
1
+ import figma from 'figma';
2
+ declare const _default: {
3
+ id: string;
4
+ imports: string[];
5
+ example: figma.TemplateStringResult;
6
+ };
7
+ export default _default;
8
+ //# sourceMappingURL=Alert.figma.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/Alert.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;AA4B1B,wBAiBE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdx-ui/components",
3
- "version": "0.0.1-beta.71",
3
+ "version": "0.0.1-beta.73",
4
4
  "main": "lib/commonjs/index.js",
5
5
  "module": "lib/module/index.js",
6
6
  "react-native": "src/index.ts",
@@ -67,9 +67,9 @@
67
67
  "@gorhom/bottom-sheet": "^5.2.6",
68
68
  "class-variance-authority": "^0.7.1",
69
69
  "uniwind": "1.6.1",
70
- "@cdx-ui/primitives": "0.0.1-beta.71",
71
- "@cdx-ui/utils": "0.0.1-beta.71",
72
- "@cdx-ui/icons": "0.0.1-beta.71"
70
+ "@cdx-ui/primitives": "0.0.1-beta.73",
71
+ "@cdx-ui/utils": "0.0.1-beta.73",
72
+ "@cdx-ui/icons": "0.0.1-beta.73"
73
73
  },
74
74
  "devDependencies": {
75
75
  "@react-navigation/bottom-tabs": "*",
@@ -0,0 +1,318 @@
1
+ import React, { forwardRef, useMemo, type ReactNode } from 'react';
2
+ import { Text, View, type TextProps, type ViewProps } from 'react-native';
3
+ import { Slot, dataAttributes, mergeDataAttributes } from '@cdx-ui/primitives';
4
+ import type { ForgeIcon } from '@cdx-ui/icons';
5
+ import { CheckCircle, EmergencyHome, Info, Warning } from '@cdx-ui/icons';
6
+ import { cn, ParentContext, useParentContext, useStyleContext } from '@cdx-ui/utils';
7
+ import { Icon, type IconProps } from '../Icon';
8
+ import {
9
+ alertActionsVariants,
10
+ alertBodyVariants,
11
+ alertDescriptionVariants,
12
+ alertIconVariants,
13
+ alertRootVariants,
14
+ alertTextVariants,
15
+ alertTitleVariants,
16
+ type AlertSeverity,
17
+ type AlertVariantProps,
18
+ } from './styles';
19
+
20
+ // =============================================================================
21
+ // CONTEXT
22
+ // =============================================================================
23
+
24
+ const SCOPE = 'ALERT';
25
+
26
+ interface AlertContextValue {
27
+ severity: AlertSeverity;
28
+ }
29
+
30
+ const useAlertStyleContext = (): AlertContextValue => {
31
+ const ctx = useStyleContext(SCOPE) as { severity?: AlertSeverity };
32
+ return { severity: ctx?.severity ?? 'info' };
33
+ };
34
+
35
+ // Severity → default icon mapping
36
+ const SEVERITY_ICONS: Record<AlertSeverity, ForgeIcon> = {
37
+ danger: EmergencyHome,
38
+ warning: Warning,
39
+ success: CheckCircle,
40
+ info: Info,
41
+ };
42
+
43
+ // =============================================================================
44
+ // ROOT
45
+ // =============================================================================
46
+
47
+ export interface AlertProps extends ViewProps, AlertVariantProps {
48
+ /**
49
+ * Replace the root element with the consumer's child element via `Slot`.
50
+ * When `true`, children are rendered as-is (no automatic icon/text/actions
51
+ * layout splitting). Severity context is still provided so sub-components
52
+ * receive the correct styles.
53
+ */
54
+ asChild?: boolean;
55
+ /** Severity level that controls background colour, icon, and live-region urgency. */
56
+ severity?: AlertSeverity;
57
+ className?: string;
58
+ /**
59
+ * Sub-components (`Alert.Icon`, `Alert.Title`, `Alert.Description`,
60
+ * `Alert.Actions`) must be rendered as **direct** children — wrapping them
61
+ * in HOCs or `memo()` will break the automatic layout splitting.
62
+ */
63
+ children?: ReactNode;
64
+ }
65
+
66
+ const AlertRoot = forwardRef<View, AlertProps>(
67
+ ({ asChild, severity = 'info', className, style, children, ...props }, ref) => {
68
+ const isAssertive = severity === 'danger' || severity === 'warning';
69
+ const parent = useParentContext();
70
+ const ctx = useMemo(() => ({ ...parent, [SCOPE]: { severity } }), [parent, severity]);
71
+
72
+ const rootClassName = cn(alertRootVariants({ severity }), className);
73
+ const role = isAssertive ? 'alert' : 'status';
74
+ const liveRegion = isAssertive ? 'assertive' : 'polite';
75
+ const dataProps = mergeDataAttributes(props, dataAttributes({ slot: 'alert' }));
76
+
77
+ if (asChild) {
78
+ return (
79
+ <ParentContext.Provider value={ctx}>
80
+ <Slot
81
+ ref={ref}
82
+ className={rootClassName}
83
+ style={style}
84
+ role={role}
85
+ accessibilityLiveRegion={liveRegion}
86
+ {...props}
87
+ {...dataProps}
88
+ >
89
+ {children}
90
+ </Slot>
91
+ </ParentContext.Provider>
92
+ );
93
+ }
94
+
95
+ // Split children into three regions:
96
+ // 1. Alert.Icon — rendered at inline-start (left)
97
+ // 2. Alert.Actions — rendered at inline-end (right), beside the text
98
+ // 3. Everything else (Title, Description) — text column, flex-1
99
+ //
100
+ // Layout: [Icon] [flex-1 flex-row: [text flex-1] [Actions]]
101
+ const childArray = React.Children.toArray(children);
102
+ const iconChild = childArray.find(
103
+ (child) =>
104
+ React.isValidElement(child) && (child as React.ReactElement).type === AlertIconComponent,
105
+ );
106
+ const actionsChild = childArray.find(
107
+ (child) => React.isValidElement(child) && (child as React.ReactElement).type === AlertActions,
108
+ );
109
+ const textChildren = childArray.filter(
110
+ (child) =>
111
+ !React.isValidElement(child) ||
112
+ ((child as React.ReactElement).type !== AlertIconComponent &&
113
+ (child as React.ReactElement).type !== AlertActions),
114
+ );
115
+ const hasBody = textChildren.length > 0 || !!actionsChild;
116
+
117
+ return (
118
+ <ParentContext.Provider value={ctx}>
119
+ <View
120
+ ref={ref}
121
+ className={rootClassName}
122
+ style={style}
123
+ role={role}
124
+ accessibilityLiveRegion={liveRegion}
125
+ {...props}
126
+ {...dataProps}
127
+ >
128
+ {iconChild}
129
+ {hasBody ? (
130
+ <View className={alertBodyVariants()}>
131
+ {textChildren.length > 0 ? (
132
+ <View className={alertTextVariants()}>{textChildren}</View>
133
+ ) : null}
134
+ {actionsChild}
135
+ </View>
136
+ ) : null}
137
+ </View>
138
+ </ParentContext.Provider>
139
+ );
140
+ },
141
+ );
142
+
143
+ AlertRoot.displayName = 'Alert';
144
+
145
+ // =============================================================================
146
+ // ICON
147
+ // =============================================================================
148
+
149
+ export interface AlertIconProps extends Omit<IconProps, 'as'> {
150
+ asChild?: boolean;
151
+ /**
152
+ * Override the auto-rendered severity icon. Omit to use the default icon for
153
+ * the current severity (EmergencyHome, Warning, CheckCircle, or Info).
154
+ * Not required when `asChild` is set.
155
+ */
156
+ as?: ForgeIcon;
157
+ }
158
+
159
+ const AlertIconComponent = forwardRef<View, AlertIconProps>(
160
+ ({ asChild, as: asOverride, className, style, ...props }, ref) => {
161
+ const { severity } = useAlertStyleContext();
162
+ const computedClassName = cn(alertIconVariants({ severity }), className);
163
+
164
+ if (asChild) {
165
+ return (
166
+ <Slot
167
+ ref={ref}
168
+ className={computedClassName}
169
+ style={style}
170
+ {...props}
171
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'alert-icon' }))}
172
+ />
173
+ );
174
+ }
175
+
176
+ return (
177
+ <Icon
178
+ as={asOverride ?? SEVERITY_ICONS[severity]}
179
+ className={computedClassName}
180
+ style={style}
181
+ {...props}
182
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'alert-icon' }))}
183
+ />
184
+ );
185
+ },
186
+ );
187
+
188
+ AlertIconComponent.displayName = 'Alert.Icon';
189
+
190
+ // =============================================================================
191
+ // TITLE
192
+ // =============================================================================
193
+
194
+ export interface AlertTitleProps extends TextProps {
195
+ asChild?: boolean;
196
+ className?: string;
197
+ children?: ReactNode;
198
+ }
199
+
200
+ const AlertTitle = forwardRef<Text, AlertTitleProps>(
201
+ ({ asChild, className, style, children, ...props }, ref) => {
202
+ const { severity } = useAlertStyleContext();
203
+ const computedClassName = cn(alertTitleVariants({ severity }), className);
204
+ const Comp = asChild ? Slot : Text;
205
+
206
+ return (
207
+ <Comp
208
+ ref={ref}
209
+ className={computedClassName}
210
+ style={style}
211
+ {...props}
212
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'alert-title' }))}
213
+ >
214
+ {children}
215
+ </Comp>
216
+ );
217
+ },
218
+ );
219
+
220
+ AlertTitle.displayName = 'Alert.Title';
221
+
222
+ // =============================================================================
223
+ // DESCRIPTION
224
+ // =============================================================================
225
+
226
+ export interface AlertDescriptionProps extends TextProps {
227
+ asChild?: boolean;
228
+ className?: string;
229
+ children?: ReactNode;
230
+ }
231
+
232
+ const AlertDescription = forwardRef<Text, AlertDescriptionProps>(
233
+ ({ asChild, className, style, children, ...props }, ref) => {
234
+ const { severity } = useAlertStyleContext();
235
+ const computedClassName = cn(alertDescriptionVariants({ severity }), className);
236
+ const Comp = asChild ? Slot : Text;
237
+
238
+ return (
239
+ <Comp
240
+ ref={ref}
241
+ className={computedClassName}
242
+ style={style}
243
+ {...props}
244
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'alert-description' }))}
245
+ >
246
+ {children}
247
+ </Comp>
248
+ );
249
+ },
250
+ );
251
+
252
+ AlertDescription.displayName = 'Alert.Description';
253
+
254
+ // =============================================================================
255
+ // ACTIONS
256
+ // =============================================================================
257
+
258
+ export interface AlertActionsProps extends ViewProps {
259
+ /**
260
+ * Replace the wrapper element with the consumer's child via `Slot`.
261
+ * **Note:** when `true`, automatic `color={severity}` injection on
262
+ * direct `Button`/`IconButton` children is bypassed — the consumer
263
+ * must set `color` explicitly.
264
+ */
265
+ asChild?: boolean;
266
+ className?: string;
267
+ children?: ReactNode;
268
+ }
269
+
270
+ const AlertActions = forwardRef<View, AlertActionsProps>(
271
+ ({ asChild, className, style, children, ...props }, ref) => {
272
+ const { severity } = useAlertStyleContext();
273
+ const computedClassName = cn(alertActionsVariants(), className);
274
+ const Comp = asChild ? Slot : View;
275
+
276
+ // Auto-inject color={severity} on direct Button / IconButton children unless
277
+ // the consumer already provides a color prop.
278
+ const injectedChildren = React.Children.map(children, (child) => {
279
+ if (!React.isValidElement<{ color?: unknown }>(child)) return child;
280
+ if ('color' in child.props) return child;
281
+ return React.cloneElement(child, { color: severity });
282
+ });
283
+
284
+ return (
285
+ <Comp
286
+ ref={ref}
287
+ className={computedClassName}
288
+ style={style}
289
+ {...props}
290
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'alert-actions' }))}
291
+ >
292
+ {asChild ? children : injectedChildren}
293
+ </Comp>
294
+ );
295
+ },
296
+ );
297
+
298
+ AlertActions.displayName = 'Alert.Actions';
299
+
300
+ // =============================================================================
301
+ // COMPOUND EXPORT
302
+ // =============================================================================
303
+
304
+ type AlertCompoundComponent = typeof AlertRoot & {
305
+ Icon: typeof AlertIconComponent;
306
+ Title: typeof AlertTitle;
307
+ Description: typeof AlertDescription;
308
+ Actions: typeof AlertActions;
309
+ };
310
+
311
+ export const Alert = Object.assign(AlertRoot, {
312
+ Icon: AlertIconComponent,
313
+ Title: AlertTitle,
314
+ Description: AlertDescription,
315
+ Actions: AlertActions,
316
+ }) as AlertCompoundComponent;
317
+
318
+ export type { AlertVariantProps, AlertSeverity };
@@ -0,0 +1,88 @@
1
+ import { cva, type VariantProps } from 'class-variance-authority';
2
+
3
+ // ── Severity type ────────────────────────────────────────────────────────────
4
+
5
+ export type AlertSeverity = 'danger' | 'warning' | 'success' | 'info';
6
+
7
+ // ── Root ─────────────────────────────────────────────────────────────────────
8
+
9
+ export const alertRootVariants = cva(
10
+ ['flex-row items-start', 'gap-2 px-3', 'rounded-[var(--border-radius-default)]'],
11
+ {
12
+ variants: {
13
+ severity: {
14
+ danger: 'bg-surface-danger-subtle',
15
+ warning: 'bg-surface-warning-subtle',
16
+ success: 'bg-surface-success-subtle',
17
+ info: 'bg-surface-info-subtle',
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ severity: 'info',
22
+ },
23
+ },
24
+ );
25
+
26
+ // ── Icon ─────────────────────────────────────────────────────────────────────
27
+
28
+ export const alertIconVariants = cva(['size-5 shrink-0 mt-3'], {
29
+ variants: {
30
+ severity: {
31
+ danger: 'text-content-danger-on-subtle',
32
+ warning: 'text-content-warning-on-subtle',
33
+ success: 'text-content-success-on-subtle',
34
+ info: 'text-content-info-on-subtle',
35
+ },
36
+ },
37
+ defaultVariants: {
38
+ severity: 'info',
39
+ },
40
+ });
41
+
42
+ // ── Body (internal row: text area + trailing actions) ────────────────────────
43
+
44
+ export const alertBodyVariants = cva(['flex-1 flex-row items-start gap-2 min-w-0']);
45
+
46
+ // ── Text (internal flex-col for title + description) ─────────────────────────
47
+
48
+ export const alertTextVariants = cva(['flex-1 flex-col gap-1 min-w-0 mt-3 mb-3']);
49
+
50
+ // ── Title ────────────────────────────────────────────────────────────────────
51
+
52
+ export const alertTitleVariants = cva(['body-md font-semibold'], {
53
+ variants: {
54
+ severity: {
55
+ danger: 'text-content-danger-on-subtle',
56
+ warning: 'text-content-warning-on-subtle',
57
+ success: 'text-content-success-on-subtle',
58
+ info: 'text-content-info-on-subtle',
59
+ },
60
+ },
61
+ defaultVariants: {
62
+ severity: 'info',
63
+ },
64
+ });
65
+
66
+ // ── Description ──────────────────────────────────────────────────────────────
67
+
68
+ export const alertDescriptionVariants = cva(['body-md'], {
69
+ variants: {
70
+ severity: {
71
+ danger: 'text-content-danger-on-subtle',
72
+ warning: 'text-content-warning-on-subtle',
73
+ success: 'text-content-success-on-subtle',
74
+ info: 'text-content-info-on-subtle',
75
+ },
76
+ },
77
+ defaultVariants: {
78
+ severity: 'info',
79
+ },
80
+ });
81
+
82
+ // ── Actions ──────────────────────────────────────────────────────────────────
83
+
84
+ export const alertActionsVariants = cva(['shrink-0 flex-row items-center gap-1.5 mt-1.5 mb-1.5']);
85
+
86
+ // ── Types ─────────────────────────────────────────────────────────────────────
87
+
88
+ export type AlertVariantProps = VariantProps<typeof alertRootVariants>;
@@ -113,7 +113,7 @@ Where: **styled layer.** Pure styling hint with no behavior or a11y semantics
113
113
  - `asChild` re-uses `Slot` from `@cdx-ui/primitives` — no new primitive needed for sub-slots
114
114
  - `buttonIconVariants` / `buttonSpinnerVariants` carry `data-[icon=inline-start]:me-1.5 data-[icon=inline-end]:ms-1.5` so leading/trailing padding works without per-call overrides
115
115
 
116
- `packages/components/src/components/IconButton/index.tsx` shows the second axis of Standard 1: a styled-layer slot (the glyph) is the place that opts into `useButtonContext()` when its styling reacts to interaction state. The pattern is the same as the primitive Root — call `useButtonContext()`, spread `dataAttributes({ ... })` — only it lives in the styled layer.
116
+ `packages/components/src/components/QuickActionButton/index.tsx` shows the second axis of Standard 1: a styled-layer sub-slot (the Indicator) opts into `useButtonContext()` when its styling reacts to interaction state. The pattern is the same as the primitive Root — call `useButtonContext()`, spread `mergeDataAttributes(props, dataAttributes({ ... }))` — only it lives in the styled layer.
117
117
 
118
118
  ### Pattern summary
119
119
 
@@ -1,3 +1,4 @@
1
+ export * from './Alert';
1
2
  export * from './AlertDialog';
2
3
  export * from './Avatar';
3
4
  export * from './BottomSheet';