@butternutbox/pawprint-native 0.21.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
- CJS dist/index.cjs 548.39 KB
11
- CJS dist/index.cjs.map 1.06 MB
12
- CJS ⚡️ Build success in 8017ms
13
- ESM dist/index.js 518.18 KB
14
- ESM dist/index.js.map 1.06 MB
15
- ESM ⚡️ Build success in 8017ms
16
- DTS ⚡️ Build success in 22080ms
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,23 @@
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
+
15
+ ## 0.22.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 19b56fb: Allow checkbox content to drop to multiple lines
20
+
3
21
  ## 0.21.0
4
22
 
5
23
  ### 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
@@ -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, contentFlex }) => ({
6767
+ var StyledContent2 = styled51__default.default(reactNative.View)(({ contentGap, contentFlex, contentFitContent }) => __spreadValues({
6758
6768
  flexDirection: "column",
6759
6769
  gap: contentGap,
6760
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,
@@ -6847,6 +6857,7 @@ var Checkbox = React66__default.default.forwardRef(
6847
6857
  {
6848
6858
  contentGap: parseTokenValue31(checkbox.spacing.content.gap),
6849
6859
  contentFlex: isTile && fitContent ? 0 : 1,
6860
+ contentFitContent: isTile && fitContent,
6850
6861
  children: [
6851
6862
  label && /* @__PURE__ */ jsxRuntime.jsx(
6852
6863
  Typography,
@@ -9011,7 +9022,7 @@ var SelectFieldItem = React66__default.default.forwardRef(
9011
9022
  );
9012
9023
  SelectFieldItem.displayName = "SelectField.Item";
9013
9024
  var parseTokenValue48 = (value) => parseFloat(value);
9014
- var StyledNoResults = styled51__default.default(reactNative.View)(({ theme: theme2 }) => {
9025
+ var StyledStatusRow = styled51__default.default(reactNative.View)(({ theme: theme2 }) => {
9015
9026
  const { dropdown } = theme2.tokens.components.dropdownList;
9016
9027
  return {
9017
9028
  paddingVertical: parseTokenValue48(dropdown.listItem.spacing.verticalPadding),
@@ -9044,7 +9055,10 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9044
9055
  disabled,
9045
9056
  searchable = false,
9046
9057
  searchPlaceholder,
9047
- noResultsText = "No results found"
9058
+ noResultsText = "No results found",
9059
+ onSearchQuery,
9060
+ debounceMs = 300,
9061
+ errorText = "Something went wrong"
9048
9062
  } = _b, rest = __objRest(_b, [
9049
9063
  "label",
9050
9064
  "placeholder",
@@ -9060,7 +9074,10 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9060
9074
  "disabled",
9061
9075
  "searchable",
9062
9076
  "searchPlaceholder",
9063
- "noResultsText"
9077
+ "noResultsText",
9078
+ "onSearchQuery",
9079
+ "debounceMs",
9080
+ "errorText"
9064
9081
  ]);
9065
9082
  const [isOpen, setIsOpen] = React66__default.default.useState(false);
9066
9083
  const [showContent, setShowContent] = React66__default.default.useState(false);
@@ -9070,6 +9087,44 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9070
9087
  const [searchQuery, setSearchQuery] = React66__default.default.useState("");
9071
9088
  const [clearKey, setClearKey] = React66__default.default.useState(0);
9072
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]);
9073
9128
  React66__default.default.useEffect(() => {
9074
9129
  if (!isOpen) {
9075
9130
  setShowContent(false);
@@ -9102,7 +9157,7 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9102
9157
  clearTimeout(hardwareKeyboardTimer);
9103
9158
  keyboardSub.remove();
9104
9159
  };
9105
- }, [isOpen, searchable]);
9160
+ }, [isOpen, searchable, isSearching, searchQuery]);
9106
9161
  const isCompound = React66__default.default.Children.toArray(children).some(
9107
9162
  (child) => React66__default.default.isValidElement(child) && child.type === SelectFieldContent
9108
9163
  );
@@ -9120,7 +9175,7 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9120
9175
  };
9121
9176
  const currentValue = value !== void 0 ? value : internalValue;
9122
9177
  const allItems = React66__default.default.Children.toArray(children);
9123
- const filteredItems = searchable ? allItems.filter((child) => {
9178
+ const localFilteredItems = searchable && !isQueryMode ? allItems.filter((child) => {
9124
9179
  var _a2;
9125
9180
  if (!searchQuery) return true;
9126
9181
  if (React66__default.default.isValidElement(child) && child.type === SelectFieldItem) {
@@ -9131,7 +9186,21 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9131
9186
  }
9132
9187
  return true;
9133
9188
  }) : allItems;
9134
- 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;
9135
9204
  const searchActionIcon = (() => {
9136
9205
  if (!searchable) return void 0;
9137
9206
  const showClear = isOpen && searchQuery.length > 0 || !isOpen && Boolean(currentValue);
@@ -9190,8 +9259,8 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9190
9259
  description && /* @__PURE__ */ jsxRuntime.jsx(InputDescription, { state, children: description }),
9191
9260
  error && state === "error" && /* @__PURE__ */ jsxRuntime.jsx(InputError, { children: error })
9192
9261
  ] })),
9193
- showContent && /* @__PURE__ */ jsxRuntime.jsxs(SelectFieldContent, { children: [
9194
- 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) => {
9195
9264
  if (React66__default.default.isValidElement(child) && child.type === SelectFieldItem) {
9196
9265
  const selectedValue = currentValue && typeof currentValue === "object" && "value" in currentValue ? currentValue.value : currentValue;
9197
9266
  const childProps = child.props;
@@ -9204,8 +9273,8 @@ var SelectFieldRoot = React66__default.default.forwardRef(
9204
9273
  }
9205
9274
  return child;
9206
9275
  }),
9207
- hasNoResults && /* @__PURE__ */ jsxRuntime.jsx(StyledNoResults, { children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { size: "sm", children: noResultsText }) })
9208
- ] })
9276
+ hasNoResults && /* @__PURE__ */ jsxRuntime.jsx(StyledStatusRow, { children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { size: "sm", children: noResultsText }) })
9277
+ ] }) })
9209
9278
  ]
9210
9279
  },
9211
9280
  clearKey
@@ -9570,7 +9639,7 @@ var Slider = React66__default.default.forwardRef(
9570
9639
  const isControlled = controlledValue !== void 0;
9571
9640
  const [internalValue, setInternalValue] = React66__default.default.useState(defaultValue);
9572
9641
  const currentValue = isControlled ? controlledValue : internalValue;
9573
- const thumbSize = parseTokenValue49(buttons.size.md.height);
9642
+ const thumbSize = parseTokenValue49(buttons.size.md.minHeight);
9574
9643
  const trackHeight = parseTokenValue49(slider.sizing.track.height);
9575
9644
  const isWeb = reactNative.Platform.OS === "web";
9576
9645
  const [trackLayoutWidth, setTrackLayoutWidth] = React66.useState(0);