playbook_ui 14.9.0.pre.alpha.PLAY1731inputmasking4927 → 14.9.0.pre.alpha.PLAY16264952

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 295537aeafbc78050a5d91bbcc11dae4a986ec3468f594930ffed921bdc3bc63
4
- data.tar.gz: d5feffcd1534d771725178a1e80dc0697a5ce9c0104829028ad08b95866972b7
3
+ metadata.gz: '0184005721ad49d1f678e3ad01fa6adfb793a0586e1a65e29ab855e6f63cbabf'
4
+ data.tar.gz: 1855261d8f324f9453237a5fc652eeb4a40c634161303b36a8a790fda91c66fa
5
5
  SHA512:
6
- metadata.gz: 50a8f5d6f56239f75d3c907dcbfc33b32bbb346a2f79dac4ff9f9106a9846302d138f92e4f3391c945e712caedcaf2ccc5ffd788172f6e653afc533ddca29cf3
7
- data.tar.gz: 66fca33ed514fd9cae439d7cd86ce7d9e25a8139d0383528b742f3dd8588cdfe6bf53826a793167efc677092b2562e892f9087a37df93f8c1ec01ac742ffcd02
6
+ metadata.gz: 8ac8cbafd180697b59623d27113ef372ce4ff845d49abbb37186ec8fc590836dd02df38972ffde5bf903283c5ce1c8bcde8dff5ea63de9e39a434b082ef0e317
7
+ data.tar.gz: 427b0c57a4f291bae08d15085ad71bd8d015b7358057bb5cc84ee3c24ee6aab31d4b2e8b4ef58725b8840a95549ae769145d830d27ff95a288cdcd24ee83bbdd
@@ -1,9 +1,11 @@
1
1
  import React, { useEffect, useRef } from 'react'
2
+ import { FieldValues } from 'react-hook-form'
2
3
  import Body from '../pb_body/_body'
3
4
  import Icon from '../pb_icon/_icon'
4
5
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
6
  import classnames from 'classnames'
6
7
  import { globalProps, GlobalProps } from '../utilities/globalProps'
8
+ import { withReactHookForm, WithReactHookFormProps } from '../utilities/withReactHookForm'
7
9
 
8
10
  type CheckboxProps = {
9
11
  aria?: {[key: string]: string},
@@ -13,7 +15,7 @@ type CheckboxProps = {
13
15
  dark?: boolean,
14
16
  data?: {[key: string]: string},
15
17
  disabled?: boolean,
16
- error?: boolean,
18
+ error?: boolean | string,
17
19
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
18
20
  id?: string,
19
21
  indeterminate?: boolean,
@@ -24,27 +26,26 @@ type CheckboxProps = {
24
26
  value?: string,
25
27
  } & GlobalProps
26
28
 
27
- const Checkbox = (props: CheckboxProps): React.ReactElement => {
28
- const {
29
- aria = {},
30
- checked = false,
31
- children,
32
- className,
33
- dark = false,
34
- data = {},
35
- disabled = false,
36
- error = false,
37
- htmlOptions = {},
38
- id,
39
- indeterminate = false,
40
- name = '',
41
- onChange = () => { void 0 },
42
- tabIndex,
43
- text = '',
44
- value = '',
45
- } = props
46
-
47
- const checkRef = useRef(null)
29
+ const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(({
30
+ aria = {},
31
+ checked = false,
32
+ children,
33
+ className,
34
+ dark = false,
35
+ data = {},
36
+ disabled = false,
37
+ error = false,
38
+ htmlOptions = {},
39
+ id,
40
+ indeterminate = false,
41
+ name = '',
42
+ onChange = () => { void 0 },
43
+ tabIndex,
44
+ text = '',
45
+ value = '',
46
+ ...props
47
+ }, ref) => {
48
+ const checkRef = useRef<HTMLInputElement>(null)
48
49
  const ariaProps = buildAriaProps(aria)
49
50
  const dataProps = buildDataProps(data)
50
51
  const htmlProps = buildHtmlProps(htmlOptions)
@@ -68,11 +69,12 @@ const Checkbox = (props: CheckboxProps): React.ReactElement => {
68
69
  else
69
70
  return (
70
71
  <input
72
+ {...props}
71
73
  defaultChecked={checked}
72
74
  disabled={disabled}
73
75
  name={name}
74
76
  onChange={onChange}
75
- ref={checkRef}
77
+ ref={ref || checkRef}
76
78
  tabIndex={tabIndex}
77
79
  type="checkbox"
78
80
  value={value}
@@ -112,13 +114,18 @@ const Checkbox = (props: CheckboxProps): React.ReactElement => {
112
114
  <Body
113
115
  className="pb_checkbox_label"
114
116
  dark={dark}
115
- status={error ? 'negative' : null}
117
+ status={typeof error === 'string' ? 'negative' : null}
116
118
  variant={null}
117
119
  >
118
120
  {text}
119
121
  </Body>
120
122
  </label>
121
123
  )
122
- }
124
+ })
125
+
126
+ Checkbox.displayName = 'Checkbox'
127
+
128
+ export type CheckboxWithHookFormProps<T extends FieldValues = FieldValues> = CheckboxProps & WithReactHookFormProps<T>
123
129
 
124
- export default Checkbox
130
+ const CheckboxWithHookForm = withReactHookForm(Checkbox)
131
+ export default CheckboxWithHookForm
@@ -0,0 +1,138 @@
1
+ import React from "react"
2
+ import { useForm } from "react-hook-form"
3
+ import { Checkbox, Card, Body, Button } from "playbook-ui"
4
+
5
+ const CheckboxForm = () => {
6
+ const {
7
+ register,
8
+ handleSubmit,
9
+ formState: { errors },
10
+ watch,
11
+ } = useForm({
12
+ defaultValues: {
13
+ termsAccepted: false,
14
+ newsletter: false,
15
+ interests: [],
16
+ preferences: {
17
+ emailUpdates: false,
18
+ smsUpdates: false,
19
+ pushNotifications: false,
20
+ },
21
+ },
22
+ })
23
+
24
+ const onSubmit = (data) => {
25
+ console.log("Form submitted:", data)
26
+ }
27
+
28
+ const formValues = watch()
29
+
30
+ return (
31
+ <div>
32
+ <Card padding='md'>
33
+ <form onSubmit={handleSubmit(onSubmit)}>
34
+ <div>
35
+ <Body marginBottom='xs'
36
+ text='Terms and Conditions'
37
+ />
38
+ <Checkbox
39
+ error={errors.termsAccepted?.message}
40
+ name='termsAccepted'
41
+ register={register}
42
+ rules={{
43
+ required: "You must accept the terms and conditions",
44
+ }}
45
+ text='I accept the terms and conditions'
46
+ />
47
+ </div>
48
+ <div className='mt-4'>
49
+ <Body marginBottom='xs'
50
+ text='Newsletter Subscription'
51
+ />
52
+ <Checkbox
53
+ name='newsletter'
54
+ register={register}
55
+ text='Subscribe to our newsletter'
56
+ />
57
+ </div>
58
+ <div className='mt-4'>
59
+ <Body marginBottom='xs'
60
+ text='Your Interests'
61
+ />
62
+ <Checkbox
63
+ error={errors.interests?.message}
64
+ name='interests'
65
+ register={register}
66
+ rules={{
67
+ validate: (value) => {
68
+ const selectedInterests = Object.values(value).filter(Boolean)
69
+ return (
70
+ selectedInterests.length >= 1 ||
71
+ "Please select at least one interest"
72
+ )
73
+ },
74
+ }}
75
+ text='Technology'
76
+ value='technology'
77
+ />
78
+ <Checkbox
79
+ name='interests'
80
+ register={register}
81
+ text='Design'
82
+ value='design'
83
+ />
84
+ <Checkbox
85
+ name='interests'
86
+ register={register}
87
+ text='Business'
88
+ value='business'
89
+ />
90
+ <Checkbox
91
+ name='interests'
92
+ register={register}
93
+ text='Marketing'
94
+ value='marketing'
95
+ />
96
+ </div>
97
+ <div className='mt-4'>
98
+ <Body marginBottom='xs'
99
+ text='Communication Preferences'
100
+ />
101
+ <Checkbox
102
+ name='preferences.emailUpdates'
103
+ register={register}
104
+ text='Email Updates'
105
+ />
106
+ <Checkbox
107
+ name='preferences.smsUpdates'
108
+ register={register}
109
+ text='SMS Updates'
110
+ />
111
+ <Checkbox
112
+ name='preferences.pushNotifications'
113
+ register={register}
114
+ text='Push Notifications'
115
+ />
116
+ </div>
117
+ <Button
118
+ htmlType="submit"
119
+ marginTop='lg'
120
+ text='Submit'
121
+ type='submit'
122
+ variant='primary'
123
+ />
124
+ </form>
125
+ <Card marginTop='lg'>
126
+ <Body text='Current Form Values:'
127
+ variant='bold'
128
+ />
129
+ <pre style={{ marginTop: "8px", color: "white" }}>
130
+ {JSON.stringify(formValues, null, 2)}
131
+ </pre>
132
+ </Card>
133
+ </Card>
134
+ </div>
135
+ )
136
+ }
137
+
138
+ export default CheckboxForm
@@ -9,12 +9,13 @@ examples:
9
9
  - checkbox_disabled: Disabled Checkbox
10
10
 
11
11
  react:
12
- - checkbox_default: Default
13
- - checkbox_checked: Load as checked
14
- - checkbox_custom: Custom Checkbox
15
- - checkbox_error: Default w/ Error
16
- - checkbox_indeterminate: Indeterminate Checkbox
17
- - checkbox_disabled: Disabled Checkbox
12
+ - checkbox_default: Default
13
+ - checkbox_checked: Load as checked
14
+ - checkbox_custom: Custom Checkbox
15
+ - checkbox_error: Default w/ Error
16
+ - checkbox_indeterminate: Indeterminate Checkbox
17
+ - checkbox_disabled: Disabled Checkbox
18
+ - checkbox_form: Checkbox Form
18
19
 
19
20
  swift:
20
21
  - checkbox_default_swift: Default
@@ -4,3 +4,4 @@ export { default as CheckboxError } from './_checkbox_error.jsx'
4
4
  export { default as CheckboxChecked } from './_checkbox_checked.jsx'
5
5
  export { default as CheckboxIndeterminate } from './_checkbox_indeterminate.jsx'
6
6
  export { default as CheckboxDisabled } from './_checkbox_disabled.jsx'
7
+ export { default as CheckboxForm } from './_checkbox_form.jsx'
@@ -1,10 +1,12 @@
1
- import React, { forwardRef } from 'react'
1
+ import React from 'react'
2
2
  import classnames from 'classnames'
3
+ import { FieldValues } from 'react-hook-form'
3
4
 
4
5
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
6
  import { globalProps, GlobalProps, domSafeProps } from '../utilities/globalProps'
6
7
  import type { InputCallback } from '../types'
7
8
  import { getAllIcons } from "../utilities/icons/allicons"
9
+ import { withReactHookForm, WithReactHookFormProps } from '../utilities/withReactHookForm'
8
10
 
9
11
  import Body from '../pb_body/_body'
10
12
  import Caption from '../pb_caption/_caption'
@@ -30,11 +32,12 @@ type SelectProps = {
30
32
  includeBlank?: string,
31
33
  inline?: boolean,
32
34
  label?: string,
33
- margin: string,
34
- marginBottom: string,
35
+ margin?: string,
36
+ marginBottom?: string,
37
+ marginTop?: string,
35
38
  multiple?: boolean,
36
39
  name?: string,
37
- onChange: InputCallback<HTMLSelectElement>,
40
+ onChange?: InputCallback<HTMLSelectElement>,
38
41
  options: SelectOption[],
39
42
  required?: boolean,
40
43
  showArrow?: boolean,
@@ -51,7 +54,7 @@ const createOptions = (options: SelectOption[]) => options.map((option, index) =
51
54
  </option>
52
55
  ))
53
56
 
54
- const Select = ({
57
+ const Select = React.forwardRef<HTMLSelectElement, SelectProps>(({
55
58
  aria = {},
56
59
  blankSelection,
57
60
  children,
@@ -65,13 +68,13 @@ const Select = ({
65
68
  inline = false,
66
69
  multiple = false,
67
70
  name,
68
- onChange = () => undefined,
71
+ onChange,
69
72
  options = [],
70
73
  required = false,
71
74
  showArrow = false,
72
75
  value,
73
76
  ...props
74
- }: SelectProps, ref: React.LegacyRef<HTMLSelectElement>) => {
77
+ }, ref) => {
75
78
  const ariaProps = buildAriaProps(aria)
76
79
  const dataProps = buildDataProps(data)
77
80
  const htmlProps = buildHtmlProps(htmlOptions)
@@ -91,14 +94,14 @@ const Select = ({
91
94
  compactClass
92
95
  );
93
96
 
94
- const angleDown = getAllIcons()["angleDown"].icon as unknown as { [key: string]: SVGElement }
97
+ const icons = getAllIcons()
98
+ const angleDown = icons?.angleDown?.icon
95
99
 
96
100
  const selectWrapperClass = classnames(buildCss('pb_select_kit_wrapper'), { error }, className)
97
101
  const selectBody =(() =>{
98
102
  if (children) return children
99
103
  return (
100
104
  <select
101
- {...htmlOptions}
102
105
  {...domSafeProps(props)}
103
106
  disabled={disabled}
104
107
  id={name}
@@ -135,14 +138,12 @@ const Select = ({
135
138
  htmlFor={name}
136
139
  >
137
140
  {selectBody}
138
- { multiple !== true ?
141
+ { multiple !== true && angleDown &&
139
142
  <Icon
140
143
  className="pb_select_kit_caret svg-inline--fa"
141
144
  customIcon={angleDown}
142
145
  fixedWidth
143
146
  />
144
- :
145
- null
146
147
  }
147
148
  {error &&
148
149
  <Body
@@ -153,6 +154,11 @@ const Select = ({
153
154
  </label>
154
155
  </div>
155
156
  )
156
- }
157
+ })
158
+
159
+ Select.displayName = 'Select'
160
+
161
+ export type SelectWithHookFormProps<T extends FieldValues = FieldValues> = SelectProps & WithReactHookFormProps<T>
157
162
 
158
- export default forwardRef(Select)
163
+ const SelectWithHookForm = withReactHookForm(Select)
164
+ export default SelectWithHookForm
@@ -0,0 +1,109 @@
1
+ import React from 'react'
2
+ import { useForm } from 'react-hook-form'
3
+ import { Select, Card, Body, Button } from 'playbook-ui'
4
+
5
+ const SelectForm = (props) => {
6
+ const {
7
+ register,
8
+ handleSubmit,
9
+ formState: { errors },
10
+ watch,
11
+ } = useForm({
12
+ defaultValues: {
13
+ favoriteFood: '',
14
+ mealType: '',
15
+ dietaryRestrictions: '',
16
+ }
17
+ })
18
+
19
+ const onSubmit = (data) => {
20
+ console.log('Form submitted:', data)
21
+ }
22
+
23
+ // Watch form values for real-time display
24
+ const formValues = watch()
25
+
26
+ const foodOptions = [
27
+ { value: 'pizza', text: 'Pizza' },
28
+ { value: 'burger', text: 'Burger' },
29
+ { value: 'sushi', text: 'Sushi' },
30
+ { value: 'salad', text: 'Salad' },
31
+ ]
32
+
33
+ const mealTypes = [
34
+ { value: 'breakfast', text: 'Breakfast' },
35
+ { value: 'lunch', text: 'Lunch' },
36
+ { value: 'dinner', text: 'Dinner' },
37
+ ]
38
+
39
+ const dietaryOptions = [
40
+ { value: 'none', text: 'No Restrictions' },
41
+ { value: 'vegetarian', text: 'Vegetarian' },
42
+ { value: 'vegan', text: 'Vegan' },
43
+ { value: 'glutenFree', text: 'Gluten Free' },
44
+ ]
45
+
46
+ return (
47
+ <div>
48
+ <Card>
49
+ <form onSubmit={handleSubmit(onSubmit)}>
50
+ <Select
51
+ error={errors.favoriteFood?.message}
52
+ label="What's your favorite food?"
53
+ name="favoriteFood"
54
+ options={foodOptions}
55
+ register={register}
56
+ rules={{
57
+ required: 'Please select your favorite food',
58
+ }}
59
+ {...props}
60
+ />
61
+ <Select
62
+ blankSelection="Choose a meal type..."
63
+ error={errors.mealType?.message}
64
+ label="Preferred meal time"
65
+ marginTop="md"
66
+ name="mealType"
67
+ options={mealTypes}
68
+ register={register}
69
+ rules={{
70
+ required: 'Please select a meal type',
71
+ }}
72
+ {...props}
73
+ />
74
+ <Select
75
+ label="Dietary Restrictions"
76
+ marginTop="md"
77
+ name="dietaryRestrictions"
78
+ options={dietaryOptions}
79
+ register={register}
80
+ {...props}
81
+ />
82
+
83
+ <Button
84
+ htmlType="submit"
85
+ marginTop="lg"
86
+ text="Submit"
87
+ type="submit"
88
+ variant="primary"
89
+
90
+ />
91
+ </form>
92
+ <Card marginTop="lg">
93
+ <Body
94
+ text="Current Form Values:"
95
+ variant="bold"
96
+ />
97
+ <pre style={{ marginTop: '8px', color: "white" }}>
98
+ {JSON.stringify(formValues, null, 2)}
99
+ </pre>
100
+ </Card>
101
+ </Card>
102
+ </div>
103
+ )
104
+ }
105
+
106
+ export default SelectForm
107
+
108
+
109
+
@@ -30,6 +30,7 @@ examples:
30
30
  - select_inline_show_arrow: Select Inline (Always Show Arrow)
31
31
  - select_inline_compact: Select Inline Compact
32
32
  - select_multiple: Select Multiple
33
+ - select_form: Form
33
34
 
34
35
  swift:
35
36
  - select_default_swift: Default
@@ -10,3 +10,4 @@ export { default as SelectInline } from './_select_inline.jsx'
10
10
  export { default as SelectInlineShowArrow } from './_select_inline_show_arrow.jsx'
11
11
  export { default as SelectInlineCompact } from './_select_inline_compact.jsx'
12
12
  export { default as SelectMultiple } from './_select_multiple.jsx'
13
+ export { default as SelectForm } from './_select_form.jsx'
@@ -1,4 +1,4 @@
1
- import React, { forwardRef, ChangeEvent } from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import classnames from 'classnames'
3
3
 
4
4
  import { globalProps, GlobalProps, domSafeProps } from '../utilities/globalProps'
@@ -10,8 +10,6 @@ import Caption from '../pb_caption/_caption'
10
10
  import Body from '../pb_body/_body'
11
11
  import Icon from '../pb_icon/_icon'
12
12
 
13
- import { INPUTMASKS } from './inputMask'
14
-
15
13
  type TextInputProps = {
16
14
  aria?: { [key: string]: string },
17
15
  className?: string,
@@ -24,7 +22,6 @@ type TextInputProps = {
24
22
  inline?: boolean,
25
23
  name: string,
26
24
  label: string,
27
- mask?: 'currency' | 'zipCode' | 'postalCode' | 'ssn',
28
25
  onChange: (e: React.FormEvent<HTMLInputElement>) => void,
29
26
  placeholder: string,
30
27
  required?: boolean,
@@ -50,7 +47,6 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
50
47
  htmlOptions = {},
51
48
  id,
52
49
  inline = false,
53
- mask = null,
54
50
  name,
55
51
  label,
56
52
  onChange = () => { void 0 },
@@ -94,33 +90,6 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
94
90
  />
95
91
  )
96
92
 
97
- const isMaskedInput = mask && mask in INPUTMASKS
98
-
99
- const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
100
- if (isMaskedInput) {
101
- const inputValue = e.target.value
102
-
103
- let cursorPosition = e.target.selectionStart;
104
- const isAtEnd = cursorPosition === inputValue.length;
105
-
106
- const formattedValue = INPUTMASKS[mask].format(inputValue)
107
- e.target.value = formattedValue
108
-
109
- // Keep cursor position
110
- if (!isAtEnd) {
111
- // Account for extra characters (e.g., commas added/removed in currency)
112
- if (formattedValue.length - inputValue.length === 1) {
113
- cursorPosition = cursorPosition + 1
114
- } else if (mask === "currency" && formattedValue.length - inputValue.length === -1) {
115
- cursorPosition = cursorPosition - 1
116
- }
117
- e.target.selectionStart = e.target.selectionEnd = cursorPosition
118
- }
119
- }
120
-
121
- onChange(e)
122
- }
123
-
124
93
  const childInput = children ? children.type === "input" : undefined
125
94
 
126
95
  const textInput = (
@@ -132,9 +101,8 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
132
101
  id={id}
133
102
  key={id}
134
103
  name={name}
135
- onChange={isMaskedInput ? handleChange : onChange}
136
- pattern={isMaskedInput ? INPUTMASKS[mask]?.pattern : undefined}
137
- placeholder={placeholder || (isMaskedInput ? INPUTMASKS[mask]?.placeholder : undefined)}
104
+ onChange={onChange}
105
+ placeholder={placeholder}
138
106
  ref={ref}
139
107
  required={required}
140
108
  type={type}
@@ -16,7 +16,6 @@ examples:
16
16
  - text_input_add_on: Add On
17
17
  - text_input_inline: Inline
18
18
  - text_input_no_label: No Label
19
- - text_input_mask: Mask
20
19
 
21
20
  swift:
22
21
  - text_input_default_swift: Default
@@ -5,4 +5,3 @@ export { default as TextInputDisabled } from './_text_input_disabled.jsx'
5
5
  export { default as TextInputAddOn } from './_text_input_add_on.jsx'
6
6
  export { default as TextInputInline } from './_text_input_inline.jsx'
7
7
  export { default as TextInputNoLabel } from './_text_input_no_label.jsx'
8
- export { default as TextInputMask } from './_text_input_mask.jsx'