@vellira-ui/react-native 2.44.5 → 2.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export type { TabsContentProps, TabsListProps, TabsProps, TabsTriggerProps, } fr
10
10
  export { Tabs } from './components/Tabs';
11
11
  export type { TooltipContentProps, TooltipProps, TooltipRootProps, TooltipTriggerProps, } from './components/Tooltip';
12
12
  export { Tooltip } from './components/Tooltip';
13
- export type { FormFieldProps } from './patterns/FormField';
13
+ export type { FormFieldControlProps, FormFieldDescriptionProps, FormFieldLabelProps, FormFieldMessageProps, FormFieldProps, } from './patterns/FormField';
14
14
  export { FormField } from './patterns/FormField';
15
15
  export type { ButtonProps } from './primitives/Button';
16
16
  export { Button } from './primitives/Button';
package/dist/index.js CHANGED
@@ -1995,6 +1995,13 @@ const createStyles$9 = (theme) => StyleSheet.create({
1995
1995
  fontWeight: fontWeight$2(theme.tokens.typography.weight.medium),
1996
1996
  lineHeight: theme.components.formField.size.md.labelLineHeight
1997
1997
  },
1998
+ labelRow: {
1999
+ flexDirection: "row",
2000
+ justifyContent: "space-between",
2001
+ alignItems: "flex-start",
2002
+ gap: theme.components.formField.size.md.gap
2003
+ },
2004
+ labelAction: { flexShrink: 0 },
1998
2005
  labelDisabled: { color: theme.components.formField.disabled.labelFg },
1999
2006
  required: {
2000
2007
  marginLeft: theme.tokens.spacing[1],
@@ -2031,12 +2038,15 @@ const createStyles$9 = (theme) => StyleSheet.create({
2031
2038
  minWidth: 0,
2032
2039
  alignSelf: "stretch"
2033
2040
  },
2034
- error: {
2035
- color: theme.components.formField.helperText.error.fg,
2041
+ message: {
2042
+ color: theme.components.formField.helperText.default.fg,
2036
2043
  fontFamily: theme.tokens.typography.family.regular,
2037
2044
  fontSize: theme.components.formField.size.md.helperTextFontSize,
2038
2045
  lineHeight: theme.components.formField.size.md.helperTextLineHeight
2039
2046
  },
2047
+ messageSuccess: { color: theme.components.formField.helperText.success.fg },
2048
+ messageWarning: { color: theme.components.formField.helperText.warning.fg },
2049
+ messageDanger: { color: theme.components.formField.helperText.error.fg },
2040
2050
  helperTextDisabled: { color: theme.components.formField.disabled.helperTextFg }
2041
2051
  });
2042
2052
  //#endregion
@@ -2045,29 +2055,92 @@ const FormFieldContext = createContext(null);
2045
2055
  const useFormFieldContext = () => useContext(FormFieldContext);
2046
2056
  //#endregion
2047
2057
  //#region src/patterns/FormField/FormField.tsx
2048
- function FormField({ id, label, description, error, required = false, disabled = false, invalid = false, size = "md", labelInfo, optionalText, children, style, controlStyle, labelStyle, descriptionStyle, errorStyle, ...rest }) {
2058
+ function createFormFieldSlot(name, displayName) {
2059
+ const Slot = () => null;
2060
+ Slot.__velliraFormFieldPart = name;
2061
+ Slot.displayName = displayName;
2062
+ return Slot;
2063
+ }
2064
+ function parseFormFieldChildren(children) {
2065
+ const fallbackChildren = [];
2066
+ const parsed = { hasSlots: false };
2067
+ Children.forEach(children, (child) => {
2068
+ if (!isValidElement(child)) {
2069
+ if (child !== null && child !== void 0 && child !== false) fallbackChildren.push(child);
2070
+ return;
2071
+ }
2072
+ switch (child.type.__velliraFormFieldPart) {
2073
+ case "label":
2074
+ parsed.hasSlots = true;
2075
+ parsed.label = child.props;
2076
+ return;
2077
+ case "description":
2078
+ parsed.hasSlots = true;
2079
+ parsed.description = child.props;
2080
+ return;
2081
+ case "control":
2082
+ parsed.hasSlots = true;
2083
+ parsed.control = child.props;
2084
+ return;
2085
+ case "message":
2086
+ parsed.hasSlots = true;
2087
+ parsed.message = child.props;
2088
+ return;
2089
+ default: fallbackChildren.push(child);
2090
+ }
2091
+ });
2092
+ if (fallbackChildren.length > 0) parsed.fallbackChildren = fallbackChildren.length === 1 ? fallbackChildren[0] : fallbackChildren;
2093
+ return parsed;
2094
+ }
2095
+ function FormFieldRoot({ id, label, description, error, message, messageTone, messageLive, required = false, disabled = false, invalid = false, size = "md", labelInfo, labelAction, optionalText, children, style, controlStyle, labelStyle, descriptionStyle, errorStyle, messageStyle, ...rest }) {
2096
+ const parsedChildren = parseFormFieldChildren(children);
2097
+ const resolvedLabel = label ?? parsedChildren.label?.children;
2098
+ const resolvedDescription = description ?? parsedChildren.description?.children;
2099
+ const resolvedMessage = message ?? parsedChildren.message?.children;
2100
+ const resolvedMessageTone = messageTone ?? parsedChildren.message?.tone ?? "neutral";
2101
+ const resolvedMessageLive = messageLive ?? parsedChildren.message?.live ?? "off";
2102
+ const resolvedLabelInfo = labelInfo ?? parsedChildren.label?.info;
2103
+ const resolvedLabelAction = labelAction ?? parsedChildren.label?.action;
2104
+ const resolvedOptionalText = optionalText ?? parsedChildren.label?.optionalText;
2105
+ const resolvedChildren = parsedChildren.hasSlots ? parsedChildren.control?.children ?? parsedChildren.fallbackChildren : children;
2049
2106
  const { theme } = useTheme();
2050
2107
  const styles = useThemeStyles(createStyles$9);
2051
2108
  const sizeTokens = theme.components.formField.size[size];
2052
2109
  const generatedId = useId();
2053
2110
  const controlId = id ?? generatedId;
2054
- const labelId = label ? `${controlId}-label` : void 0;
2055
- const descriptionId = description ? `${controlId}-description` : void 0;
2111
+ const labelId = resolvedLabel ? `${controlId}-label` : void 0;
2112
+ const descriptionId = resolvedDescription ? `${controlId}-description` : void 0;
2056
2113
  const errorId = error ? `${controlId}-error` : void 0;
2114
+ const messageId = !error && resolvedMessage ? `${controlId}-message` : void 0;
2115
+ const isInvalid = invalid || Boolean(error);
2116
+ const visibleMessage = error ?? resolvedMessage;
2117
+ const visibleTone = error ? "danger" : resolvedMessageTone;
2057
2118
  const contextValue = {
2058
2119
  controlId,
2059
2120
  labelId,
2060
2121
  descriptionId,
2061
2122
  errorId,
2123
+ messageId,
2062
2124
  description,
2063
2125
  error,
2126
+ message: resolvedMessage,
2064
2127
  required,
2065
2128
  disabled,
2066
- invalid: invalid || Boolean(error),
2129
+ invalid: isInvalid,
2067
2130
  size,
2068
2131
  ariaLabelledBy: labelId,
2069
- ariaDescribedBy: [descriptionId, errorId].filter(Boolean).join(" ") || void 0
2132
+ ariaDescribedBy: [
2133
+ descriptionId,
2134
+ errorId,
2135
+ messageId
2136
+ ].filter(Boolean).join(" ") || void 0
2070
2137
  };
2138
+ const messageToneStyle = {
2139
+ neutral: void 0,
2140
+ success: styles.messageSuccess,
2141
+ warning: styles.messageWarning,
2142
+ danger: styles.messageDanger
2143
+ }[visibleTone];
2071
2144
  return /* @__PURE__ */ jsxs(View, {
2072
2145
  ...rest,
2073
2146
  accessibilityState: disabled ? { disabled: true } : void 0,
@@ -2077,54 +2150,61 @@ function FormField({ id, label, description, error, required = false, disabled =
2077
2150
  style
2078
2151
  ],
2079
2152
  children: [
2080
- label && (typeof label === "string" || typeof label === "number" ? /* @__PURE__ */ jsxs(Text, {
2081
- style: [
2082
- styles.label,
2083
- {
2084
- fontSize: sizeTokens.labelFontSize,
2085
- lineHeight: sizeTokens.labelLineHeight
2086
- },
2087
- disabled && styles.labelDisabled,
2088
- labelStyle
2089
- ],
2090
- children: [
2091
- label,
2092
- required && /* @__PURE__ */ jsx(Text, {
2093
- style: styles.required,
2094
- accessible: false,
2095
- importantForAccessibility: "no",
2096
- children: " *"
2097
- }),
2098
- !required && optionalText && /* @__PURE__ */ jsx(Text, {
2099
- style: [styles.optional, {
2100
- fontSize: sizeTokens.optionalFontSize,
2101
- lineHeight: sizeTokens.optionalLineHeight
2102
- }],
2103
- children: optionalText
2104
- }),
2105
- labelInfo && /* @__PURE__ */ jsx(Text, {
2106
- style: [styles.labelInfo, {
2107
- fontSize: sizeTokens.labelInfoFontSize,
2108
- lineHeight: sizeTokens.labelInfoSize
2109
- }],
2110
- children: labelInfo
2111
- })
2112
- ]
2113
- }) : /* @__PURE__ */ jsxs(View, {
2114
- style: styles.customLabel,
2115
- children: [
2116
- label,
2117
- required && /* @__PURE__ */ jsx(Text, {
2118
- style: styles.required,
2119
- accessible: false,
2120
- importantForAccessibility: "no",
2121
- children: "*"
2122
- }),
2123
- !required && optionalText,
2124
- labelInfo
2125
- ]
2126
- })),
2127
- description && (typeof description === "string" || typeof description === "number" ? /* @__PURE__ */ jsx(Text, {
2153
+ (resolvedLabel || resolvedLabelAction) && /* @__PURE__ */ jsxs(View, {
2154
+ style: [styles.labelRow, { gap: sizeTokens.gap }],
2155
+ children: [resolvedLabel && (typeof resolvedLabel === "string" || typeof resolvedLabel === "number" ? /* @__PURE__ */ jsxs(Text, {
2156
+ style: [
2157
+ styles.label,
2158
+ {
2159
+ fontSize: sizeTokens.labelFontSize,
2160
+ lineHeight: sizeTokens.labelLineHeight
2161
+ },
2162
+ disabled && styles.labelDisabled,
2163
+ parsedChildren.label?.style,
2164
+ labelStyle
2165
+ ],
2166
+ children: [
2167
+ resolvedLabel,
2168
+ required && /* @__PURE__ */ jsx(Text, {
2169
+ style: styles.required,
2170
+ accessible: false,
2171
+ importantForAccessibility: "no",
2172
+ children: " *"
2173
+ }),
2174
+ !required && resolvedOptionalText && /* @__PURE__ */ jsx(Text, {
2175
+ style: [styles.optional, {
2176
+ fontSize: sizeTokens.optionalFontSize,
2177
+ lineHeight: sizeTokens.optionalLineHeight
2178
+ }],
2179
+ children: resolvedOptionalText
2180
+ }),
2181
+ resolvedLabelInfo && /* @__PURE__ */ jsx(Text, {
2182
+ style: [styles.labelInfo, {
2183
+ fontSize: sizeTokens.labelInfoFontSize,
2184
+ lineHeight: sizeTokens.labelInfoSize
2185
+ }],
2186
+ children: resolvedLabelInfo
2187
+ })
2188
+ ]
2189
+ }) : /* @__PURE__ */ jsxs(View, {
2190
+ style: styles.customLabel,
2191
+ children: [
2192
+ resolvedLabel,
2193
+ required && /* @__PURE__ */ jsx(Text, {
2194
+ style: styles.required,
2195
+ accessible: false,
2196
+ importantForAccessibility: "no",
2197
+ children: "*"
2198
+ }),
2199
+ !required && resolvedOptionalText,
2200
+ resolvedLabelInfo
2201
+ ]
2202
+ })), resolvedLabelAction && /* @__PURE__ */ jsx(View, {
2203
+ style: styles.labelAction,
2204
+ children: resolvedLabelAction
2205
+ })]
2206
+ }),
2207
+ resolvedDescription && (typeof resolvedDescription === "string" || typeof resolvedDescription === "number" ? /* @__PURE__ */ jsx(Text, {
2128
2208
  style: [
2129
2209
  styles.description,
2130
2210
  {
@@ -2132,40 +2212,55 @@ function FormField({ id, label, description, error, required = false, disabled =
2132
2212
  lineHeight: sizeTokens.descriptionLineHeight
2133
2213
  },
2134
2214
  disabled && styles.descriptionDisabled,
2215
+ parsedChildren.description?.style,
2135
2216
  descriptionStyle
2136
2217
  ],
2137
- children: description
2138
- }) : description),
2218
+ children: resolvedDescription
2219
+ }) : resolvedDescription),
2139
2220
  /* @__PURE__ */ jsx(FormFieldContext.Provider, {
2140
2221
  value: contextValue,
2141
2222
  children: /* @__PURE__ */ jsx(View, {
2142
2223
  style: [
2143
2224
  styles.control,
2144
2225
  { gap: sizeTokens.gap },
2226
+ parsedChildren.control?.style,
2145
2227
  controlStyle
2146
2228
  ],
2147
- children
2229
+ children: resolvedChildren
2148
2230
  })
2149
2231
  }),
2150
- error && (typeof error === "string" || typeof error === "number" ? /* @__PURE__ */ jsx(Text, {
2151
- accessibilityLiveRegion: "polite",
2232
+ visibleMessage && (typeof visibleMessage === "string" || typeof visibleMessage === "number" ? /* @__PURE__ */ jsx(Text, {
2233
+ accessibilityLiveRegion: error || resolvedMessageLive === "polite" ? "polite" : void 0,
2152
2234
  style: [
2153
- styles.error,
2235
+ styles.message,
2154
2236
  {
2155
2237
  fontSize: sizeTokens.helperTextFontSize,
2156
2238
  lineHeight: sizeTokens.helperTextLineHeight
2157
2239
  },
2240
+ messageToneStyle,
2158
2241
  disabled && styles.helperTextDisabled,
2159
- errorStyle
2242
+ !error && parsedChildren.message?.style,
2243
+ error ? errorStyle : messageStyle
2160
2244
  ],
2161
- children: error
2245
+ children: visibleMessage
2162
2246
  }) : /* @__PURE__ */ jsx(View, {
2163
- accessibilityLiveRegion: "polite",
2164
- children: error
2247
+ accessibilityLiveRegion: error || resolvedMessageLive === "polite" ? "polite" : void 0,
2248
+ children: visibleMessage
2165
2249
  }))
2166
2250
  ]
2167
2251
  });
2168
2252
  }
2253
+ const FormFieldLabel = createFormFieldSlot("label", "FormField.Label");
2254
+ const FormFieldDescription = createFormFieldSlot("description", "FormField.Description");
2255
+ const FormFieldControl = createFormFieldSlot("control", "FormField.Control");
2256
+ const FormFieldMessage = createFormFieldSlot("message", "FormField.Message");
2257
+ const FormField = Object.assign(FormFieldRoot, {
2258
+ Label: FormFieldLabel,
2259
+ Description: FormFieldDescription,
2260
+ Control: FormFieldControl,
2261
+ Message: FormFieldMessage,
2262
+ displayName: "FormField"
2263
+ });
2169
2264
  //#endregion
2170
2265
  //#region src/components/RadioGroup/RadioGroup.styles.ts
2171
2266
  const createStyles$8 = (_theme) => StyleSheet.create({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellira-ui/react-native",
3
- "version": "2.44.5",
3
+ "version": "2.45.0",
4
4
  "description": "React Native components for Vellira Design System",
5
5
  "author": "Roman Bakurov",
6
6
  "license": "MIT",