@butternutbox/pawprint-native 2.0.1 → 2.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": "@butternutbox/pawprint-native",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "description": "ButternutBox Pawprint Design System - React Native Components",
6
6
  "main": "./dist/index.cjs",
@@ -54,10 +54,10 @@
54
54
  }
55
55
  },
56
56
  "devDependencies": {
57
- "@butternutbox/pawprint-icons": "workspace:*",
58
- "@butternutbox/pawprint-illustrations": "workspace:*",
59
- "@repo/eslint-config": "workspace:*",
60
- "@repo/typescript-config": "workspace:*",
57
+ "@butternutbox/pawprint-icons": "1.8.1",
58
+ "@butternutbox/pawprint-illustrations": "3.1.1",
59
+ "@repo/eslint-config": "0.0.0",
60
+ "@repo/typescript-config": "0.0.0",
61
61
  "@testing-library/dom": "^10.4.1",
62
62
  "@testing-library/jest-dom": "^6.6.3",
63
63
  "@testing-library/react": "^16.3.0",
@@ -80,4 +80,4 @@
80
80
  "publishConfig": {
81
81
  "access": "public"
82
82
  }
83
- }
83
+ }
@@ -151,6 +151,19 @@ export const WithOptionalText = () => (
151
151
  </StoryWrapper>
152
152
  )
153
153
 
154
+ export const NotSearchable = () => (
155
+ <StoryWrapper>
156
+ <Section title="Pick from the list only">
157
+ <SelectField
158
+ label="Country"
159
+ placeholder="Select a country"
160
+ searchable={false}
161
+ options={COUNTRIES}
162
+ />
163
+ </Section>
164
+ </StoryWrapper>
165
+ )
166
+
154
167
  export const Controlled = () => {
155
168
  const [country, setCountry] = useState<string | null>("ca")
156
169
 
@@ -293,6 +293,47 @@ describe("SelectField", () => {
293
293
  })
294
294
  })
295
295
 
296
+ describe("when not searchable", () => {
297
+ it("can't be typed into", () => {
298
+ const input = renderField({ searchable: false })
299
+
300
+ expect(input).toBeDisabled()
301
+ })
302
+
303
+ it("stays closed until the field is pressed", () => {
304
+ renderField({ searchable: false })
305
+
306
+ expect(screen.queryByText("United Kingdom")).not.toBeInTheDocument()
307
+ })
308
+
309
+ it("shows every option when the field is pressed", () => {
310
+ const input = renderField({ searchable: false })
311
+ fireEvent.click(input)
312
+
313
+ COUNTRIES.forEach((option) => {
314
+ expect(screen.getByText(option.label)).toBeInTheDocument()
315
+ })
316
+ })
317
+
318
+ it("selects the pressed option and closes", () => {
319
+ const onValueChange = vi.fn()
320
+ const input = renderField({ searchable: false, onValueChange })
321
+ fireEvent.click(input)
322
+ fireEvent.click(screen.getByText("Canada"))
323
+
324
+ expect(onValueChange).toHaveBeenCalledWith("ca")
325
+ expect(input).toHaveValue("Canada")
326
+ expect(screen.queryByText("Australia")).not.toBeInTheDocument()
327
+ })
328
+
329
+ it("does not open when disabled", () => {
330
+ const input = renderField({ searchable: false, disabled: true })
331
+ fireEvent.click(input)
332
+
333
+ expect(screen.queryByText("United Kingdom")).not.toBeInTheDocument()
334
+ })
335
+ })
336
+
296
337
  describe("controlled mode", () => {
297
338
  it("shows the label for the controlled value", () => {
298
339
  const input = renderField({ value: "au" })
@@ -2,6 +2,7 @@ import React from "react"
2
2
  import {
3
3
  Keyboard,
4
4
  Pressable,
5
+ StyleSheet,
5
6
  TextInput,
6
7
  useWindowDimensions,
7
8
  View,
@@ -40,6 +41,7 @@ type SelectFieldOwnProps = {
40
41
  optionalText?: string
41
42
  placeholder?: string
42
43
  leadingIcon?: React.ReactNode
44
+ searchable?: boolean
43
45
  noResultsText?: string
44
46
  errorText?: string
45
47
  onSearchQuery?: SelectOptionsResolver
@@ -73,6 +75,7 @@ export const SelectField = React.forwardRef<View, SelectFieldProps>(
73
75
  optionalText,
74
76
  placeholder,
75
77
  leadingIcon,
78
+ searchable = true,
76
79
  noResultsText = "No results found",
77
80
  errorText = "Something went wrong",
78
81
  onSearchQuery,
@@ -244,7 +247,7 @@ export const SelectField = React.forwardRef<View, SelectFieldProps>(
244
247
  setInputText("")
245
248
  setFilterQuery("")
246
249
  commitValue(null)
247
- inputRef.current?.focus()
250
+ if (searchable) inputRef.current?.focus()
248
251
  }
249
252
 
250
253
  const fieldState: InputState = error ? "error" : state
@@ -272,24 +275,34 @@ export const SelectField = React.forwardRef<View, SelectFieldProps>(
272
275
  if (!isOpen || !anchorRect) return null
273
276
 
274
277
  return (
275
- <SelectFieldDropdown
276
- anchor={anchorRect}
277
- placement={placement.direction}
278
- maxHeight={placement.maxHeight}
279
- screenHeight={windowHeight}
280
- accessibilityLiveRegion="polite"
281
- >
282
- <SelectFieldList
283
- state={optionsState}
284
- selectedValue={selectedValue}
285
- onSelect={onOptionPress}
286
- noResultsText={noResultsText}
287
- errorText={errorText}
288
- searchHintText={searchHintText}
289
- />
290
- </SelectFieldDropdown>
278
+ <>
279
+ {!searchable && (
280
+ <Pressable
281
+ style={StyleSheet.absoluteFill}
282
+ onPress={() => setIsFocused(false)}
283
+ accessible={false}
284
+ />
285
+ )}
286
+ <SelectFieldDropdown
287
+ anchor={anchorRect}
288
+ placement={placement.direction}
289
+ maxHeight={placement.maxHeight}
290
+ screenHeight={windowHeight}
291
+ accessibilityLiveRegion="polite"
292
+ >
293
+ <SelectFieldList
294
+ state={optionsState}
295
+ selectedValue={selectedValue}
296
+ onSelect={onOptionPress}
297
+ noResultsText={noResultsText}
298
+ errorText={errorText}
299
+ searchHintText={searchHintText}
300
+ />
301
+ </SelectFieldDropdown>
302
+ </>
291
303
  )
292
304
  }, [
305
+ searchable,
293
306
  isOpen,
294
307
  anchorRect,
295
308
  placement,
@@ -313,11 +326,14 @@ export const SelectField = React.forwardRef<View, SelectFieldProps>(
313
326
  <InputField
314
327
  ref={inputRef}
315
328
  value={inputText}
316
- onChangeText={handleChangeText}
317
- onFocus={handleFocus}
318
- onBlur={handleBlur}
329
+ onChangeText={searchable ? handleChangeText : undefined}
330
+ onFocus={searchable ? handleFocus : undefined}
331
+ onBlur={searchable ? handleBlur : undefined}
332
+ onPress={
333
+ !searchable && !disabled ? () => setIsFocused(true) : undefined
334
+ }
319
335
  placeholder={placeholder}
320
- editable={!disabled}
336
+ editable={searchable && !disabled}
321
337
  state={fieldState}
322
338
  hideStateIcons={Boolean(clearAction)}
323
339
  leadingIcon={leadingIcon}