superglue 1.0.0 → 1.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 825363825f0e6cf14431bd47cdc43b6be0dfcfb6723d19004ee99175bd98dda3
4
- data.tar.gz: 27a52faf2563be8e0242c2ed68a5e02c531137e03c5e67e5993e06b615139266
3
+ metadata.gz: 8e9624774c0133d0a9d8aac0d8b5d47bbb95862eea0bb1a26ffe3ce373c5e922
4
+ data.tar.gz: 8c69fd808df13768c9036981ca27d2a0b24eb9ce8ab8d890c88b666cc9bd5798
5
5
  SHA512:
6
- metadata.gz: 8dc5c1de22f7d525e82b3e00f49cd774a814f689c8f0e5018e5f1192d694ae036af07b14c162b113e91911bfc918019784863adc7cde2bc9b9786784709d357d
7
- data.tar.gz: 5a9618185af23be3406af0153d54af83633cdc0a927337c7cd7d33f257150e6def65471b19c186ffe9d385312f979f9624f61b29c3c4ce9266c8a62820ca6b0c
6
+ metadata.gz: 17522e020054291483b60953d3fa31e60d6b95de4316ce7469ed71e7f397fa15b07533051b4a4266d5263313a947e7b3eb82621d1d0f8dd45088b9db77295cdf
7
+ data.tar.gz: 97e27d5f9330ac515cd1636af3c9974584476a324d142573176187dd3cf18a7e6db696cec11ba473f8b5f7fc3d8849fa9fbc49d14f359ef9373d5ec75b763d56
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ <div align="center" style="padding: 30px 0px 20px 0px;">
2
+ <img src="https://thoughtbot.github.io/superglue/images/superglue.svg" data-origin="images/superglue.svg" alt="Logo" width=250>
3
+ </div>
4
+
5
+ # Superglue Rails
6
+ Use classic Rails to build rich React Redux applications with **NO APIs** and
7
+ **NO client-side routing**.
8
+
9
+ This is the officially supported Rails adapter to [Superglue]. This gem will
10
+ add install and scaffold generators to your rails project.
11
+
12
+ To get started, visit the [documentation] and add this to your Gemfile
13
+
14
+ [documentation]: https://thoughtbot.github.io/superglue/
15
+
16
+ ```
17
+ gem 'superglue'
18
+ ```
19
+
20
+ Then run `bundle`
21
+
22
+ [![Test superglue_rails](https://github.com/thoughtbot/superglue_rails/actions/workflows/build_rails.yml/badge.svg)](https://github.com/thoughtbot/superglue_rails/actions/workflows/build_rails.yml)
23
+
24
+ ## Documentation
25
+
26
+ Documentation is hosted on [Github pages](https://thoughtbot.github.io/superglue).
27
+
28
+ ## Contributing
29
+
30
+ Thank you, [contributors]!
31
+
32
+ [contributors]: https://github.com/thoughtbot/superglue_rails/graphs/contributors
@@ -7,14 +7,25 @@
7
7
  * There is no style and structured with bare necessities. You should modify
8
8
  * these components to fit your design needs.
9
9
  */
10
- import React, { useContext, createContext, useMemo } from "react";
11
- export const ValidationContext = createContext({});
12
- export const useErrorKeyValidation = ({ errorKey, }) => {
13
- const errors = useContext(ValidationContext);
14
- return useMemo(() => {
15
- return errors[errorKey];
16
- }, [errors, errorKey]);
17
- };
10
+ import React, { useContext, createContext, useMemo } from 'react'
11
+ export const ValidationContext = createContext({})
12
+ export const useErrorMessage = (errorKey) => {
13
+ const errors = useContext(ValidationContext)
14
+ return useMemo(() => {
15
+ if (!errorKey) {
16
+ return null
17
+ }
18
+ const validationError = errors[errorKey]
19
+ const hasErrors = errorKey && validationError
20
+ if (!hasErrors) {
21
+ return null
22
+ }
23
+ const errorMessages = Array.isArray(validationError)
24
+ ? validationError
25
+ : [validationError]
26
+ return errorMessages.join(' ')
27
+ }, [errors, errorKey])
28
+ }
18
29
  /**
19
30
  * Extras renders the hidden inputs generated by form_props.
20
31
  *
@@ -22,10 +33,12 @@ export const useErrorKeyValidation = ({ errorKey, }) => {
22
33
  * utf8, crsf_token, _method
23
34
  */
24
35
  export const Extras = (hiddenInputAttributes) => {
25
- const hiddenProps = Object.values(hiddenInputAttributes);
26
- const hiddenInputs = hiddenProps.map((props) => (<input {...props} type="hidden" key={props.name}/>));
27
- return <>{hiddenInputs}</>;
28
- };
36
+ const hiddenProps = Object.values(hiddenInputAttributes)
37
+ const hiddenInputs = hiddenProps.map((props) => (
38
+ <input {...props} type="hidden" key={props.name} />
39
+ ))
40
+ return <>{hiddenInputs}</>
41
+ }
29
42
  /**
30
43
  * A basic form component that supports inline errors.
31
44
  *
@@ -33,13 +46,15 @@ export const Extras = (hiddenInputAttributes) => {
33
46
  * Rails forms are generated.
34
47
  */
35
48
  export const Form = ({ extras, validationErrors = {}, children, ...props }) => {
36
- return (<form {...props}>
49
+ return (
50
+ <form {...props}>
37
51
  <ValidationContext.Provider value={validationErrors}>
38
52
  <Extras {...extras}></Extras>
39
53
  {children}
40
54
  </ValidationContext.Provider>
41
- </form>);
42
- };
55
+ </form>
56
+ )
57
+ }
43
58
  /**
44
59
  * An inline error component.
45
60
  *
@@ -47,84 +62,110 @@ export const Form = ({ extras, validationErrors = {}, children, ...props }) => {
47
62
  * Please modify this to your liking.
48
63
  */
49
64
  export const FieldError = ({ errorKey }) => {
50
- const errors = useContext(ValidationContext);
51
- if (!errorKey || !errors) {
52
- return null;
53
- }
54
- const validationError = errors[errorKey];
55
- const hasErrors = errorKey && validationError;
56
- if (!hasErrors) {
57
- return null;
58
- }
59
- const errorMessages = Array.isArray(validationError)
60
- ? validationError
61
- : [validationError];
62
- return <span>{errorMessages.join(" ")}</span>;
63
- };
65
+ const errorMessage = useErrorMessage(errorKey)
66
+ return <span>{errorMessage}</span>
67
+ }
64
68
  /**
65
69
  * A Field component.
66
70
  *
67
71
  * Combines a label, input and a FieldError. Please modify this to your liking.
68
72
  */
69
73
  export const FieldBase = ({ label, errorKey, children, ...props }) => {
70
- return (<>
74
+ return (
75
+ <>
71
76
  <label htmlFor={props.id}>{label}</label>
72
- {children || <input {...props}/>}
73
- <FieldError errorKey={errorKey}/>
74
- </>);
75
- };
76
- export const Checkbox = ({ type: _type, includeHidden, uncheckedValue, errorKey, ...rest }) => {
77
- const { name } = rest;
78
- return (<FieldBase {...rest} errorKey={errorKey}>
79
- {includeHidden && (<input type="hidden" name={name} defaultValue={uncheckedValue} autoComplete="off"/>)}
77
+ {children || <input {...props} />}
78
+ <FieldError errorKey={errorKey} />
79
+ </>
80
+ )
81
+ }
82
+ export const Checkbox = ({
83
+ type: _type,
84
+ includeHidden,
85
+ uncheckedValue,
86
+ errorKey,
87
+ ...rest
88
+ }) => {
89
+ const { name } = rest
90
+ return (
91
+ <FieldBase {...rest} errorKey={errorKey}>
92
+ {includeHidden && (
93
+ <input
94
+ type="hidden"
95
+ name={name}
96
+ defaultValue={uncheckedValue}
97
+ autoComplete="off"
98
+ />
99
+ )}
80
100
  <input type="checkbox" {...rest}></input>
81
- </FieldBase>);
82
- };
101
+ </FieldBase>
102
+ )
103
+ }
83
104
  /**
84
105
  * A collection checkbox component.
85
106
  *
86
107
  * Designed to work with a payload form_props's [collection_check_boxes helper](https://github.com/thoughtbot/form_props?tab=readme-ov-file#collection-select).
87
108
  * Mimics the rails equivalent. Please modify to your liking.
88
109
  */
89
- export const CollectionCheckboxes = ({ includeHidden, collection, label, errorKey, }) => {
90
- if (collection.length == 0) {
91
- return null;
92
- }
93
- const checkboxes = collection.map((options) => {
94
- return <Checkbox {...options} key={options.id}/>;
95
- });
96
- const { name } = collection[0];
97
- return (<>
98
- {includeHidden && (<input type="hidden" name={name} defaultValue={""} autoComplete="off"/>)}
110
+ export const CollectionCheckboxes = ({
111
+ includeHidden,
112
+ collection,
113
+ label,
114
+ errorKey,
115
+ }) => {
116
+ if (collection.length == 0) {
117
+ return null
118
+ }
119
+ const checkboxes = collection.map((options) => {
120
+ return <Checkbox {...options} key={options.id} />
121
+ })
122
+ const { name } = collection[0]
123
+ return (
124
+ <>
125
+ {includeHidden && (
126
+ <input type="hidden" name={name} defaultValue={''} autoComplete="off" />
127
+ )}
99
128
  <label>{label}</label>
100
129
  {checkboxes}
101
- <FieldError errorKey={errorKey}/>
102
- </>);
103
- };
130
+ <FieldError errorKey={errorKey} />
131
+ </>
132
+ )
133
+ }
104
134
  /**
105
135
  * A collection radio button component.
106
136
  *
107
137
  * Designed to work with a payload form_props's [collection_radio_buttons helper](https://github.com/thoughtbot/form_props?tab=readme-ov-file#collection-select).
108
138
  * Mimics the rails equivalent. Please modify to your liking.
109
139
  */
110
- export const CollectionRadioButtons = ({ includeHidden, collection, label, errorKey, }) => {
111
- if (collection.length == 0) {
112
- return null;
113
- }
114
- const radioButtons = collection.map((options) => {
115
- return (<div key={options.value}>
116
- <input {...options} type="radio"/>
140
+ export const CollectionRadioButtons = ({
141
+ includeHidden,
142
+ collection,
143
+ label,
144
+ errorKey,
145
+ }) => {
146
+ if (collection.length == 0) {
147
+ return null
148
+ }
149
+ const radioButtons = collection.map((options) => {
150
+ return (
151
+ <div key={options.value}>
152
+ <input {...options} type="radio" />
117
153
  <label htmlFor={options.id}>{options.label}</label>
118
- </div>);
119
- });
120
- const { name } = collection[0];
121
- return (<>
122
- {includeHidden && (<input type="hidden" name={name} defaultValue={""} autoComplete="off"/>)}
154
+ </div>
155
+ )
156
+ })
157
+ const { name } = collection[0]
158
+ return (
159
+ <>
160
+ {includeHidden && (
161
+ <input type="hidden" name={name} defaultValue={''} autoComplete="off" />
162
+ )}
123
163
  <label>{label}</label>
124
164
  {radioButtons}
125
- <FieldError errorKey={errorKey}/>
126
- </>);
127
- };
165
+ <FieldError errorKey={errorKey} />
166
+ </>
167
+ )
168
+ }
128
169
  /**
129
170
  * A text field component.
130
171
  *
@@ -132,8 +173,8 @@ export const CollectionRadioButtons = ({ includeHidden, collection, label, error
132
173
  * Mimics the rails equivalent. Please modify to your liking.
133
174
  */
134
175
  export const TextField = ({ type: _type, ...rest }) => {
135
- return <FieldBase {...rest} type="text"/>;
136
- };
176
+ return <FieldBase {...rest} type="text" />
177
+ }
137
178
  /**
138
179
  * A email field component.
139
180
  *
@@ -141,8 +182,8 @@ export const TextField = ({ type: _type, ...rest }) => {
141
182
  * Mimics the rails equivalent. Please modify to your liking.
142
183
  */
143
184
  export const EmailField = ({ type: _type, ...rest }) => {
144
- return <FieldBase {...rest} type="email"/>;
145
- };
185
+ return <FieldBase {...rest} type="email" />
186
+ }
146
187
  /**
147
188
  * A color field component.
148
189
  *
@@ -150,8 +191,8 @@ export const EmailField = ({ type: _type, ...rest }) => {
150
191
  * Mimics the rails equivalent. Please modify to your liking.
151
192
  */
152
193
  export const ColorField = ({ type: _type, ...rest }) => {
153
- return <FieldBase {...rest} type="color"/>;
154
- };
194
+ return <FieldBase {...rest} type="color" />
195
+ }
155
196
  /**
156
197
  * A date field component.
157
198
  *
@@ -159,8 +200,8 @@ export const ColorField = ({ type: _type, ...rest }) => {
159
200
  * Mimics the rails equivalent. Please modify to your liking.
160
201
  */
161
202
  export const DateField = ({ type: _type, ...rest }) => {
162
- return <FieldBase {...rest} type="date"/>;
163
- };
203
+ return <FieldBase {...rest} type="date" />
204
+ }
164
205
  /**
165
206
  * A date field component.
166
207
  *
@@ -168,8 +209,8 @@ export const DateField = ({ type: _type, ...rest }) => {
168
209
  * Mimics the rails equivalent. Please modify to your liking.
169
210
  */
170
211
  export const DateTimeLocalField = ({ type: _type, ...rest }) => {
171
- return <FieldBase {...rest} type="datetime-local"/>;
172
- };
212
+ return <FieldBase {...rest} type="datetime-local" />
213
+ }
173
214
  /**
174
215
  * A search field component.
175
216
  *
@@ -177,8 +218,8 @@ export const DateTimeLocalField = ({ type: _type, ...rest }) => {
177
218
  * Mimics the rails equivalent. Please modify to your liking.
178
219
  */
179
220
  export const SearchField = ({ type: _type, ...rest }) => {
180
- return <FieldBase {...rest} type="search"/>;
181
- };
221
+ return <FieldBase {...rest} type="search" />
222
+ }
182
223
  /**
183
224
  * A tel field component.
184
225
  *
@@ -186,8 +227,8 @@ export const SearchField = ({ type: _type, ...rest }) => {
186
227
  * Mimics the rails equivalent. Please modify to your liking.
187
228
  */
188
229
  export const TelField = ({ type: _type, ...rest }) => {
189
- return <FieldBase {...rest} type="tel"/>;
190
- };
230
+ return <FieldBase {...rest} type="tel" />
231
+ }
191
232
  /**
192
233
  * A url field component.
193
234
  *
@@ -195,8 +236,8 @@ export const TelField = ({ type: _type, ...rest }) => {
195
236
  * Mimics the rails equivalent. Please modify to your liking.
196
237
  */
197
238
  export const UrlField = ({ type: _type, ...rest }) => {
198
- return <FieldBase {...rest} type="url"/>;
199
- };
239
+ return <FieldBase {...rest} type="url" />
240
+ }
200
241
  /**
201
242
  * A month field component.
202
243
  *
@@ -204,17 +245,17 @@ export const UrlField = ({ type: _type, ...rest }) => {
204
245
  * Mimics the rails equivalent. Please modify to your liking.
205
246
  */
206
247
  export const MonthField = ({ type: _type, ...rest }) => {
207
- return <FieldBase {...rest} type="month"/>;
208
- };
248
+ return <FieldBase {...rest} type="month" />
249
+ }
209
250
  /**
210
- * A month field component.
251
+ * A time field component.
211
252
  *
212
253
  * Designed to work with a payload form_props's [month_field helper](https://github.com/thoughtbot/form_props?tab=readme-ov-file#date-helpers).
213
254
  * Mimics the rails equivalent. Please modify to your liking.
214
255
  */
215
256
  export const TimeField = ({ type: _type, ...rest }) => {
216
- return <FieldBase {...rest} type="time"/>;
217
- };
257
+ return <FieldBase {...rest} type="time" />
258
+ }
218
259
  /**
219
260
  * A number field component.
220
261
  *
@@ -222,8 +263,8 @@ export const TimeField = ({ type: _type, ...rest }) => {
222
263
  * Mimics the rails equivalent. Please modify to your liking.
223
264
  */
224
265
  export const NumberField = ({ type: _type, ...rest }) => {
225
- return <FieldBase {...rest} type="number"/>;
226
- };
266
+ return <FieldBase {...rest} type="number" />
267
+ }
227
268
  /**
228
269
  * A range field component.
229
270
  *
@@ -231,8 +272,8 @@ export const NumberField = ({ type: _type, ...rest }) => {
231
272
  * Mimics the rails equivalent. Please modify to your liking.
232
273
  */
233
274
  export const RangeField = ({ type: _type, ...rest }) => {
234
- return <FieldBase {...rest} type="range"/>;
235
- };
275
+ return <FieldBase {...rest} type="range" />
276
+ }
236
277
  /**
237
278
  * A password field component.
238
279
  *
@@ -240,8 +281,8 @@ export const RangeField = ({ type: _type, ...rest }) => {
240
281
  * Mimics the rails equivalent. Please modify to your liking.
241
282
  */
242
283
  export const PasswordField = ({ type: _type, ...rest }) => {
243
- return <FieldBase {...rest} type="password"/>;
244
- };
284
+ return <FieldBase {...rest} type="password" />
285
+ }
245
286
  /**
246
287
  * A select component.
247
288
  *
@@ -250,26 +291,46 @@ export const PasswordField = ({ type: _type, ...rest }) => {
250
291
  *
251
292
  * Please modify to your liking.
252
293
  */
253
- export const Select = ({ includeHidden, name, id, children, options, multiple, type: _type, ...rest }) => {
254
- const addHidden = includeHidden && multiple;
255
- const optionElements = options.map((item) => {
256
- if ("options" in item) {
257
- return (<optgroup label={item.label} key={item.label}>
258
- {item.options.map((opt) => (<option key={opt.label} {...opt}/>))}
259
- </optgroup>);
260
- }
261
- else {
262
- return <option key={item.label} {...item}/>;
263
- }
264
- });
265
- return (<>
266
- {addHidden && (<input type="hidden" name={name} value={""} autoComplete="off"/>)}
267
- <select name={name} id={id} multiple={multiple} {...rest}>
268
- {children}
269
- {optionElements}
270
- </select>
271
- </>);
272
- };
294
+ export const Select = ({
295
+ includeHidden,
296
+ name,
297
+ id,
298
+ children,
299
+ options,
300
+ label,
301
+ errorKey,
302
+ multiple,
303
+ type: _type,
304
+ ...rest
305
+ }) => {
306
+ const addHidden = includeHidden && multiple
307
+ const optionElements = options.map((item) => {
308
+ if ('options' in item) {
309
+ return (
310
+ <optgroup label={item.label} key={item.label}>
311
+ {item.options.map((opt) => (
312
+ <option key={opt.label} {...opt} />
313
+ ))}
314
+ </optgroup>
315
+ )
316
+ } else {
317
+ return <option key={item.label} {...item} />
318
+ }
319
+ })
320
+ return (
321
+ <>
322
+ {addHidden && (
323
+ <input type="hidden" name={name} value={''} autoComplete="off" />
324
+ )}
325
+ <FieldBase label={label} errorKey={errorKey} id={id}>
326
+ <select name={name} id={id} multiple={multiple} {...rest}>
327
+ {children}
328
+ {optionElements}
329
+ </select>
330
+ </FieldBase>
331
+ </>
332
+ )
333
+ }
273
334
  /**
274
335
  * A text area component.
275
336
  *
@@ -277,11 +338,13 @@ export const Select = ({ includeHidden, name, id, children, options, multiple, t
277
338
  * Mimics the rails equivalent. Please modify to your liking.
278
339
  */
279
340
  export const TextArea = ({ type: _type, errorKey, ...rest }) => {
280
- const { label } = rest;
281
- return (<FieldBase label={label} errorKey={errorKey} id={rest.id}>
282
- <textarea {...rest}/>
283
- </FieldBase>);
284
- };
341
+ const { label } = rest
342
+ return (
343
+ <FieldBase label={label} errorKey={errorKey} id={rest.id}>
344
+ <textarea {...rest} />
345
+ </FieldBase>
346
+ )
347
+ }
285
348
  /**
286
349
  * A file field component.
287
350
  *
@@ -289,8 +352,8 @@ export const TextArea = ({ type: _type, errorKey, ...rest }) => {
289
352
  * Mimics the rails equivalent. Please modify to your liking.
290
353
  */
291
354
  export const FileField = ({ type: _type, ...rest }) => {
292
- return <FieldBase {...rest} type="file"/>;
293
- };
355
+ return <FieldBase {...rest} type="file" />
356
+ }
294
357
  /**
295
358
  * A SubmitButton component.
296
359
  *
@@ -298,5 +361,10 @@ export const FileField = ({ type: _type, ...rest }) => {
298
361
  * Mimics the rails equivalent. Please modify to your liking.
299
362
  */
300
363
  export const SubmitButton = ({ type: _type, text, ...rest }) => {
301
- return <button {...rest} type="submit"> {text} </button>;
302
- };
364
+ return (
365
+ <button {...rest} type="submit">
366
+ {' '}
367
+ {text}{' '}
368
+ </button>
369
+ )
370
+ }
@@ -8,7 +8,7 @@
8
8
  * these components to fit your design needs.
9
9
  */
10
10
 
11
- import React, { ReactNode, useContext, createContext, useMemo } from "react";
11
+ import React, { ReactNode, useContext, createContext, useMemo } from 'react'
12
12
  import {
13
13
  CheckboxField as RailsCheckboxField,
14
14
  CollectionCheckboxesField as RailsCollectionCheckboxesField,
@@ -31,25 +31,35 @@ import {
31
31
  UrlField as RailsUrlField,
32
32
  TextArea as RailsTextArea,
33
33
  ValidationErrors,
34
- SubmitProps as RailsSubmitButton
34
+ SubmitProps as RailsSubmitButton,
35
35
  } from '@thoughtbot/candy_wrapper'
36
36
 
37
- export const ValidationContext = createContext<ValidationErrors>({});
37
+ export const ValidationContext = createContext<ValidationErrors>({})
38
38
 
39
- export const useErrorKeyValidation = ({
40
- errorKey,
41
- }: {
42
- errorKey: string;
43
- name: string;
44
- }) => {
45
- const errors = useContext(ValidationContext);
39
+ export const useErrorMessage = (errorKey?: string) => {
40
+ const errors = useContext(ValidationContext)
46
41
 
47
42
  return useMemo(() => {
48
- return errors[errorKey];
49
- }, [errors, errorKey]);
50
- };
43
+ if (!errorKey) {
44
+ return null
45
+ }
46
+
47
+ const validationError = errors[errorKey]
48
+ const hasErrors = errorKey && validationError
49
+
50
+ if (!hasErrors) {
51
+ return null
52
+ }
53
+
54
+ const errorMessages = Array.isArray(validationError)
55
+ ? validationError
56
+ : [validationError]
51
57
 
52
- export type ExtrasProps = Record<string, RailsHiddenField>;
58
+ return errorMessages.join(' ')
59
+ }, [errors, errorKey])
60
+ }
61
+
62
+ export type ExtrasProps = Record<string, RailsHiddenField>
53
63
 
54
64
  /**
55
65
  * Extras renders the hidden inputs generated by form_props.
@@ -58,25 +68,24 @@ export type ExtrasProps = Record<string, RailsHiddenField>;
58
68
  * utf8, crsf_token, _method
59
69
  */
60
70
  export const Extras = (hiddenInputAttributes: ExtrasProps) => {
61
- const hiddenProps = Object.values(hiddenInputAttributes);
71
+ const hiddenProps = Object.values(hiddenInputAttributes)
62
72
  const hiddenInputs = hiddenProps.map((props: RailsHiddenField) => (
63
73
  <input {...props} type="hidden" key={props.name} />
64
- ));
74
+ ))
65
75
 
66
- return <>{hiddenInputs}</>;
67
- };
76
+ return <>{hiddenInputs}</>
77
+ }
68
78
 
69
- // TODO: Add this as a form props props??
70
- export interface FormProps<T={}> {
71
- extras: ExtrasProps;
72
- inputs: T;
73
- form: React.FormHTMLAttributes<HTMLFormElement>;
79
+ export interface FormProps<T = {}> {
80
+ extras: ExtrasProps
81
+ inputs: T
82
+ form: React.FormHTMLAttributes<HTMLFormElement>
74
83
  }
75
84
 
76
85
  type FormElementProps = React.FormHTMLAttributes<HTMLFormElement> & {
77
- extras: ExtrasProps;
78
- validationErrors?: ValidationErrors;
79
- };
86
+ extras: ExtrasProps
87
+ validationErrors?: ValidationErrors
88
+ }
80
89
  /**
81
90
  * A basic form component that supports inline errors.
82
91
  *
@@ -96,8 +105,8 @@ export const Form = ({
96
105
  {children}
97
106
  </ValidationContext.Provider>
98
107
  </form>
99
- );
100
- };
108
+ )
109
+ }
101
110
 
102
111
  /**
103
112
  * An inline error component.
@@ -106,31 +115,17 @@ export const Form = ({
106
115
  * Please modify this to your liking.
107
116
  */
108
117
  export const FieldError = ({ errorKey }: { errorKey: string | undefined }) => {
109
- const errors = useContext(ValidationContext);
110
- if (!errorKey || !errors) {
111
- return null;
112
- }
118
+ const errorMessage = useErrorMessage(errorKey)
113
119
 
114
- const validationError = errors[errorKey];
115
- const hasErrors = errorKey && validationError;
116
-
117
- if (!hasErrors) {
118
- return null;
119
- }
120
-
121
- const errorMessages = Array.isArray(validationError)
122
- ? validationError
123
- : [validationError];
124
-
125
- return <span>{errorMessages.join(" ")}</span>;
126
- };
120
+ return <span>{errorMessage}</span>
121
+ }
127
122
 
128
123
  export type FieldBaseProps = React.InputHTMLAttributes<HTMLInputElement> & {
129
- id?: string;
130
- label: string;
131
- errorKey?: string;
132
- children?: ReactNode;
133
- };
124
+ id?: string
125
+ label: string
126
+ errorKey?: string
127
+ children?: ReactNode
128
+ }
134
129
 
135
130
  /**
136
131
  * A Field component.
@@ -149,13 +144,13 @@ export const FieldBase = ({
149
144
  {children || <input {...props} />}
150
145
  <FieldError errorKey={errorKey} />
151
146
  </>
152
- );
153
- };
147
+ )
148
+ }
154
149
 
155
150
  type InputProps = {
156
- label: string;
157
- errorKey?: string;
158
- };
151
+ label: string
152
+ errorKey?: string
153
+ }
159
154
 
160
155
  /**
161
156
  * A checkbox component.
@@ -163,7 +158,7 @@ type InputProps = {
163
158
  * Designed to work with a payload form_props's [checkbox helper](https://github.com/thoughtbot/form_props?tab=readme-ov-file#checkbox-helper).
164
159
  * Mimics the rails equivalent. Please modify to your liking.
165
160
  */
166
- type CheckboxProps = RailsCheckboxField & InputProps;
161
+ type CheckboxProps = RailsCheckboxField & InputProps
167
162
  export const Checkbox = ({
168
163
  type: _type,
169
164
  includeHidden,
@@ -171,7 +166,7 @@ export const Checkbox = ({
171
166
  errorKey,
172
167
  ...rest
173
168
  }: CheckboxProps) => {
174
- const { name } = rest;
169
+ const { name } = rest
175
170
  return (
176
171
  <FieldBase {...rest} errorKey={errorKey}>
177
172
  {includeHidden && (
@@ -184,11 +179,11 @@ export const Checkbox = ({
184
179
  )}
185
180
  <input type="checkbox" {...rest}></input>
186
181
  </FieldBase>
187
- );
188
- };
182
+ )
183
+ }
189
184
 
190
185
  type CollectionCheckboxesFieldProps = RailsCollectionCheckboxesField &
191
- InputProps;
186
+ InputProps
192
187
 
193
188
  /**
194
189
  * A collection checkbox component.
@@ -203,29 +198,29 @@ export const CollectionCheckboxes = ({
203
198
  errorKey,
204
199
  }: CollectionCheckboxesFieldProps) => {
205
200
  if (collection.length == 0) {
206
- return null;
201
+ return null
207
202
  }
208
203
 
209
204
  const checkboxes = collection.map((options) => {
210
- return <Checkbox {...options} key={options.id} />;
211
- });
205
+ return <Checkbox {...options} key={options.id} />
206
+ })
212
207
 
213
- const { name } = collection[0];
208
+ const { name } = collection[0]
214
209
 
215
210
  return (
216
211
  <>
217
212
  {includeHidden && (
218
- <input type="hidden" name={name} defaultValue={""} autoComplete="off" />
213
+ <input type="hidden" name={name} defaultValue={''} autoComplete="off" />
219
214
  )}
220
215
  <label>{label}</label>
221
216
  {checkboxes}
222
217
  <FieldError errorKey={errorKey} />
223
218
  </>
224
- );
225
- };
219
+ )
220
+ }
226
221
 
227
222
  type CollectionRadioButtonsFieldProps = RailsCollectionRadioButtonsField &
228
- InputProps;
223
+ InputProps
229
224
 
230
225
  /**
231
226
  * A collection radio button component.
@@ -240,7 +235,7 @@ export const CollectionRadioButtons = ({
240
235
  errorKey,
241
236
  }: CollectionRadioButtonsFieldProps) => {
242
237
  if (collection.length == 0) {
243
- return null;
238
+ return null
244
239
  }
245
240
 
246
241
  const radioButtons = collection.map((options) => {
@@ -249,26 +244,26 @@ export const CollectionRadioButtons = ({
249
244
  <input {...options} type="radio" />
250
245
  <label htmlFor={options.id}>{options.label}</label>
251
246
  </div>
252
- );
253
- });
247
+ )
248
+ })
254
249
 
255
- const { name } = collection[0];
250
+ const { name } = collection[0]
256
251
 
257
252
  return (
258
253
  <>
259
254
  {includeHidden && (
260
- <input type="hidden" name={name} defaultValue={""} autoComplete="off" />
255
+ <input type="hidden" name={name} defaultValue={''} autoComplete="off" />
261
256
  )}
262
257
  <label>{label}</label>
263
258
  {radioButtons}
264
259
  <FieldError errorKey={errorKey} />
265
260
  </>
266
- );
267
- };
261
+ )
262
+ }
268
263
 
269
264
  export type TextFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
270
265
  RailsTextField &
271
- InputProps;
266
+ InputProps
272
267
 
273
268
  /**
274
269
  * A text field component.
@@ -277,12 +272,12 @@ export type TextFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
277
272
  * Mimics the rails equivalent. Please modify to your liking.
278
273
  */
279
274
  export const TextField = ({ type: _type, ...rest }: TextFieldProps) => {
280
- return <FieldBase {...rest} type="text" />;
281
- };
275
+ return <FieldBase {...rest} type="text" />
276
+ }
282
277
 
283
278
  export type EmailFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
284
279
  RailsEmailField &
285
- InputProps;
280
+ InputProps
286
281
 
287
282
  /**
288
283
  * A email field component.
@@ -291,12 +286,12 @@ export type EmailFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
291
286
  * Mimics the rails equivalent. Please modify to your liking.
292
287
  */
293
288
  export const EmailField = ({ type: _type, ...rest }: EmailFieldProps) => {
294
- return <FieldBase {...rest} type="email" />;
295
- };
289
+ return <FieldBase {...rest} type="email" />
290
+ }
296
291
 
297
292
  export type ColorFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
298
293
  RailsColorField &
299
- InputProps;
294
+ InputProps
300
295
 
301
296
  /**
302
297
  * A color field component.
@@ -305,12 +300,12 @@ export type ColorFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
305
300
  * Mimics the rails equivalent. Please modify to your liking.
306
301
  */
307
302
  export const ColorField = ({ type: _type, ...rest }: ColorFieldProps) => {
308
- return <FieldBase {...rest} type="color" />;
309
- };
303
+ return <FieldBase {...rest} type="color" />
304
+ }
310
305
 
311
306
  export type DateFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
312
307
  RailsDateField &
313
- InputProps;
308
+ InputProps
314
309
 
315
310
  /**
316
311
  * A date field component.
@@ -319,13 +314,13 @@ export type DateFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
319
314
  * Mimics the rails equivalent. Please modify to your liking.
320
315
  */
321
316
  export const DateField = ({ type: _type, ...rest }: DateFieldProps) => {
322
- return <FieldBase {...rest} type="date" />;
323
- };
317
+ return <FieldBase {...rest} type="date" />
318
+ }
324
319
 
325
320
  export type DateTimeLocalFieldProps =
326
321
  React.InputHTMLAttributes<HTMLInputElement> &
327
322
  RailsDateTimeLocalField &
328
- InputProps;
323
+ InputProps
329
324
 
330
325
  /**
331
326
  * A date field component.
@@ -337,12 +332,12 @@ export const DateTimeLocalField = ({
337
332
  type: _type,
338
333
  ...rest
339
334
  }: DateTimeLocalFieldProps) => {
340
- return <FieldBase {...rest} type="datetime-local" />;
341
- };
335
+ return <FieldBase {...rest} type="datetime-local" />
336
+ }
342
337
 
343
338
  export type SearchFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
344
339
  RailsSearchField &
345
- InputProps;
340
+ InputProps
346
341
 
347
342
  /**
348
343
  * A search field component.
@@ -351,12 +346,12 @@ export type SearchFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
351
346
  * Mimics the rails equivalent. Please modify to your liking.
352
347
  */
353
348
  export const SearchField = ({ type: _type, ...rest }: SearchFieldProps) => {
354
- return <FieldBase {...rest} type="search" />;
355
- };
349
+ return <FieldBase {...rest} type="search" />
350
+ }
356
351
 
357
352
  export type TelFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
358
353
  RailsTelField &
359
- InputProps;
354
+ InputProps
360
355
 
361
356
  /**
362
357
  * A tel field component.
@@ -365,12 +360,12 @@ export type TelFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
365
360
  * Mimics the rails equivalent. Please modify to your liking.
366
361
  */
367
362
  export const TelField = ({ type: _type, ...rest }: TelFieldProps) => {
368
- return <FieldBase {...rest} type="tel" />;
369
- };
363
+ return <FieldBase {...rest} type="tel" />
364
+ }
370
365
 
371
366
  export type UrlFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
372
367
  RailsUrlField &
373
- InputProps;
368
+ InputProps
374
369
 
375
370
  /**
376
371
  * A url field component.
@@ -379,12 +374,12 @@ export type UrlFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
379
374
  * Mimics the rails equivalent. Please modify to your liking.
380
375
  */
381
376
  export const UrlField = ({ type: _type, ...rest }: UrlFieldProps) => {
382
- return <FieldBase {...rest} type="url" />;
383
- };
377
+ return <FieldBase {...rest} type="url" />
378
+ }
384
379
 
385
380
  export type MonthFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
386
381
  RailsMonthField &
387
- InputProps;
382
+ InputProps
388
383
 
389
384
  /**
390
385
  * A month field component.
@@ -393,26 +388,26 @@ export type MonthFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
393
388
  * Mimics the rails equivalent. Please modify to your liking.
394
389
  */
395
390
  export const MonthField = ({ type: _type, ...rest }: MonthFieldProps) => {
396
- return <FieldBase {...rest} type="month" />;
397
- };
391
+ return <FieldBase {...rest} type="month" />
392
+ }
398
393
 
399
394
  export type TimeFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
400
395
  RailsTimeField &
401
- InputProps;
396
+ InputProps
402
397
 
403
398
  /**
404
- * A month field component.
399
+ * A time field component.
405
400
  *
406
401
  * Designed to work with a payload form_props's [month_field helper](https://github.com/thoughtbot/form_props?tab=readme-ov-file#date-helpers).
407
402
  * Mimics the rails equivalent. Please modify to your liking.
408
403
  */
409
404
  export const TimeField = ({ type: _type, ...rest }: TimeFieldProps) => {
410
- return <FieldBase {...rest} type="time" />;
411
- };
405
+ return <FieldBase {...rest} type="time" />
406
+ }
412
407
 
413
408
  export type NumberFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
414
409
  RailsNumberField &
415
- InputProps;
410
+ InputProps
416
411
  /**
417
412
  * A number field component.
418
413
  *
@@ -420,12 +415,12 @@ export type NumberFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
420
415
  * Mimics the rails equivalent. Please modify to your liking.
421
416
  */
422
417
  export const NumberField = ({ type: _type, ...rest }: NumberFieldProps) => {
423
- return <FieldBase {...rest} type="number" />;
424
- };
418
+ return <FieldBase {...rest} type="number" />
419
+ }
425
420
 
426
421
  export type RangeFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
427
422
  RailsRangeField &
428
- InputProps;
423
+ InputProps
429
424
  /**
430
425
  * A range field component.
431
426
  *
@@ -433,12 +428,12 @@ export type RangeFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
433
428
  * Mimics the rails equivalent. Please modify to your liking.
434
429
  */
435
430
  export const RangeField = ({ type: _type, ...rest }: RangeFieldProps) => {
436
- return <FieldBase {...rest} type="range" />;
437
- };
431
+ return <FieldBase {...rest} type="range" />
432
+ }
438
433
 
439
434
  export type PasswordFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
440
435
  RailsPasswordField &
441
- InputProps;
436
+ InputProps
442
437
  /**
443
438
  * A password field component.
444
439
  *
@@ -446,14 +441,12 @@ export type PasswordFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
446
441
  * Mimics the rails equivalent. Please modify to your liking.
447
442
  */
448
443
  export const PasswordField = ({ type: _type, ...rest }: PasswordFieldProps) => {
449
- return <FieldBase {...rest} type="password" />;
450
- };
444
+ return <FieldBase {...rest} type="password" />
445
+ }
451
446
 
452
447
  export type SelectProps = React.SelectHTMLAttributes<HTMLSelectElement> &
453
- RailsSelect & {
454
- label?: string;
455
- errorKey?: string;
456
- };
448
+ RailsSelect &
449
+ InputProps
457
450
  /**
458
451
  * A select component.
459
452
  *
@@ -468,42 +461,46 @@ export const Select = ({
468
461
  id,
469
462
  children,
470
463
  options,
464
+ label,
465
+ errorKey,
471
466
  multiple,
472
467
  type: _type,
473
468
  ...rest
474
469
  }: SelectProps) => {
475
- const addHidden = includeHidden && multiple;
470
+ const addHidden = includeHidden && multiple
476
471
 
477
472
  const optionElements = options.map((item) => {
478
- if ("options" in item) {
473
+ if ('options' in item) {
479
474
  return (
480
475
  <optgroup label={item.label} key={item.label}>
481
476
  {item.options.map((opt) => (
482
477
  <option key={opt.label} {...opt} />
483
478
  ))}
484
479
  </optgroup>
485
- );
480
+ )
486
481
  } else {
487
- return <option key={item.label} {...item} />;
482
+ return <option key={item.label} {...item} />
488
483
  }
489
- });
484
+ })
490
485
 
491
486
  return (
492
487
  <>
493
488
  {addHidden && (
494
- <input type="hidden" name={name} value={""} autoComplete="off" />
489
+ <input type="hidden" name={name} value={''} autoComplete="off" />
495
490
  )}
496
- <select name={name} id={id} multiple={multiple} {...rest}>
497
- {children}
498
- {optionElements}
499
- </select>
491
+ <FieldBase label={label} errorKey={errorKey} id={id}>
492
+ <select name={name} id={id} multiple={multiple} {...rest}>
493
+ {children}
494
+ {optionElements}
495
+ </select>
496
+ </FieldBase>
500
497
  </>
501
- );
502
- };
498
+ )
499
+ }
503
500
 
504
501
  export type TextAreaProps = React.InputHTMLAttributes<HTMLTextAreaElement> &
505
502
  RailsTextArea &
506
- InputProps;
503
+ InputProps
507
504
  /**
508
505
  * A text area component.
509
506
  *
@@ -511,18 +508,18 @@ export type TextAreaProps = React.InputHTMLAttributes<HTMLTextAreaElement> &
511
508
  * Mimics the rails equivalent. Please modify to your liking.
512
509
  */
513
510
  export const TextArea = ({ type: _type, errorKey, ...rest }: TextAreaProps) => {
514
- const { label } = rest;
511
+ const { label } = rest
515
512
 
516
513
  return (
517
514
  <FieldBase label={label} errorKey={errorKey} id={rest.id}>
518
515
  <textarea {...rest} />
519
516
  </FieldBase>
520
- );
521
- };
517
+ )
518
+ }
522
519
 
523
520
  export type FileFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
524
521
  RailsFileField &
525
- InputProps;
522
+ InputProps
526
523
 
527
524
  /**
528
525
  * A file field component.
@@ -531,17 +528,27 @@ export type FileFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
531
528
  * Mimics the rails equivalent. Please modify to your liking.
532
529
  */
533
530
  export const FileField = ({ type: _type, ...rest }: FileFieldProps) => {
534
- return <FieldBase {...rest} type="file" />;
535
- };
531
+ return <FieldBase {...rest} type="file" />
532
+ }
536
533
 
537
534
  export type SubmitButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
538
535
  RailsSubmitButton
536
+
539
537
  /**
540
538
  * A SubmitButton component.
541
539
  *
542
540
  * Designed to work with a payload form_props's [submit helper](https://github.com/thoughtbot/form_props?tab=readme-ov-file#form-helpers).
543
541
  * Mimics the rails equivalent. Please modify to your liking.
544
542
  */
545
- export const SubmitButton = ({ type: _type, text, ...rest }: SubmitButtonProps) => {
546
- return <button {...rest} type="submit"> {text} </button>
547
- };
543
+ export const SubmitButton = ({
544
+ type: _type,
545
+ text,
546
+ ...rest
547
+ }: SubmitButtonProps) => {
548
+ return (
549
+ <button {...rest} type="submit">
550
+ {' '}
551
+ {text}{' '}
552
+ </button>
553
+ )
554
+ }
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: superglue
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johny Ho
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 2025-01-06 00:00:00.000000000 Z
11
+ date: 2025-01-13 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: actionpack
@@ -63,6 +64,7 @@ executables: []
63
64
  extensions: []
64
65
  extra_rdoc_files: []
65
66
  files:
67
+ - README.md
66
68
  - lib/generators/superglue/install/install_generator.rb
67
69
  - lib/generators/superglue/install/templates/application.json.props
68
70
  - lib/generators/superglue/install/templates/initializer.rb
@@ -107,10 +109,11 @@ files:
107
109
  - lib/superglue.rb
108
110
  - lib/superglue/helpers.rb
109
111
  - lib/superglue/redirection.rb
110
- homepage: https://github.com/thoughtbot/superglue/
112
+ homepage: https://github.com/thoughtbot/superglue_rails/
111
113
  licenses:
112
114
  - MIT
113
115
  metadata: {}
116
+ post_install_message:
114
117
  rdoc_options: []
115
118
  require_paths:
116
119
  - lib
@@ -125,7 +128,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
128
  - !ruby/object:Gem::Version
126
129
  version: '0'
127
130
  requirements: []
128
- rubygems_version: 3.6.2
131
+ rubygems_version: 3.5.3
132
+ signing_key:
129
133
  specification_version: 4
130
134
  summary: Rails integration for SuperglueJS
131
135
  test_files: []