@butternutbox/pawprint-native 0.22.0 → 0.23.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.
@@ -7,12 +7,12 @@
7
7
  CJS Build start
8
8
  ESM Build start
9
9
  DTS Build start
10
- ESM dist/index.js 518.12 KB
11
- ESM dist/index.js.map 1.06 MB
12
- ESM ⚡️ Build success in 7711ms
13
- CJS dist/index.cjs 548.33 KB
14
- CJS dist/index.cjs.map 1.06 MB
15
- CJS ⚡️ Build success in 7715ms
16
- DTS ⚡️ Build success in 22565ms
17
- DTS dist/index.d.cts 102.08 KB
18
- DTS dist/index.d.ts 102.08 KB
10
+ CJS dist/index.cjs 551.83 KB
11
+ CJS dist/index.cjs.map 1.07 MB
12
+ CJS ⚡️ Build success in 7688ms
13
+ ESM dist/index.js 521.42 KB
14
+ ESM dist/index.js.map 1.07 MB
15
+ ESM ⚡️ Build success in 7691ms
16
+ DTS ⚡️ Build success in 21136ms
17
+ DTS dist/index.d.cts 102.54 KB
18
+ DTS dist/index.d.ts 102.54 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @butternutbox/pawprint-native
2
2
 
3
+ ## 0.23.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a970fa5: SelectField: add async search. Pass `onSearchQuery` alongside `searchable` to run a debounced query as the user types, with the returned items replacing the list. The component renders a loading spinner while the query runs, `errorText` if it rejects, and `noResultsText` if it resolves empty; any `children` act as the default list before the user types. New props: `onSearchQuery`, `debounceMs` (default 300), `errorText`. Exports a `SelectFieldSearchResult` type for the resolver's return shape.
8
+ - 1ba9b0f: update checkbox, badge and buttons to allow for multiple lines
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [1ba9b0f]
13
+ - @butternutbox/pawprint-tokens@0.5.0
14
+
3
15
  ## 0.22.0
4
16
 
5
17
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -1201,7 +1201,7 @@ var IconWrapper = styled51__default.default(reactNative.View)({
1201
1201
  });
1202
1202
  var StyledButton = styled51__default.default(reactNative.Pressable)(
1203
1203
  ({
1204
- buttonHeight,
1204
+ buttonMinHeight,
1205
1205
  buttonMinWidth,
1206
1206
  buttonPaddingHorizontal,
1207
1207
  buttonPaddingVertical,
@@ -1217,7 +1217,7 @@ var StyledButton = styled51__default.default(reactNative.Pressable)(
1217
1217
  alignItems: "center",
1218
1218
  justifyContent: "center",
1219
1219
  position: "relative",
1220
- height: buttonHeight,
1220
+ minHeight: buttonMinHeight,
1221
1221
  minWidth: buttonMinWidth,
1222
1222
  paddingHorizontal: buttonPaddingHorizontal,
1223
1223
  paddingVertical: buttonPaddingVertical,
@@ -1229,7 +1229,7 @@ var StyledButton = styled51__default.default(reactNative.Pressable)(
1229
1229
  );
1230
1230
  var StyledTextWrapper = styled51__default.default(reactNative.View)(({ textOpacity }) => ({
1231
1231
  opacity: textOpacity,
1232
- flexShrink: 0
1232
+ flex: 1
1233
1233
  }));
1234
1234
  var StyledSpinnerWrapper = styled51__default.default(reactNative.View)({
1235
1235
  position: "absolute",
@@ -1305,7 +1305,7 @@ var Button = React66__default.default.forwardRef(
1305
1305
  accessibilityState: { disabled: isDisabled, busy: loading },
1306
1306
  onPressIn: () => setPressed(true),
1307
1307
  onPressOut: () => setPressed(false),
1308
- buttonHeight: parseTokenValue7(sizeTokens.height),
1308
+ buttonMinHeight: parseTokenValue7(sizeTokens.minHeight),
1309
1309
  buttonMinWidth: parseTokenValue7(sizeTokens.minWidth),
1310
1310
  buttonPaddingHorizontal: parseTokenValue7(
1311
1311
  spacingTokens.horizontalPadding
@@ -1332,6 +1332,7 @@ var Button = React66__default.default.forwardRef(
1332
1332
  letterSpacing: typography.letterSpacing
1333
1333
  },
1334
1334
  color: variantStyles.textColor,
1335
+ align: "center",
1335
1336
  children
1336
1337
  }
1337
1338
  ) }),
@@ -1467,7 +1468,7 @@ var IconButton = React66__default.default.forwardRef(
1467
1468
  const isDisabled = disabled || loading;
1468
1469
  const buttons = theme2.tokens.components.buttons;
1469
1470
  const sizeTokens = buttons.size[size];
1470
- const dimension = parseTokenValue10(sizeTokens.height);
1471
+ const dimension = parseTokenValue10(sizeTokens.minHeight);
1471
1472
  const iconSizing = theme2.tokens.components.icons.sizing.icons.core;
1472
1473
  const iconDimension = parseTokenValue10(iconSizing[sizeToIconSizeToken[size]]);
1473
1474
  const [pressed, setPressed] = React66__default.default.useState(false);
@@ -4899,6 +4900,7 @@ Switch.displayName = "Switch";
4899
4900
  var parseTokenValue18 = (value) => parseFloat(value);
4900
4901
  var StyledTag = styled51__default.default(reactNative.View)(({ theme: theme2, tagVariant, tagSize }) => {
4901
4902
  const { sizing, spacing, colour, badge } = theme2.tokens.components.tags;
4903
+ const { spacing: semanticSpacing } = theme2.tokens.semantics.dimensions;
4902
4904
  const backgroundColorMap = {
4903
4905
  primary: colour.primary.background,
4904
4906
  secondary: colour.primary.secondary,
@@ -4908,13 +4910,21 @@ var StyledTag = styled51__default.default(reactNative.View)(({ theme: theme2, ta
4908
4910
  warning: colour.primary.warning,
4909
4911
  error: colour.primary.error
4910
4912
  };
4913
+ const verticalPaddingMap = {
4914
+ small: semanticSpacing["2xs"],
4915
+ medium: semanticSpacing["3xs"],
4916
+ large: semanticSpacing["2xs"]
4917
+ };
4911
4918
  return {
4912
4919
  flexDirection: "row",
4913
4920
  alignItems: "center",
4914
4921
  justifyContent: "center",
4915
- height: parseTokenValue18(sizing[tagSize].height),
4922
+ minHeight: parseTokenValue18(sizing[tagSize].minHeight),
4916
4923
  minWidth: parseTokenValue18(sizing[tagSize].minWidth),
4917
- paddingHorizontal: parseTokenValue18(spacing.horizontalPadding),
4924
+ paddingLeft: parseTokenValue18(spacing.horizontalPadding) * 2,
4925
+ paddingRight: parseTokenValue18(spacing.horizontalPadding) * 2,
4926
+ paddingTop: parseTokenValue18(verticalPaddingMap[tagSize]),
4927
+ paddingBottom: parseTokenValue18(verticalPaddingMap[tagSize]),
4918
4928
  gap: parseTokenValue18(spacing[tagSize].gap),
4919
4929
  borderRadius: parseTokenValue18(badge.borderRadius.default),
4920
4930
  backgroundColor: backgroundColorMap[tagVariant]
@@ -6363,7 +6373,7 @@ var DrawerBody = React66__default.default.forwardRef(
6363
6373
  const horizontalPadding = parseTokenValue27(content.slot.horizontalPadding);
6364
6374
  const topPadding = parseTokenValue27(content.slot.verticalPadding);
6365
6375
  const bodyMaxHeight = providedMaxHeight != null ? providedMaxHeight : windowHeight - 300;
6366
- const paddingRight = headerContext === null ? parseTokenValue27(spacing.close.right.md) + parseTokenValue27(buttons.size.sm.height) : horizontalPadding;
6376
+ const paddingRight = headerContext === null ? parseTokenValue27(spacing.close.right.md) + parseTokenValue27(buttons.size.sm.minHeight) : horizontalPadding;
6367
6377
  const bodyPaddingBottom = !footerContext ? Math.max(
6368
6378
  parseTokenValue27(theme2.tokens.semantics.dimensions.spacing["2xl"]),
6369
6379
  insets.bottom
@@ -6733,7 +6743,7 @@ var StyledRootPressable = styled51__default.default(reactNative.Pressable)(
6733
6743
  alignItems: rootFlexAlign,
6734
6744
  gap: rootGap,
6735
6745
  opacity: rootOpacity
6736
- }, rootPaddingVertical !== void 0 ? { paddingVertical: rootPaddingVertical } : {}), rootPaddingHorizontal !== void 0 ? { paddingHorizontal: rootPaddingHorizontal } : {}), rootMaxWidth !== void 0 ? rootFitContent ? { maxWidth: rootMaxWidth, alignSelf: "flex-start" } : { maxWidth: rootMaxWidth, width: "100%" } : { width: "100%" }), rootBgColor ? { backgroundColor: rootBgColor } : {}), rootBorderWidth !== void 0 ? { borderWidth: rootBorderWidth, borderColor: rootBorderColor } : {}), rootBorderRadius !== void 0 ? { borderRadius: rootBorderRadius } : {})
6746
+ }, rootPaddingVertical !== void 0 ? { paddingVertical: rootPaddingVertical } : {}), rootPaddingHorizontal !== void 0 ? { paddingHorizontal: rootPaddingHorizontal } : {}), rootMaxWidth !== void 0 ? rootFitContent ? { maxWidth: rootMaxWidth, alignSelf: "flex-start" } : { maxWidth: rootMaxWidth, width: "100%" } : {}), rootBgColor ? { backgroundColor: rootBgColor } : {}), rootBorderWidth !== void 0 ? { borderWidth: rootBorderWidth, borderColor: rootBorderColor } : {}), rootBorderRadius !== void 0 ? { borderRadius: rootBorderRadius } : {})
6737
6747
  );
6738
6748
  var StyledControl = styled51__default.default(reactNative.View)(
6739
6749
  ({
@@ -6754,12 +6764,12 @@ var StyledControl = styled51__default.default(reactNative.View)(
6754
6764
  justifyContent: "center"
6755
6765
  })
6756
6766
  );
6757
- var StyledContent2 = styled51__default.default(reactNative.View)(({ contentGap }) => ({
6767
+ var StyledContent2 = styled51__default.default(reactNative.View)(({ contentGap, contentFlex, contentFitContent }) => __spreadValues({
6758
6768
  flexDirection: "column",
6759
6769
  gap: contentGap,
6760
- flex: 1,
6770
+ flex: contentFlex,
6761
6771
  minWidth: 0
6762
- }));
6772
+ }, contentFitContent ? { maxWidth: "85%" } : {}));
6763
6773
  var StyledIllustration = styled51__default.default(reactNative.View)(({ illustrationSize }) => ({
6764
6774
  flexShrink: 0,
6765
6775
  width: illustrationSize,
@@ -6846,6 +6856,8 @@ var Checkbox = React66__default.default.forwardRef(
6846
6856
  StyledContent2,
6847
6857
  {
6848
6858
  contentGap: parseTokenValue31(checkbox.spacing.content.gap),
6859
+ contentFlex: isTile && fitContent ? 0 : 1,
6860
+ contentFitContent: isTile && fitContent,
6849
6861
  children: [
6850
6862
  label && /* @__PURE__ */ jsxRuntime.jsx(
6851
6863
  Typography,
@@ -9010,7 +9022,7 @@ var SelectFieldItem = React66__default.default.forwardRef(
9010
9022
  );
9011
9023
  SelectFieldItem.displayName = "SelectField.Item";
9012
9024
  var parseTokenValue48 = (value) => parseFloat(value);
9013
- var StyledNoResults = styled51__default.default(reactNative.View)(({ theme: theme2 }) => {
9025
+ var StyledStatusRow = styled51__default.default(reactNative.View)(({ theme: theme2 }) => {
9014
9026
  const { dropdown } = theme2.tokens.components.dropdownList;
9015
9027
  return {
9016
9028
  paddingVertical: parseTokenValue48(dropdown.listItem.spacing.verticalPadding),
@@ -9043,7 +9055,10 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9043
9055
  disabled,
9044
9056
  searchable = false,
9045
9057
  searchPlaceholder,
9046
- noResultsText = "No results found"
9058
+ noResultsText = "No results found",
9059
+ onSearchQuery,
9060
+ debounceMs = 300,
9061
+ errorText = "Something went wrong"
9047
9062
  } = _b, rest = __objRest(_b, [
9048
9063
  "label",
9049
9064
  "placeholder",
@@ -9059,7 +9074,10 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9059
9074
  "disabled",
9060
9075
  "searchable",
9061
9076
  "searchPlaceholder",
9062
- "noResultsText"
9077
+ "noResultsText",
9078
+ "onSearchQuery",
9079
+ "debounceMs",
9080
+ "errorText"
9063
9081
  ]);
9064
9082
  const [isOpen, setIsOpen] = React66__default.default.useState(false);
9065
9083
  const [showContent, setShowContent] = React66__default.default.useState(false);
@@ -9069,6 +9087,44 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9069
9087
  const [searchQuery, setSearchQuery] = React66__default.default.useState("");
9070
9088
  const [clearKey, setClearKey] = React66__default.default.useState(0);
9071
9089
  const searchInputRef = React66__default.default.useRef(null);
9090
+ const isQueryMode = searchable && typeof onSearchQuery === "function";
9091
+ const [searchResults, setSearchResults] = React66__default.default.useState([]);
9092
+ const [isSearching, setIsSearching] = React66__default.default.useState(false);
9093
+ const [searchFailed, setSearchFailed] = React66__default.default.useState(false);
9094
+ const searchRequestIdRef = React66__default.default.useRef(0);
9095
+ const onSearchQueryRef = React66__default.default.useRef(onSearchQuery);
9096
+ React66__default.default.useEffect(() => {
9097
+ onSearchQueryRef.current = onSearchQuery;
9098
+ });
9099
+ React66__default.default.useEffect(() => {
9100
+ if (!isQueryMode) return;
9101
+ if (searchQuery.length === 0) {
9102
+ searchRequestIdRef.current += 1;
9103
+ setSearchResults([]);
9104
+ setIsSearching(false);
9105
+ setSearchFailed(false);
9106
+ return;
9107
+ }
9108
+ const requestId = searchRequestIdRef.current + 1;
9109
+ searchRequestIdRef.current = requestId;
9110
+ setIsSearching(true);
9111
+ setSearchFailed(false);
9112
+ const debounceTimer = setTimeout(() => {
9113
+ const runQuery = onSearchQueryRef.current;
9114
+ if (!runQuery) return;
9115
+ Promise.resolve(runQuery(searchQuery)).then((items) => {
9116
+ if (searchRequestIdRef.current !== requestId) return;
9117
+ setSearchResults(items);
9118
+ setIsSearching(false);
9119
+ }).catch(() => {
9120
+ if (searchRequestIdRef.current !== requestId) return;
9121
+ setSearchResults([]);
9122
+ setSearchFailed(true);
9123
+ setIsSearching(false);
9124
+ });
9125
+ }, debounceMs);
9126
+ return () => clearTimeout(debounceTimer);
9127
+ }, [searchQuery, isQueryMode, debounceMs]);
9072
9128
  React66__default.default.useEffect(() => {
9073
9129
  if (!isOpen) {
9074
9130
  setShowContent(false);
@@ -9101,7 +9157,7 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9101
9157
  clearTimeout(hardwareKeyboardTimer);
9102
9158
  keyboardSub.remove();
9103
9159
  };
9104
- }, [isOpen, searchable]);
9160
+ }, [isOpen, searchable, isSearching, searchQuery]);
9105
9161
  const isCompound = React66__default.default.Children.toArray(children).some(
9106
9162
  (child) => React66__default.default.isValidElement(child) && child.type === SelectFieldContent
9107
9163
  );
@@ -9119,7 +9175,7 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9119
9175
  };
9120
9176
  const currentValue = value !== void 0 ? value : internalValue;
9121
9177
  const allItems = React66__default.default.Children.toArray(children);
9122
- const filteredItems = searchable ? allItems.filter((child) => {
9178
+ const localFilteredItems = searchable && !isQueryMode ? allItems.filter((child) => {
9123
9179
  var _a2;
9124
9180
  if (!searchQuery) return true;
9125
9181
  if (React66__default.default.isValidElement(child) && child.type === SelectFieldItem) {
@@ -9130,7 +9186,21 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9130
9186
  }
9131
9187
  return true;
9132
9188
  }) : allItems;
9133
- const hasNoResults = searchable && searchQuery.length > 0 && filteredItems.length === 0;
9189
+ const isQueryActive = isQueryMode && searchQuery.length > 0;
9190
+ const queryResultItems = searchResults.map((result) => /* @__PURE__ */ jsxRuntime.jsx(
9191
+ SelectFieldItem,
9192
+ {
9193
+ value: result.value,
9194
+ leadingIcon: result.leadingIcon,
9195
+ hintText: result.hintText,
9196
+ disabled: result.disabled,
9197
+ children: result.label
9198
+ },
9199
+ String(result.value)
9200
+ ));
9201
+ const itemsToRender = isQueryActive ? queryResultItems : localFilteredItems;
9202
+ const hasNoResults = isQueryMode ? isQueryActive && !isSearching && !searchFailed && searchResults.length === 0 : searchable && searchQuery.length > 0 && localFilteredItems.length === 0;
9203
+ const hasContentToShow = isSearching || searchFailed || hasNoResults || itemsToRender.length > 0;
9134
9204
  const searchActionIcon = (() => {
9135
9205
  if (!searchable) return void 0;
9136
9206
  const showClear = isOpen && searchQuery.length > 0 || !isOpen && Boolean(currentValue);
@@ -9189,8 +9259,8 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9189
9259
  description && /* @__PURE__ */ jsxRuntime.jsx(InputDescription, { state, children: description }),
9190
9260
  error && state === "error" && /* @__PURE__ */ jsxRuntime.jsx(InputError, { children: error })
9191
9261
  ] })),
9192
- showContent && /* @__PURE__ */ jsxRuntime.jsxs(SelectFieldContent, { children: [
9193
- filteredItems.map((child) => {
9262
+ showContent && hasContentToShow && /* @__PURE__ */ jsxRuntime.jsx(SelectFieldContent, { children: isSearching ? /* @__PURE__ */ jsxRuntime.jsx(StyledStatusRow, { children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: "sm" }) }) : searchFailed ? /* @__PURE__ */ jsxRuntime.jsx(StyledStatusRow, { children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { size: "sm", children: errorText }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9263
+ itemsToRender.map((child) => {
9194
9264
  if (React66__default.default.isValidElement(child) && child.type === SelectFieldItem) {
9195
9265
  const selectedValue = currentValue && typeof currentValue === "object" && "value" in currentValue ? currentValue.value : currentValue;
9196
9266
  const childProps = child.props;
@@ -9203,8 +9273,8 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9203
9273
  }
9204
9274
  return child;
9205
9275
  }),
9206
- hasNoResults && /* @__PURE__ */ jsxRuntime.jsx(StyledNoResults, { children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { size: "sm", children: noResultsText }) })
9207
- ] })
9276
+ hasNoResults && /* @__PURE__ */ jsxRuntime.jsx(StyledStatusRow, { children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { size: "sm", children: noResultsText }) })
9277
+ ] }) })
9208
9278
  ]
9209
9279
  },
9210
9280
  clearKey
@@ -9569,7 +9639,7 @@ var Slider = React66__default.default.forwardRef(
9569
9639
  const isControlled = controlledValue !== void 0;
9570
9640
  const [internalValue, setInternalValue] = React66__default.default.useState(defaultValue);
9571
9641
  const currentValue = isControlled ? controlledValue : internalValue;
9572
- const thumbSize = parseTokenValue49(buttons.size.md.height);
9642
+ const thumbSize = parseTokenValue49(buttons.size.md.minHeight);
9573
9643
  const trackHeight = parseTokenValue49(slider.sizing.track.height);
9574
9644
  const isWeb = reactNative.Platform.OS === "web";
9575
9645
  const [trackLayoutWidth, setTrackLayoutWidth] = React66.useState(0);