@swan-io/lake 18.0.3 → 18.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swan-io/lake",
3
- "version": "18.0.3",
3
+ "version": "18.1.0",
4
4
  "engines": {
5
5
  "node": ">22.12.0"
6
6
  },
@@ -106,5 +106,5 @@ export const BottomPanel = ({ visible, onPressClose, children, returnFocus = tru
106
106
  if (onPressClose != null) {
107
107
  onPressClose();
108
108
  }
109
- }, style: styles.trap, children: [_jsx(View, { style: styles.modal, children: children }), onPressClose != null ? (_jsx(Pressable, { onPress: onPressClose, style: styles.pressableOverlay })) : null] }) }) })) : null }) })] }));
109
+ }, style: styles.trap, children: [_jsx(View, { style: styles.modal, children: children }), onPressClose != null ? (_jsx(Pressable, { onPress: onPressClose, style: styles.pressableOverlay, tabIndex: -1, "aria-hidden": true })) : null] }) }) })) : null }) })] }));
110
110
  };
@@ -14,5 +14,8 @@ type Props = {
14
14
  };
15
15
  export declare const BreadcrumbsRoot: ({ rootLevelCrumbs, children }: Props) => import("react").JSX.Element;
16
16
  export declare const useCrumb: (crumb?: Crumb) => void;
17
- export declare const Breadcrumbs: () => import("react").JSX.Element;
17
+ type BreadcrumbsProps = {
18
+ ariaLabel?: string;
19
+ };
20
+ export declare const Breadcrumbs: ({ ariaLabel }: BreadcrumbsProps) => import("react").JSX.Element;
18
21
  export {};
@@ -340,7 +340,7 @@ const arrangeArray = (array) => {
340
340
  end: array.slice(-2),
341
341
  };
342
342
  };
343
- export const Breadcrumbs = () => {
343
+ export const Breadcrumbs = ({ ariaLabel = "Breadcrumb" }) => {
344
344
  const crumbs = useBreadcrumbs();
345
345
  const cleanCrumbs = useMemo(() => {
346
346
  const hasCrumb = (value) => isNotNullish(value.crumb);
@@ -358,5 +358,5 @@ export const Breadcrumbs = () => {
358
358
  isRootCrumb,
359
359
  })));
360
360
  }, [cleanCrumbs]);
361
- return (_jsxs(View, { role: "navigation", style: styles.container, children: [start.map(({ id, crumb, isFirst, isLast, isRootCrumb }) => (_jsx(BreadcrumbsItem, { crumb: crumb, isFirstItem: isFirst, isLastItem: isLast, shouldAnimate: !previousCrumbs.has(id) && !isRootCrumb }, id))), collapsed.length > 0 ? _jsx(BreadcrumbsDropdownItems, { crumbs: collapsed }) : null, end.map(({ id, crumb, isLast, isRootCrumb }) => (_jsx(BreadcrumbsItem, { crumb: crumb, isLastItem: isLast, shouldAnimate: !previousCrumbs.has(id) && !isRootCrumb }, id)))] }));
361
+ return (_jsxs(View, { role: "navigation", "aria-label": ariaLabel, style: styles.container, children: [start.map(({ id, crumb, isFirst, isLast, isRootCrumb }) => (_jsx(BreadcrumbsItem, { crumb: crumb, isFirstItem: isFirst, isLastItem: isLast, shouldAnimate: !previousCrumbs.has(id) && !isRootCrumb }, id))), collapsed.length > 0 ? _jsx(BreadcrumbsDropdownItems, { crumbs: collapsed }) : null, end.map(({ id, crumb, isLast, isRootCrumb }) => (_jsx(BreadcrumbsItem, { crumb: crumb, isLastItem: isLast, shouldAnimate: !previousCrumbs.has(id) && !isRootCrumb }, id)))] }));
362
362
  };
@@ -220,7 +220,7 @@ export const LakeButton = memo(({ ref, ariaControls, ariaExpanded, ariaLabel, ch
220
220
  isSmall ? styles.textSmall : styles.text,
221
221
  shouldHideContents && styles.hidden,
222
222
  { color: textColor },
223
- ], children: children })) : (_jsx(Box, { alignItems: "center", direction: "row", justifyContent: "center", style: [vertical && styles.vertical, shouldHideContents && styles.hidden], children: children })), hasIconEnd && (_jsxs(_Fragment, { children: [isNotNullish(children) && _jsx(Space, { height: spaceHeight, width: spaceWidth }), _jsx(Icon, { color: textColor, name: icon, size: iconSize, style: shouldHideContents && styles.hidden })] })), loading && (_jsx(View, { style: styles.loaderContainer, children: _jsx(ActivityIndicator, { color: isPrimary ? colors[color].contrast : colors[color].primary, size: iconSize }) })), isPrimary && _jsx(View, { style: [styles.hiddenView, pressed && styles.pressed] }), match(progressAnimation)
223
+ ], children: children })) : (_jsx(Box, { alignItems: "center", direction: "row", justifyContent: "center", style: [vertical && styles.vertical, shouldHideContents && styles.hidden], children: children })), hasIconEnd && (_jsxs(_Fragment, { children: [isNotNullish(children) && _jsx(Space, { height: spaceHeight, width: spaceWidth }), _jsx(Icon, { color: textColor, name: icon, size: iconSize, style: shouldHideContents && styles.hidden })] })), loading && (_jsx(View, { style: styles.loaderContainer, children: _jsx(ActivityIndicator, { "aria-hidden": true, color: isPrimary ? colors[color].contrast : colors[color].primary, size: iconSize }) })), isPrimary && _jsx(View, { style: [styles.hiddenView, pressed && styles.pressed] }), match(progressAnimation)
224
224
  .with(Option.P.Some(P.select()), ({ startTime, now, duration }) => (_jsxs(View, { style: styles.loaderContainer, children: [_jsx(View, { style: [
225
225
  styles.loaderContainerProgress,
226
226
  { transform: `scaleX(${((now - startTime) / duration) * 100}%)` },
@@ -12,9 +12,10 @@ type Props = {
12
12
  help?: ReactNode;
13
13
  render: (id: string) => ReactNode;
14
14
  actions?: ReactNode;
15
+ actionsAlign?: "content" | "labelAndContent";
15
16
  readOnly?: boolean;
16
17
  style?: StyleProp<ViewStyle>;
17
18
  description?: string;
18
19
  };
19
- export declare const LakeLabel: ({ label, optionalLabel, description, extra, readOnly, color, readOnlyColor, type, help, render, actions, style, }: Props) => import("react").JSX.Element;
20
+ export declare const LakeLabel: ({ label, optionalLabel, description, extra, readOnly, color, readOnlyColor, type, help, render, actions, actionsAlign, style, }: Props) => import("react").JSX.Element;
20
21
  export {};
@@ -1,5 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useId, useRef } from "react";
2
+ import { useCallback, useId } from "react";
3
3
  import { StyleSheet, unstable_createElement, View, } from "react-native";
4
4
  import { match } from "ts-pattern";
5
5
  import { commonStyles } from "../constants/commonStyles";
@@ -21,26 +21,33 @@ const styles = StyleSheet.create({
21
21
  optionalLabel: {
22
22
  fontStyle: "italic",
23
23
  },
24
+ content: {
25
+ alignSelf: "stretch",
26
+ justifyContent: "flex-end",
27
+ },
28
+ topActions: {
29
+ // matches LakeTextInput height, so actions are centered on the input, not on its error line
30
+ minHeight: 40,
31
+ justifyContent: "center",
32
+ },
24
33
  });
25
34
  const Label = (props) => {
26
35
  return unstable_createElement("label", props);
27
36
  };
28
37
  const defaultLabelType = "formSmall";
29
- export const LakeLabel = ({ label, optionalLabel, description, extra, readOnly = false, color = "current", readOnlyColor = colors[color].primary, type = defaultLabelType, help, render, actions, style, }) => {
38
+ export const LakeLabel = ({ label, optionalLabel, description, extra, readOnly = false, color = "current", readOnlyColor = colors[color].primary, type = defaultLabelType, help, render, actions, actionsAlign = "labelAndContent", style, }) => {
30
39
  const id = useId();
31
- const containerRef = useRef(null);
40
+ const isFormLabel = type === "form" || type === "formSmall" || type === "radioGroup";
32
41
  const onClick = useCallback((event) => {
33
42
  event.preventDefault();
34
- if (containerRef.current != null) {
35
- const container = containerRef.current;
36
- const target = container.querySelector(`[id="${id}"]`);
37
- target === null || target === void 0 ? void 0 : target.focus();
38
- }
43
+ const target = document.getElementById(id);
44
+ target === null || target === void 0 ? void 0 : target.focus();
39
45
  }, [id]);
40
- return (_jsxs(Box, { style: [styles.container, style], direction: "row", alignItems: "center", justifyContent: "spaceBetween", children: [_jsxs(View, { style: commonStyles.fill, ref: containerRef, children: [_jsxs(Box, { direction: "row", justifyContent: "spaceBetween", alignItems: "center", children: [_jsxs(Box, { direction: "row", alignItems: "center", shrink: 1, children: [type === "form" || type === "formSmall" || type === "radioGroup" ? (_jsxs(Box, { shrink: 1, children: [_jsxs(Label, { onClick: onClick, htmlFor: id, style: [styles.label, readOnly && { color: readOnlyColor }], children: [label, optionalLabel != null && (_jsx(LakeText, { color: colors.gray[400], style: styles.optionalLabel, children: ` - ${optionalLabel}` }))] }), description != null && (_jsxs(_Fragment, { children: [_jsx(LakeText, { variant: "smallRegular", children: description }), _jsx(Space, { height: 8 })] }))] })) : (_jsxs(LakeText, { variant: "medium", color: readOnlyColor, id: id, children: [label, optionalLabel != null && (_jsx(LakeText, { color: colors.gray[400], style: styles.optionalLabel, children: ` - ${optionalLabel}` }))] })), isNotNullish(extra) && extra()] }), isNotNullish(help) && (_jsxs(_Fragment, { children: [_jsx(Space, { width: 16 }), help] }))] }), _jsx(Space, { height: match(type)
46
+ const renderActions = () => isNotNullish(actions) && (_jsxs(_Fragment, { children: [_jsx(Space, { width: 16 }), actionsAlign === "content" && isFormLabel ? (_jsx(View, { style: styles.topActions, children: actions })) : (actions)] }));
47
+ return (_jsxs(Box, { style: [styles.container, style], direction: "row", alignItems: "center", children: [_jsxs(View, { style: commonStyles.fill, children: [_jsxs(Box, { direction: "row", justifyContent: "spaceBetween", alignItems: "center", children: [_jsxs(Box, { direction: "row", alignItems: "center", shrink: 1, children: [isFormLabel ? (_jsxs(Box, { shrink: 1, children: [_jsxs(Label, { onClick: onClick, htmlFor: id, style: [styles.label, readOnly && { color: readOnlyColor }], children: [label, optionalLabel != null && (_jsx(LakeText, { color: colors.gray[400], style: styles.optionalLabel, children: ` - ${optionalLabel}` }))] }), description != null && (_jsxs(_Fragment, { children: [_jsx(LakeText, { variant: "smallRegular", children: description }), _jsx(Space, { height: 8 })] }))] })) : (_jsxs(LakeText, { variant: "medium", color: readOnlyColor, children: [label, optionalLabel != null && (_jsx(LakeText, { color: colors.gray[400], style: styles.optionalLabel, children: ` - ${optionalLabel}` }))] })), isNotNullish(extra) && extra()] }), isNotNullish(help) && (_jsxs(_Fragment, { children: [_jsx(Space, { width: 16 }), help] }))] }), _jsx(Space, { height: match(type)
41
48
  .returnType()
42
49
  .with("formSmall", "viewSmall", () => 4)
43
50
  .with("form", "view", () => 8)
44
51
  .with("radioGroup", () => 12)
45
- .exhaustive() }), _jsx(View, { "aria-labelledby": type === "view" || type === "viewSmall" ? id : undefined, children: render(id) })] }), isNotNullish(actions) && (_jsxs(_Fragment, { children: [_jsx(Space, { width: 16 }), actions] }))] }));
52
+ .exhaustive() }), _jsxs(Box, { direction: "row", alignItems: isFormLabel ? "start" : "center", children: [_jsx(View, { style: [commonStyles.fill, styles.content], children: render(id) }), actionsAlign === "content" && renderActions()] })] }), actionsAlign === "labelAndContent" && renderActions()] }));
46
53
  };
@@ -164,11 +164,11 @@ maxCharCount, help, warning = false, info, renderEnd, ...props }) => {
164
164
  hasError && styles.error,
165
165
  valid && styles.valid,
166
166
  stylesFromProps,
167
- ], ref: containerRef, children: [isNotNullish(icon) && (_jsx(Icon, { name: icon, size: 20, color: colors.current.primary, style: styles.icon })), _jsx(TextInput, { "aria-expanded": ariaExpanded, "aria-controls": ariaControls, inputMode: inputMode, ...props, defaultValue: defaultValue, value: isNullish(defaultValue) ? (value !== null && value !== void 0 ? value : "") : value, onFocus: onFocus, onBlur: onBlur, readOnly: !isInteractive, onChange: onChange, multiline: multiline, ref: mergedRef, style: [
167
+ ], ref: containerRef, children: [isNotNullish(icon) && (_jsx(Icon, { name: icon, size: 20, color: colors.current.primary, style: styles.icon })), _jsx(TextInput, { "aria-expanded": ariaExpanded, "aria-controls": ariaControls, "aria-busy": validating, inputMode: inputMode, ...props, defaultValue: defaultValue, value: isNullish(defaultValue) ? (value !== null && value !== void 0 ? value : "") : value, onFocus: onFocus, onBlur: onBlur, readOnly: !isInteractive, onChange: onChange, multiline: multiline, ref: mergedRef, style: [
168
168
  styles.input,
169
169
  multiline && styles.multilineInput,
170
170
  readOnly && hasError && styles.readOnlyError,
171
171
  disabled && styles.disabled,
172
172
  readOnly && styles.readOnly,
173
- ] }), isNotNullish(renderEnd) && _jsx(View, { style: styles.endComponents, children: renderEnd() }), validating && (_jsx(ActivityIndicator, { size: "small", style: styles.endIcon, color: colors.current[500] })), !validating && hasError && (_jsx(Icon, { name: "warning-regular", size: 20, color: colors.negative[400], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), !validating && warning && !hasError && (_jsx(Icon, { name: "warning-regular", size: 20, color: colors.warning[500], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), !validating && info && !hasError && (_jsx(Icon, { name: "info-regular", size: 20, color: colors.shakespear[500], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), !validating && !hasError && valid && (_jsx(Icon, { name: "checkmark-filled", size: 20, color: colors.positive[400], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] }))] }), isNotNullish(units) && isNotNullish(onUnitChange) ? (_jsx(Box, { children: _jsx(LakeSelect, { value: unit, onValueChange: onUnitChange, items: units.map(value => ({ name: value, value })), disabled: disabled, style: [styles.unit, (disabled || readOnly) && styles.unitDisabled], mode: "borderless", hideErrors: true }) })) : isNotNullish(unit) ? (_jsx(LakeText, { color: colors.gray[900], style: [styles.unit, (disabled || readOnly) && styles.unitDisabled], children: unit })) : null] }), children] }), !hideErrors && (_jsxs(Box, { direction: "row", style: styles.errorContainer, children: [isNotNullish(error) ? (_jsx(LakeText, { variant: "smallRegular", color: colors.negative[500], children: error })) : (_jsx(LakeText, { variant: "smallRegular", color: colors.gray[500], children: help !== null && help !== void 0 ? help : " " })), isNotNullish(info) && (_jsx(LakeText, { variant: "smallRegular", color: colors.shakespear[500], children: info })), isNotNullish(maxCharCount) && (_jsxs(_Fragment, { children: [_jsx(Fill, { minWidth: 4 }), _jsxs(LakeText, { variant: "smallRegular", color: charCount > maxCharCount ? colors.negative[500] : colors.gray[400], style: styles.descriptionLimitation, children: [charCount, " / ", maxCharCount] })] }))] }))] }));
173
+ ] }), isNotNullish(renderEnd) && _jsx(View, { style: styles.endComponents, children: renderEnd() }), validating && (_jsx(ActivityIndicator, { "aria-hidden": true, size: "small", style: styles.endIcon, color: colors.current[500] })), !validating && hasError && (_jsx(Icon, { name: "warning-regular", size: 20, color: colors.negative[400], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), !validating && warning && !hasError && (_jsx(Icon, { name: "warning-regular", size: 20, color: colors.warning[500], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), !validating && info && !hasError && (_jsx(Icon, { name: "info-regular", size: 20, color: colors.shakespear[500], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] })), !validating && !hasError && valid && (_jsx(Icon, { name: "checkmark-filled", size: 20, color: colors.positive[400], style: [styles.endIcon, readOnly && styles.readOnlyEndIcon] }))] }), isNotNullish(units) && isNotNullish(onUnitChange) ? (_jsx(Box, { children: _jsx(LakeSelect, { value: unit, onValueChange: onUnitChange, items: units.map(value => ({ name: value, value })), disabled: disabled, style: [styles.unit, (disabled || readOnly) && styles.unitDisabled], mode: "borderless", hideErrors: true }) })) : isNotNullish(unit) ? (_jsx(LakeText, { color: colors.gray[900], style: [styles.unit, (disabled || readOnly) && styles.unitDisabled], children: unit })) : null] }), children] }), !hideErrors && (_jsxs(Box, { direction: "row", style: styles.errorContainer, children: [isNotNullish(error) ? (_jsx(LakeText, { variant: "smallRegular", color: colors.negative[500], children: error })) : (_jsx(LakeText, { variant: "smallRegular", color: colors.gray[500], children: help !== null && help !== void 0 ? help : " " })), isNotNullish(info) && (_jsx(LakeText, { variant: "smallRegular", color: colors.shakespear[500], children: info })), isNotNullish(maxCharCount) && (_jsxs(_Fragment, { children: [_jsx(Fill, { minWidth: 4 }), _jsxs(LakeText, { variant: "smallRegular", color: charCount > maxCharCount ? colors.negative[500] : colors.gray[400], style: styles.descriptionLimitation, children: [charCount, " / ", maxCharCount] })] }))] }))] }));
174
174
  };
@@ -5,6 +5,7 @@ type Props = {
5
5
  color?: string;
6
6
  delay?: number;
7
7
  style?: StyleProp<ViewStyle>;
8
+ ariaLabel?: string;
8
9
  };
9
- export declare const LoadingView: ({ ref, color, delay, style, }: Props) => import("react").JSX.Element;
10
+ export declare const LoadingView: ({ ref, color, delay, style, ariaLabel, }: Props) => import("react").JSX.Element;
10
11
  export {};
@@ -20,4 +20,4 @@ const styles = StyleSheet.create({
20
20
  },
21
21
  });
22
22
  const isDev = process.env.NODE_ENV === "development";
23
- export const LoadingView = ({ ref, color = colors.gray[400], delay = isDev ? 0 : 1000, style, }) => (_jsx(View, { ref: ref, style: [styles.base, style], children: _jsx(ActivityIndicator, { size: "small", color: color, style: [styles.indicator, delay > 0 && { animationDelay: delay.toString() + "ms" }] }) }));
23
+ export const LoadingView = ({ ref, color = colors.gray[400], delay = isDev ? 0 : 1000, style, ariaLabel, }) => (_jsx(View, { ref: ref, style: [styles.base, style], children: _jsx(ActivityIndicator, { "aria-label": ariaLabel, "aria-hidden": true, size: "small", color: color, style: [styles.indicator, delay > 0 && { animationDelay: delay.toString() + "ms" }] }) }));
@@ -109,7 +109,7 @@ export const Popover = memo(({ children, id, label, placement, verticalPlacement
109
109
  if (mode === "BottomPanel") {
110
110
  return (_jsx(BottomPanel, { visible: visible, onPressClose: onDismiss, returnFocus: false, children: typeof children === "function" ? children({ mode: "panel" }) : children }));
111
111
  }
112
- return (_jsxs(Portal, { container: rootElement, children: [visible && underlay ? (_jsx(Pressable, { ref: underlayRef, style: styles.underlay, onPress: onPressUnderlay, "aria-label": "Close" })) : null, _jsx(TransitionView, { style: styles.container, ...animation, children: position.isSome() ? (_jsx(View, { style: position.get().rootStyle, children: _jsx(View, { style: [
112
+ return (_jsxs(Portal, { container: rootElement, children: [visible && underlay ? (_jsx(Pressable, { ref: underlayRef, style: styles.underlay, onPress: onPressUnderlay, tabIndex: -1, "aria-hidden": true })) : null, _jsx(TransitionView, { style: styles.container, ...animation, children: position.isSome() ? (_jsx(View, { style: position.get().rootStyle, children: _jsx(View, { style: [
113
113
  styles.popoverContainer,
114
114
  position.get().style,
115
115
  {
@@ -39,10 +39,10 @@ const styles = StyleSheet.create({
39
39
  },
40
40
  });
41
41
  export const QuickActions = ({ actions }) => {
42
- return (_jsx(View, { style: styles.container, children: actions.map((action, index) => { var _a, _b; return (_jsx(LakeTooltip, { content: action.tooltipText, placement: "right", containerStyle: styles.actionContainer, disabled: action.tooltipDisabled === true || isNullishOrEmpty(action.tooltipText), children: _jsxs(Pressable, { onPress: action.onPress, style: [styles.action, action.disabled === true && styles.disabled], disabled: action.isLoading === true || action.disabled === true, children: [_jsx(View, { style: [
42
+ return (_jsx(View, { style: styles.container, children: actions.map((action, index) => { var _a, _b; return (_jsx(LakeTooltip, { content: action.tooltipText, placement: "right", containerStyle: styles.actionContainer, disabled: action.tooltipDisabled === true || isNullishOrEmpty(action.tooltipText), children: _jsxs(Pressable, { onPress: action.onPress, style: [styles.action, action.disabled === true && styles.disabled], disabled: action.isLoading === true || action.disabled === true, "aria-busy": action.isLoading === true, children: [_jsx(View, { style: [
43
43
  styles.icon,
44
44
  action.backgroundColor != null
45
45
  ? { backgroundColor: action.backgroundColor, borderColor: action.backgroundColor }
46
46
  : null,
47
- ], children: action.isLoading === true ? (_jsx(ActivityIndicator, { color: (_a = action.color) !== null && _a !== void 0 ? _a : colors.gray[300], size: 16 })) : (_jsx(Icon, { name: action.icon, size: 16, color: (_b = action.color) !== null && _b !== void 0 ? _b : colors.gray[300] })) }), _jsx(Space, { height: 8 }), _jsx(LakeText, { variant: "smallRegular", align: "center", style: styles.label, children: action.label })] }, index) }, index)); }) }));
47
+ ], children: action.isLoading === true ? (_jsx(ActivityIndicator, { "aria-hidden": true, color: (_a = action.color) !== null && _a !== void 0 ? _a : colors.gray[300], size: 16 })) : (_jsx(Icon, { name: action.icon, size: 16, color: (_b = action.color) !== null && _b !== void 0 ? _b : colors.gray[300] })) }), _jsx(Space, { height: 8 }), _jsx(LakeText, { variant: "smallRegular", align: "center", style: styles.label, children: action.label })] }, index) }, index)); }) }));
48
48
  };