superglue 2.0.0.alpha.2 → 2.0.0.alpha.9
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 +4 -4
- data/app/channels/superglue/streams/broadcasts.rb +3 -0
- data/app/channels/superglue/streams/stream_name.rb +3 -0
- data/app/channels/superglue/streams_channel.rb +3 -0
- data/app/controllers/concerns/superglue/request_id_tracking.rb +3 -0
- data/app/helpers/superglue/streams_helper.rb +4 -1
- data/app/jobs/superglue/streams/action_broadcast_job.rb +3 -0
- data/app/jobs/superglue/streams/broadcast_stream_job.rb +3 -0
- data/app/models/concerns/superglue/broadcastable.rb +4 -1
- data/app/models/superglue/debouncer.rb +3 -0
- data/app/models/superglue/thread_debouncer.rb +3 -0
- data/lib/generators/superglue/install/install_generator.rb +2 -2
- data/lib/generators/superglue/install/templates/application.json.props +4 -1
- data/lib/generators/superglue/install/templates/js/application.jsx +1 -1
- data/lib/generators/superglue/install/templates/js/application_visit.js +1 -1
- data/lib/generators/superglue/install/templates/js/inputs.jsx +1 -1
- data/lib/generators/superglue/install/templates/js/store.js +3 -2
- data/lib/generators/superglue/install/templates/ts/application.tsx +10 -9
- data/lib/generators/superglue/install/templates/ts/application_visit.ts +1 -1
- data/lib/generators/superglue/install/templates/ts/inputs.tsx +150 -123
- data/lib/generators/superglue/install/templates/ts/store.ts +2 -1
- data/lib/generators/superglue/view_collection/templates/ts/edit.tsx +4 -4
- data/lib/generators/superglue/view_collection/templates/ts/new.tsx +4 -4
- data/lib/superglue/rendering.rb +6 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a65a2601f089ebb03db5e2c49f580e0e44741e1890ab03b020266bdb7a59e31
|
4
|
+
data.tar.gz: 2055cd1e038925c61f729d601c528d83fb084e250638c11092bc1b66f9dcbd17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b413e70eb67e522a693420788645ec18f7bed6595fbc2f7914f931885ca909ec93257be8acee59b44df59fed6902c7fff48546c5f9a464d2ee03f81be79bbec
|
7
|
+
data.tar.gz: c929885777b7393d32bdb26452aa6df819ed222b27731f84cfdd5fdab322453c51e9a23b3a0242e9dda88d5610b62ccdda852d6287ea265a88e2cc12b51d19ee
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# This file was ported from the amazing folks at turbo-rails
|
2
|
+
# You can find its MIT License here: https://github.com/hotwired/turbo-rails/blob/main/MIT-LICENSE
|
3
|
+
|
1
4
|
module Superglue::Streams::Broadcasts
|
2
5
|
def broadcast_save_to(*streamables, **opts)
|
3
6
|
broadcast_action_to(*streamables, action: :save, **opts)
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# This file was ported from the amazing folks at turbo-rails
|
2
|
+
# You can find its MIT License here: https://github.com/hotwired/turbo-rails/blob/main/MIT-LICENSE
|
3
|
+
|
1
4
|
module Superglue::Streams::StreamName
|
2
5
|
def verified_stream_name(signed_stream_name)
|
3
6
|
Superglue.signed_stream_verifier.verified signed_stream_name
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# This file was ported from the amazing folks at turbo-rails
|
2
|
+
# You can find its MIT License here: https://github.com/hotwired/turbo-rails/blob/main/MIT-LICENSE
|
3
|
+
|
1
4
|
class Superglue::StreamsChannel < ActionCable::Channel::Base
|
2
5
|
extend Superglue::Streams::StreamName
|
3
6
|
extend Superglue::Streams::Broadcasts
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# This file was ported from the amazing folks at turbo-rails
|
2
|
+
# You can find its MIT License here: https://github.com/hotwired/turbo-rails/blob/main/MIT-LICENSE
|
3
|
+
|
1
4
|
module Superglue::StreamsHelper
|
2
5
|
def stream_from_props(*streamables, **attributes)
|
3
6
|
raise ArgumentError, "streamables can't be blank" unless streamables.any?(&:present?)
|
@@ -33,7 +36,7 @@ module Superglue::StreamsHelper
|
|
33
36
|
broadcast_action_props(action: "append", model:, target:, options:, **rendering)
|
34
37
|
end
|
35
38
|
|
36
|
-
def broadcast_save_props(model: nil,
|
39
|
+
def broadcast_save_props(model: nil, target: nil, options: {}, **rendering)
|
37
40
|
if model && !target
|
38
41
|
target = fragment_id(model)
|
39
42
|
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# This file was ported from the amazing folks at turbo-rails
|
2
|
+
# You can find its MIT License here: https://github.com/hotwired/turbo-rails/blob/main/MIT-LICENSE
|
3
|
+
|
1
4
|
class Superglue::Streams::ActionBroadcastJob < ActiveJob::Base
|
2
5
|
discard_on ActiveJob::DeserializationError
|
3
6
|
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# This file was ported from the amazing folks at turbo-rails
|
2
|
+
# You can find its MIT License here: https://github.com/hotwired/turbo-rails/blob/main/MIT-LICENSE
|
3
|
+
|
1
4
|
class Superglue::Streams::BroadcastStreamJob < ActiveJob::Base
|
2
5
|
discard_on ActiveJob::DeserializationError
|
3
6
|
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# This file was ported from the amazing folks at turbo-rails
|
2
|
+
# You can find its MIT License here: https://github.com/hotwired/turbo-rails/blob/main/MIT-LICENSE
|
3
|
+
|
1
4
|
module Superglue::Broadcastable
|
2
5
|
extend ActiveSupport::Concern
|
3
6
|
|
@@ -129,7 +132,7 @@ module Superglue::Broadcastable
|
|
129
132
|
def broadcast_target_default
|
130
133
|
self.class.broadcast_target_default
|
131
134
|
end
|
132
|
-
|
135
|
+
|
133
136
|
private
|
134
137
|
|
135
138
|
def extract_options_and_add_target(rendering = {}, target: broadcast_target_default)
|
@@ -40,10 +40,10 @@ module Superglue
|
|
40
40
|
insert_jsx_rendering_defaults
|
41
41
|
|
42
42
|
say "Installing Superglue and friends"
|
43
|
-
run "yarn add react react-dom @reduxjs/toolkit react-redux @thoughtbot/superglue@2.0.0-alpha.
|
43
|
+
run "yarn add react react-dom @reduxjs/toolkit react-redux @thoughtbot/superglue@2.0.0-alpha.8"
|
44
44
|
|
45
45
|
if use_typescript
|
46
|
-
run "yarn add -D @types/react-dom @types/react @types/node @thoughtbot/candy_wrapper"
|
46
|
+
run "yarn add -D @types/react-dom @types/react @types/node @thoughtbot/candy_wrapper@0.0.4"
|
47
47
|
end
|
48
48
|
|
49
49
|
say "Superglue is Installed! 🎉", :green
|
@@ -5,7 +5,7 @@ import { buildVisitAndRemote } from "./application_visit"
|
|
5
5
|
import { pageIdentifierToPageComponent } from "./page_to_page_mapping"
|
6
6
|
import { store } from "./store"
|
7
7
|
|
8
|
-
if (typeof window !== "undefined") {
|
8
|
+
if (typeof window !== "undefined" && window.SUPERGLUE_INITIAL_PAGE_STATE) {
|
9
9
|
document.addEventListener("DOMContentLoaded", function() {
|
10
10
|
const appEl = document.getElementById("app")
|
11
11
|
const location = window.location
|
@@ -9,7 +9,7 @@ import { visit, remote } from "@thoughtbot/superglue/action_creators"
|
|
9
9
|
* bar. This file also adds support for data-sg-remote.
|
10
10
|
*/
|
11
11
|
export const buildVisitAndRemote = (ref, store) => {
|
12
|
-
const appRemote = (path, { dataset, ...options }) => {
|
12
|
+
const appRemote = (path, { dataset, ...options } = {}) => {
|
13
13
|
/**
|
14
14
|
* You can make use of `dataset` to add custom UJS options.
|
15
15
|
* If you are implementing a progress bar, you can selectively
|
@@ -7,7 +7,7 @@
|
|
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, {
|
10
|
+
import React, { createContext, useContext, useMemo } from 'react'
|
11
11
|
export const ValidationContext = createContext({})
|
12
12
|
export const useErrorMessage = (errorKey) => {
|
13
13
|
const errors = useContext(ValidationContext)
|
@@ -8,7 +8,7 @@ import {
|
|
8
8
|
rootReducer
|
9
9
|
} from "@thoughtbot/superglue"
|
10
10
|
|
11
|
-
const { pages, superglue } = rootReducer
|
11
|
+
const { pages, superglue, fragments } = rootReducer
|
12
12
|
|
13
13
|
export const store = configureStore({
|
14
14
|
devTools: process.env.NODE_ENV !== "production",
|
@@ -21,7 +21,8 @@ export const store = configureStore({
|
|
21
21
|
reducer: {
|
22
22
|
superglue,
|
23
23
|
pages,
|
24
|
-
flash: flashSlice.reducer
|
24
|
+
flash: flashSlice.reducer,
|
25
|
+
fragments,
|
25
26
|
}
|
26
27
|
})
|
27
28
|
|
@@ -1,15 +1,17 @@
|
|
1
|
-
import React from
|
2
|
-
import { createRoot } from
|
3
|
-
import { Application,
|
4
|
-
import { buildVisitAndRemote } from
|
5
|
-
import { pageIdentifierToPageComponent } from
|
6
|
-
import { store } from
|
1
|
+
import React from "react";
|
2
|
+
import { createRoot } from "react-dom/client";
|
3
|
+
import { Application, SaveResponse } from "@thoughtbot/superglue";
|
4
|
+
import { buildVisitAndRemote } from "./application_visit";
|
5
|
+
import { pageIdentifierToPageComponent } from "./page_to_page_mapping";
|
6
|
+
import { store } from "./store";
|
7
7
|
|
8
8
|
declare global {
|
9
|
-
interface Window {
|
9
|
+
interface Window {
|
10
|
+
SUPERGLUE_INITIAL_PAGE_STATE: SaveResponse;
|
11
|
+
}
|
10
12
|
}
|
11
13
|
|
12
|
-
if (typeof window !== "undefined") {
|
14
|
+
if (typeof window !== "undefined" && window.SUPERGLUE_INITIAL_PAGE_STATE) {
|
13
15
|
document.addEventListener("DOMContentLoaded", function () {
|
14
16
|
const appEl = document.getElementById("app");
|
15
17
|
const location = window.location;
|
@@ -37,4 +39,3 @@ if (typeof window !== "undefined") {
|
|
37
39
|
}
|
38
40
|
});
|
39
41
|
}
|
40
|
-
|
@@ -18,7 +18,7 @@ export const buildVisitAndRemote: BuildVisitAndRemote = (
|
|
18
18
|
ref,
|
19
19
|
store: SuperglueStore
|
20
20
|
) => {
|
21
|
-
const appRemote: ApplicationRemote = (path, { dataset, ...options }) => {
|
21
|
+
const appRemote: ApplicationRemote = (path, { dataset, ...options } = {}) => {
|
22
22
|
/**
|
23
23
|
* You can make use of `dataset` to add custom UJS options.
|
24
24
|
* If you are implementing a progress bar, you can selectively
|
@@ -7,59 +7,86 @@
|
|
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, { createContext, ReactNode, useContext, useMemo } from "react";
|
11
|
+
|
12
|
+
export type {
|
13
|
+
CheckboxField as RailsCheckboxFieldProps,
|
14
|
+
CollectionCheckboxesField as RailsCollectionCheckboxesFieldProps,
|
15
|
+
CollectionRadioButtonsField as RailsCollectionRadioButtonsFieldProps,
|
16
|
+
ColorField as RailsColorFieldProps,
|
17
|
+
DateField as RailsDateFieldProps,
|
18
|
+
DateTimeLocalField as RailsDateTimeLocalFieldProps,
|
19
|
+
EmailField as RailsEmailFieldProps,
|
20
|
+
FileField as RailsFileFieldProps,
|
21
|
+
HiddenField as RailsHiddenFieldProps,
|
22
|
+
MonthField as RailsMonthFieldProps,
|
23
|
+
NumberField as RailsNumberFieldProps,
|
24
|
+
PasswordField as RailsPasswordFieldProps,
|
25
|
+
RangeField as RailsRangeFieldProps,
|
26
|
+
SearchField as RailsSearchFieldProps,
|
27
|
+
Select as RailsSelectProps,
|
28
|
+
SubmitProps as RailsSubmitButtonProps,
|
29
|
+
TelField as RailsTelFieldProps,
|
30
|
+
TextArea as RailsTextAreaProps,
|
31
|
+
TextField as RailsTextFieldProps,
|
32
|
+
TimeField as RailsTimeFieldProps,
|
33
|
+
UrlField as RailsUrlFieldProps,
|
34
|
+
HTMLFormProps as RailsHTMLFormProps,
|
35
|
+
ValidationErrors,
|
36
|
+
} from "@thoughtbot/candy_wrapper";
|
10
37
|
|
11
|
-
import React, { ReactNode, useContext, createContext, useMemo } from 'react'
|
12
38
|
import {
|
13
39
|
CheckboxField as RailsCheckboxField,
|
14
40
|
CollectionCheckboxesField as RailsCollectionCheckboxesField,
|
15
|
-
HiddenField as RailsHiddenField,
|
16
41
|
CollectionRadioButtonsField as RailsCollectionRadioButtonsField,
|
17
42
|
ColorField as RailsColorField,
|
18
43
|
DateField as RailsDateField,
|
19
44
|
DateTimeLocalField as RailsDateTimeLocalField,
|
20
45
|
EmailField as RailsEmailField,
|
46
|
+
FileField as RailsFileField,
|
47
|
+
HiddenField as RailsHiddenField,
|
21
48
|
MonthField as RailsMonthField,
|
22
49
|
NumberField as RailsNumberField,
|
23
50
|
PasswordField as RailsPasswordField,
|
24
51
|
RangeField as RailsRangeField,
|
25
52
|
SearchField as RailsSearchField,
|
26
53
|
Select as RailsSelect,
|
54
|
+
SubmitProps as RailsSubmitButton,
|
27
55
|
TelField as RailsTelField,
|
28
|
-
|
56
|
+
TextArea as RailsTextArea,
|
29
57
|
TextField as RailsTextField,
|
30
58
|
TimeField as RailsTimeField,
|
31
59
|
UrlField as RailsUrlField,
|
32
|
-
|
60
|
+
HTMLFormProps as RailsHTMLFormProps,
|
33
61
|
ValidationErrors,
|
34
|
-
|
35
|
-
} from '@thoughtbot/candy_wrapper'
|
62
|
+
} from "@thoughtbot/candy_wrapper";
|
36
63
|
|
37
|
-
export const ValidationContext = createContext<ValidationErrors>({})
|
64
|
+
export const ValidationContext = createContext<ValidationErrors>({});
|
38
65
|
|
39
66
|
export const useErrorMessage = (errorKey?: string) => {
|
40
|
-
const errors = useContext(ValidationContext)
|
67
|
+
const errors = useContext(ValidationContext);
|
41
68
|
|
42
69
|
return useMemo(() => {
|
43
70
|
if (!errorKey) {
|
44
|
-
return null
|
71
|
+
return null;
|
45
72
|
}
|
46
73
|
|
47
|
-
const validationError = errors[errorKey]
|
48
|
-
const hasErrors = errorKey && validationError
|
74
|
+
const validationError = errors[errorKey];
|
75
|
+
const hasErrors = errorKey && validationError;
|
49
76
|
|
50
77
|
if (!hasErrors) {
|
51
|
-
return null
|
78
|
+
return null;
|
52
79
|
}
|
53
80
|
|
54
81
|
const errorMessages = Array.isArray(validationError)
|
55
82
|
? validationError
|
56
|
-
: [validationError]
|
83
|
+
: [validationError];
|
57
84
|
|
58
|
-
return errorMessages.join(
|
59
|
-
}, [errors, errorKey])
|
60
|
-
}
|
85
|
+
return errorMessages.join(" ");
|
86
|
+
}, [errors, errorKey]);
|
87
|
+
};
|
61
88
|
|
62
|
-
export type ExtrasProps = Record<string, RailsHiddenField
|
89
|
+
export type ExtrasProps = Record<string, RailsHiddenField>;
|
63
90
|
|
64
91
|
/**
|
65
92
|
* Extras renders the hidden inputs generated by form_props.
|
@@ -68,24 +95,24 @@ export type ExtrasProps = Record<string, RailsHiddenField>
|
|
68
95
|
* utf8, crsf_token, _method
|
69
96
|
*/
|
70
97
|
export const Extras = (hiddenInputAttributes: ExtrasProps) => {
|
71
|
-
const hiddenProps = Object.values(hiddenInputAttributes)
|
98
|
+
const hiddenProps = Object.values(hiddenInputAttributes);
|
72
99
|
const hiddenInputs = hiddenProps.map((props: RailsHiddenField) => (
|
73
100
|
<input {...props} type="hidden" key={props.name} />
|
74
|
-
))
|
101
|
+
));
|
75
102
|
|
76
|
-
return <>{hiddenInputs}
|
77
|
-
}
|
103
|
+
return <>{hiddenInputs}</>;
|
104
|
+
};
|
78
105
|
|
79
|
-
export interface FormProps<T =
|
80
|
-
extras: ExtrasProps
|
81
|
-
inputs: T
|
82
|
-
form:
|
106
|
+
export interface FormProps<T = object> {
|
107
|
+
extras: ExtrasProps;
|
108
|
+
inputs: T;
|
109
|
+
form: RailsHTMLFormProps;
|
83
110
|
}
|
84
111
|
|
85
112
|
type FormElementProps = React.FormHTMLAttributes<HTMLFormElement> & {
|
86
|
-
extras: ExtrasProps
|
87
|
-
validationErrors?: ValidationErrors
|
88
|
-
}
|
113
|
+
extras: ExtrasProps;
|
114
|
+
validationErrors?: ValidationErrors;
|
115
|
+
};
|
89
116
|
/**
|
90
117
|
* A basic form component that supports inline errors.
|
91
118
|
*
|
@@ -105,8 +132,8 @@ export const Form = ({
|
|
105
132
|
{children}
|
106
133
|
</ValidationContext.Provider>
|
107
134
|
</form>
|
108
|
-
)
|
109
|
-
}
|
135
|
+
);
|
136
|
+
};
|
110
137
|
|
111
138
|
/**
|
112
139
|
* An inline error component.
|
@@ -115,17 +142,17 @@ export const Form = ({
|
|
115
142
|
* Please modify this to your liking.
|
116
143
|
*/
|
117
144
|
export const FieldError = ({ errorKey }: { errorKey: string | undefined }) => {
|
118
|
-
const errorMessage = useErrorMessage(errorKey)
|
145
|
+
const errorMessage = useErrorMessage(errorKey);
|
119
146
|
|
120
|
-
return <span>{errorMessage}</span
|
121
|
-
}
|
147
|
+
return <span>{errorMessage}</span>;
|
148
|
+
};
|
122
149
|
|
123
150
|
export type FieldBaseProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
124
|
-
id?: string
|
125
|
-
label: string
|
126
|
-
errorKey?: string
|
127
|
-
children?: ReactNode
|
128
|
-
}
|
151
|
+
id?: string;
|
152
|
+
label: string;
|
153
|
+
errorKey?: string;
|
154
|
+
children?: ReactNode;
|
155
|
+
};
|
129
156
|
|
130
157
|
/**
|
131
158
|
* A Field component.
|
@@ -144,13 +171,13 @@ export const FieldBase = ({
|
|
144
171
|
{children || <input {...props} />}
|
145
172
|
<FieldError errorKey={errorKey} />
|
146
173
|
</>
|
147
|
-
)
|
148
|
-
}
|
174
|
+
);
|
175
|
+
};
|
149
176
|
|
150
177
|
type InputProps = {
|
151
|
-
label: string
|
152
|
-
errorKey?: string
|
153
|
-
}
|
178
|
+
label: string;
|
179
|
+
errorKey?: string;
|
180
|
+
};
|
154
181
|
|
155
182
|
/**
|
156
183
|
* A checkbox component.
|
@@ -158,7 +185,7 @@ type InputProps = {
|
|
158
185
|
* Designed to work with a payload form_props's [checkbox helper](https://github.com/thoughtbot/form_props?tab=readme-ov-file#checkbox-helper).
|
159
186
|
* Mimics the rails equivalent. Please modify to your liking.
|
160
187
|
*/
|
161
|
-
type CheckboxProps = RailsCheckboxField & InputProps
|
188
|
+
type CheckboxProps = RailsCheckboxField & InputProps;
|
162
189
|
export const Checkbox = ({
|
163
190
|
type: _type,
|
164
191
|
includeHidden,
|
@@ -166,7 +193,7 @@ export const Checkbox = ({
|
|
166
193
|
errorKey,
|
167
194
|
...rest
|
168
195
|
}: CheckboxProps) => {
|
169
|
-
const { name } = rest
|
196
|
+
const { name } = rest;
|
170
197
|
return (
|
171
198
|
<FieldBase {...rest} errorKey={errorKey}>
|
172
199
|
{includeHidden && (
|
@@ -179,11 +206,11 @@ export const Checkbox = ({
|
|
179
206
|
)}
|
180
207
|
<input type="checkbox" {...rest}></input>
|
181
208
|
</FieldBase>
|
182
|
-
)
|
183
|
-
}
|
209
|
+
);
|
210
|
+
};
|
184
211
|
|
185
212
|
type CollectionCheckboxesFieldProps = RailsCollectionCheckboxesField &
|
186
|
-
InputProps
|
213
|
+
InputProps;
|
187
214
|
|
188
215
|
/**
|
189
216
|
* A collection checkbox component.
|
@@ -198,29 +225,29 @@ export const CollectionCheckboxes = ({
|
|
198
225
|
errorKey,
|
199
226
|
}: CollectionCheckboxesFieldProps) => {
|
200
227
|
if (collection.length == 0) {
|
201
|
-
return null
|
228
|
+
return null;
|
202
229
|
}
|
203
230
|
|
204
231
|
const checkboxes = collection.map((options) => {
|
205
|
-
return <Checkbox {...options} key={options.id}
|
206
|
-
})
|
232
|
+
return <Checkbox {...options} key={options.id} />;
|
233
|
+
});
|
207
234
|
|
208
|
-
const { name } = collection[0]
|
235
|
+
const { name } = collection[0];
|
209
236
|
|
210
237
|
return (
|
211
238
|
<>
|
212
239
|
{includeHidden && (
|
213
|
-
<input type="hidden" name={name} defaultValue={
|
240
|
+
<input type="hidden" name={name} defaultValue={""} autoComplete="off" />
|
214
241
|
)}
|
215
242
|
<label>{label}</label>
|
216
243
|
{checkboxes}
|
217
244
|
<FieldError errorKey={errorKey} />
|
218
245
|
</>
|
219
|
-
)
|
220
|
-
}
|
246
|
+
);
|
247
|
+
};
|
221
248
|
|
222
249
|
type CollectionRadioButtonsFieldProps = RailsCollectionRadioButtonsField &
|
223
|
-
InputProps
|
250
|
+
InputProps;
|
224
251
|
|
225
252
|
/**
|
226
253
|
* A collection radio button component.
|
@@ -235,7 +262,7 @@ export const CollectionRadioButtons = ({
|
|
235
262
|
errorKey,
|
236
263
|
}: CollectionRadioButtonsFieldProps) => {
|
237
264
|
if (collection.length == 0) {
|
238
|
-
return null
|
265
|
+
return null;
|
239
266
|
}
|
240
267
|
|
241
268
|
const radioButtons = collection.map((options) => {
|
@@ -244,26 +271,26 @@ export const CollectionRadioButtons = ({
|
|
244
271
|
<input {...options} type="radio" />
|
245
272
|
<label htmlFor={options.id}>{options.label}</label>
|
246
273
|
</div>
|
247
|
-
)
|
248
|
-
})
|
274
|
+
);
|
275
|
+
});
|
249
276
|
|
250
|
-
const { name } = collection[0]
|
277
|
+
const { name } = collection[0];
|
251
278
|
|
252
279
|
return (
|
253
280
|
<>
|
254
281
|
{includeHidden && (
|
255
|
-
<input type="hidden" name={name} defaultValue={
|
282
|
+
<input type="hidden" name={name} defaultValue={""} autoComplete="off" />
|
256
283
|
)}
|
257
284
|
<label>{label}</label>
|
258
285
|
{radioButtons}
|
259
286
|
<FieldError errorKey={errorKey} />
|
260
287
|
</>
|
261
|
-
)
|
262
|
-
}
|
288
|
+
);
|
289
|
+
};
|
263
290
|
|
264
291
|
export type TextFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
265
292
|
RailsTextField &
|
266
|
-
InputProps
|
293
|
+
InputProps;
|
267
294
|
|
268
295
|
/**
|
269
296
|
* A text field component.
|
@@ -272,12 +299,12 @@ export type TextFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
272
299
|
* Mimics the rails equivalent. Please modify to your liking.
|
273
300
|
*/
|
274
301
|
export const TextField = ({ type: _type, ...rest }: TextFieldProps) => {
|
275
|
-
return <FieldBase {...rest} type="text"
|
276
|
-
}
|
302
|
+
return <FieldBase {...rest} type="text" />;
|
303
|
+
};
|
277
304
|
|
278
305
|
export type EmailFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
279
306
|
RailsEmailField &
|
280
|
-
InputProps
|
307
|
+
InputProps;
|
281
308
|
|
282
309
|
/**
|
283
310
|
* A email field component.
|
@@ -286,12 +313,12 @@ export type EmailFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
286
313
|
* Mimics the rails equivalent. Please modify to your liking.
|
287
314
|
*/
|
288
315
|
export const EmailField = ({ type: _type, ...rest }: EmailFieldProps) => {
|
289
|
-
return <FieldBase {...rest} type="email"
|
290
|
-
}
|
316
|
+
return <FieldBase {...rest} type="email" />;
|
317
|
+
};
|
291
318
|
|
292
319
|
export type ColorFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
293
320
|
RailsColorField &
|
294
|
-
InputProps
|
321
|
+
InputProps;
|
295
322
|
|
296
323
|
/**
|
297
324
|
* A color field component.
|
@@ -300,12 +327,12 @@ export type ColorFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
300
327
|
* Mimics the rails equivalent. Please modify to your liking.
|
301
328
|
*/
|
302
329
|
export const ColorField = ({ type: _type, ...rest }: ColorFieldProps) => {
|
303
|
-
return <FieldBase {...rest} type="color"
|
304
|
-
}
|
330
|
+
return <FieldBase {...rest} type="color" />;
|
331
|
+
};
|
305
332
|
|
306
333
|
export type DateFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
307
334
|
RailsDateField &
|
308
|
-
InputProps
|
335
|
+
InputProps;
|
309
336
|
|
310
337
|
/**
|
311
338
|
* A date field component.
|
@@ -314,13 +341,13 @@ export type DateFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
314
341
|
* Mimics the rails equivalent. Please modify to your liking.
|
315
342
|
*/
|
316
343
|
export const DateField = ({ type: _type, ...rest }: DateFieldProps) => {
|
317
|
-
return <FieldBase {...rest} type="date"
|
318
|
-
}
|
344
|
+
return <FieldBase {...rest} type="date" />;
|
345
|
+
};
|
319
346
|
|
320
347
|
export type DateTimeLocalFieldProps =
|
321
348
|
React.InputHTMLAttributes<HTMLInputElement> &
|
322
349
|
RailsDateTimeLocalField &
|
323
|
-
InputProps
|
350
|
+
InputProps;
|
324
351
|
|
325
352
|
/**
|
326
353
|
* A date field component.
|
@@ -332,12 +359,12 @@ export const DateTimeLocalField = ({
|
|
332
359
|
type: _type,
|
333
360
|
...rest
|
334
361
|
}: DateTimeLocalFieldProps) => {
|
335
|
-
return <FieldBase {...rest} type="datetime-local"
|
336
|
-
}
|
362
|
+
return <FieldBase {...rest} type="datetime-local" />;
|
363
|
+
};
|
337
364
|
|
338
365
|
export type SearchFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
339
366
|
RailsSearchField &
|
340
|
-
InputProps
|
367
|
+
InputProps;
|
341
368
|
|
342
369
|
/**
|
343
370
|
* A search field component.
|
@@ -346,12 +373,12 @@ export type SearchFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
346
373
|
* Mimics the rails equivalent. Please modify to your liking.
|
347
374
|
*/
|
348
375
|
export const SearchField = ({ type: _type, ...rest }: SearchFieldProps) => {
|
349
|
-
return <FieldBase {...rest} type="search"
|
350
|
-
}
|
376
|
+
return <FieldBase {...rest} type="search" />;
|
377
|
+
};
|
351
378
|
|
352
379
|
export type TelFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
353
380
|
RailsTelField &
|
354
|
-
InputProps
|
381
|
+
InputProps;
|
355
382
|
|
356
383
|
/**
|
357
384
|
* A tel field component.
|
@@ -360,12 +387,12 @@ export type TelFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
360
387
|
* Mimics the rails equivalent. Please modify to your liking.
|
361
388
|
*/
|
362
389
|
export const TelField = ({ type: _type, ...rest }: TelFieldProps) => {
|
363
|
-
return <FieldBase {...rest} type="tel"
|
364
|
-
}
|
390
|
+
return <FieldBase {...rest} type="tel" />;
|
391
|
+
};
|
365
392
|
|
366
393
|
export type UrlFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
367
394
|
RailsUrlField &
|
368
|
-
InputProps
|
395
|
+
InputProps;
|
369
396
|
|
370
397
|
/**
|
371
398
|
* A url field component.
|
@@ -374,12 +401,12 @@ export type UrlFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
374
401
|
* Mimics the rails equivalent. Please modify to your liking.
|
375
402
|
*/
|
376
403
|
export const UrlField = ({ type: _type, ...rest }: UrlFieldProps) => {
|
377
|
-
return <FieldBase {...rest} type="url"
|
378
|
-
}
|
404
|
+
return <FieldBase {...rest} type="url" />;
|
405
|
+
};
|
379
406
|
|
380
407
|
export type MonthFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
381
408
|
RailsMonthField &
|
382
|
-
InputProps
|
409
|
+
InputProps;
|
383
410
|
|
384
411
|
/**
|
385
412
|
* A month field component.
|
@@ -388,12 +415,12 @@ export type MonthFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
388
415
|
* Mimics the rails equivalent. Please modify to your liking.
|
389
416
|
*/
|
390
417
|
export const MonthField = ({ type: _type, ...rest }: MonthFieldProps) => {
|
391
|
-
return <FieldBase {...rest} type="month"
|
392
|
-
}
|
418
|
+
return <FieldBase {...rest} type="month" />;
|
419
|
+
};
|
393
420
|
|
394
421
|
export type TimeFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
395
422
|
RailsTimeField &
|
396
|
-
InputProps
|
423
|
+
InputProps;
|
397
424
|
|
398
425
|
/**
|
399
426
|
* A time field component.
|
@@ -402,12 +429,12 @@ export type TimeFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
402
429
|
* Mimics the rails equivalent. Please modify to your liking.
|
403
430
|
*/
|
404
431
|
export const TimeField = ({ type: _type, ...rest }: TimeFieldProps) => {
|
405
|
-
return <FieldBase {...rest} type="time"
|
406
|
-
}
|
432
|
+
return <FieldBase {...rest} type="time" />;
|
433
|
+
};
|
407
434
|
|
408
435
|
export type NumberFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
409
436
|
RailsNumberField &
|
410
|
-
InputProps
|
437
|
+
InputProps;
|
411
438
|
/**
|
412
439
|
* A number field component.
|
413
440
|
*
|
@@ -415,12 +442,12 @@ export type NumberFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
415
442
|
* Mimics the rails equivalent. Please modify to your liking.
|
416
443
|
*/
|
417
444
|
export const NumberField = ({ type: _type, ...rest }: NumberFieldProps) => {
|
418
|
-
return <FieldBase {...rest} type="number"
|
419
|
-
}
|
445
|
+
return <FieldBase {...rest} type="number" />;
|
446
|
+
};
|
420
447
|
|
421
448
|
export type RangeFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
422
449
|
RailsRangeField &
|
423
|
-
InputProps
|
450
|
+
InputProps;
|
424
451
|
/**
|
425
452
|
* A range field component.
|
426
453
|
*
|
@@ -428,12 +455,12 @@ export type RangeFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
428
455
|
* Mimics the rails equivalent. Please modify to your liking.
|
429
456
|
*/
|
430
457
|
export const RangeField = ({ type: _type, ...rest }: RangeFieldProps) => {
|
431
|
-
return <FieldBase {...rest} type="range"
|
432
|
-
}
|
458
|
+
return <FieldBase {...rest} type="range" />;
|
459
|
+
};
|
433
460
|
|
434
461
|
export type PasswordFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
435
462
|
RailsPasswordField &
|
436
|
-
InputProps
|
463
|
+
InputProps;
|
437
464
|
/**
|
438
465
|
* A password field component.
|
439
466
|
*
|
@@ -441,12 +468,12 @@ export type PasswordFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
441
468
|
* Mimics the rails equivalent. Please modify to your liking.
|
442
469
|
*/
|
443
470
|
export const PasswordField = ({ type: _type, ...rest }: PasswordFieldProps) => {
|
444
|
-
return <FieldBase {...rest} type="password"
|
445
|
-
}
|
471
|
+
return <FieldBase {...rest} type="password" />;
|
472
|
+
};
|
446
473
|
|
447
474
|
export type SelectProps = React.SelectHTMLAttributes<HTMLSelectElement> &
|
448
475
|
RailsSelect &
|
449
|
-
InputProps
|
476
|
+
InputProps;
|
450
477
|
/**
|
451
478
|
* A select component.
|
452
479
|
*
|
@@ -467,26 +494,26 @@ export const Select = ({
|
|
467
494
|
type: _type,
|
468
495
|
...rest
|
469
496
|
}: SelectProps) => {
|
470
|
-
const addHidden = includeHidden && multiple
|
497
|
+
const addHidden = includeHidden && multiple;
|
471
498
|
|
472
499
|
const optionElements = options.map((item) => {
|
473
|
-
if (
|
500
|
+
if ("options" in item) {
|
474
501
|
return (
|
475
502
|
<optgroup label={item.label} key={item.label}>
|
476
503
|
{item.options.map((opt) => (
|
477
504
|
<option key={opt.label} {...opt} />
|
478
505
|
))}
|
479
506
|
</optgroup>
|
480
|
-
)
|
507
|
+
);
|
481
508
|
} else {
|
482
|
-
return <option key={item.label} {...item}
|
509
|
+
return <option key={item.label} {...item} />;
|
483
510
|
}
|
484
|
-
})
|
511
|
+
});
|
485
512
|
|
486
513
|
return (
|
487
514
|
<>
|
488
515
|
{addHidden && (
|
489
|
-
<input type="hidden" name={name} value={
|
516
|
+
<input type="hidden" name={name} value={""} autoComplete="off" />
|
490
517
|
)}
|
491
518
|
<FieldBase label={label} errorKey={errorKey} id={id}>
|
492
519
|
<select name={name} id={id} multiple={multiple} {...rest}>
|
@@ -495,12 +522,12 @@ export const Select = ({
|
|
495
522
|
</select>
|
496
523
|
</FieldBase>
|
497
524
|
</>
|
498
|
-
)
|
499
|
-
}
|
525
|
+
);
|
526
|
+
};
|
500
527
|
|
501
528
|
export type TextAreaProps = React.InputHTMLAttributes<HTMLTextAreaElement> &
|
502
529
|
RailsTextArea &
|
503
|
-
InputProps
|
530
|
+
InputProps;
|
504
531
|
/**
|
505
532
|
* A text area component.
|
506
533
|
*
|
@@ -508,18 +535,18 @@ export type TextAreaProps = React.InputHTMLAttributes<HTMLTextAreaElement> &
|
|
508
535
|
* Mimics the rails equivalent. Please modify to your liking.
|
509
536
|
*/
|
510
537
|
export const TextArea = ({ type: _type, errorKey, ...rest }: TextAreaProps) => {
|
511
|
-
const { label } = rest
|
538
|
+
const { label } = rest;
|
512
539
|
|
513
540
|
return (
|
514
541
|
<FieldBase label={label} errorKey={errorKey} id={rest.id}>
|
515
542
|
<textarea {...rest} />
|
516
543
|
</FieldBase>
|
517
|
-
)
|
518
|
-
}
|
544
|
+
);
|
545
|
+
};
|
519
546
|
|
520
547
|
export type FileFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
521
548
|
RailsFileField &
|
522
|
-
InputProps
|
549
|
+
InputProps;
|
523
550
|
|
524
551
|
/**
|
525
552
|
* A file field component.
|
@@ -528,11 +555,11 @@ export type FileFieldProps = React.InputHTMLAttributes<HTMLInputElement> &
|
|
528
555
|
* Mimics the rails equivalent. Please modify to your liking.
|
529
556
|
*/
|
530
557
|
export const FileField = ({ type: _type, ...rest }: FileFieldProps) => {
|
531
|
-
return <FieldBase {...rest} type="file"
|
532
|
-
}
|
558
|
+
return <FieldBase {...rest} type="file" />;
|
559
|
+
};
|
533
560
|
|
534
561
|
export type SubmitButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
|
535
|
-
RailsSubmitButton
|
562
|
+
RailsSubmitButton;
|
536
563
|
|
537
564
|
/**
|
538
565
|
* A SubmitButton component.
|
@@ -547,8 +574,8 @@ export const SubmitButton = ({
|
|
547
574
|
}: SubmitButtonProps) => {
|
548
575
|
return (
|
549
576
|
<button {...rest} type="submit">
|
550
|
-
{
|
551
|
-
{text}{
|
577
|
+
{" "}
|
578
|
+
{text}{" "}
|
552
579
|
</button>
|
553
|
-
)
|
554
|
-
}
|
580
|
+
);
|
581
|
+
};
|
@@ -8,7 +8,7 @@ import {
|
|
8
8
|
rootReducer,
|
9
9
|
} from "@thoughtbot/superglue";
|
10
10
|
|
11
|
-
const { pages, superglue } = rootReducer;
|
11
|
+
const { pages, superglue, fragments } = rootReducer;
|
12
12
|
|
13
13
|
export const store = configureStore({
|
14
14
|
devTools: process.env.NODE_ENV !== "production",
|
@@ -22,6 +22,7 @@ export const store = configureStore({
|
|
22
22
|
superglue,
|
23
23
|
pages,
|
24
24
|
flash: flashSlice.reducer,
|
25
|
+
fragments,
|
25
26
|
},
|
26
27
|
});
|
27
28
|
|
@@ -5,10 +5,10 @@ import {
|
|
5
5
|
Layout,
|
6
6
|
<%- attributes.each do |attr| -%>
|
7
7
|
<%= js_component(attr)%>,
|
8
|
-
<%= js_component(attr)%>Props,
|
8
|
+
Rails<%= js_component(attr)%>Props,
|
9
9
|
<%- end -%>
|
10
10
|
SubmitButton,
|
11
|
-
|
11
|
+
RailsSubmitButtonProps
|
12
12
|
} from '@javascript/components'
|
13
13
|
import { useContent } from '@thoughtbot/superglue'
|
14
14
|
import { useAppSelector } from '@javascript/store'
|
@@ -18,9 +18,9 @@ type ContentProps = {
|
|
18
18
|
<%= js_plural_table_name %>Path: string,
|
19
19
|
<%= js_singular_table_name %>Form: FormProps<{
|
20
20
|
<%- attributes.each do |attr| -%>
|
21
|
-
<%= attr.column_name.camelize(:lower)%>: <%= js_component(attr)%>Props
|
21
|
+
<%= attr.column_name.camelize(:lower)%>: Rails<%= js_component(attr)%>Props
|
22
22
|
<%- end -%>
|
23
|
-
submit:
|
23
|
+
submit: RailsSubmitButtonProps
|
24
24
|
}>
|
25
25
|
}
|
26
26
|
|
@@ -5,10 +5,10 @@ import {
|
|
5
5
|
Layout,
|
6
6
|
<%- attributes.each do |attr| -%>
|
7
7
|
<%= js_component(attr)%>,
|
8
|
-
<%= js_component(attr)%>Props,
|
8
|
+
Rails<%= js_component(attr)%>Props,
|
9
9
|
<%- end -%>
|
10
10
|
SubmitButton,
|
11
|
-
|
11
|
+
RailsSubmitButtonProps
|
12
12
|
} from '@javascript/components'
|
13
13
|
import { useContent } from '@thoughtbot/superglue'
|
14
14
|
import { useAppSelector } from '@javascript/store'
|
@@ -17,9 +17,9 @@ type ContentProps = {
|
|
17
17
|
<%= js_plural_table_name %>Path: string
|
18
18
|
<%= js_singular_table_name %>Form: FormProps<{
|
19
19
|
<%- attributes.each do |attr| -%>
|
20
|
-
<%= attr.column_name.camelize(:lower)%>: <%=
|
20
|
+
<%= attr.column_name.camelize(:lower)%>: <%= Railsjs_component(attr)%>Props
|
21
21
|
<%- end -%>
|
22
|
-
submit:
|
22
|
+
submit: RailsSubmitButtonProps
|
23
23
|
}>
|
24
24
|
}
|
25
25
|
|
data/lib/superglue/rendering.rb
CHANGED
@@ -58,7 +58,12 @@ module Superglue
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def _ensure_react_page!(template, prefixes)
|
61
|
-
lookup_context.find(template, prefixes, false, [], formats: [], handlers: [], variants: [], locale: [])
|
61
|
+
found_template = lookup_context.find(template, prefixes, false, [], formats: [], handlers: [], variants: [], locale: [])
|
62
|
+
## This variable was created for props_template to pick up
|
63
|
+
@_active_template_virtual_path = found_template.virtual_path
|
64
|
+
found_template
|
65
|
+
rescue ActionView::MissingTemplate => e
|
66
|
+
raise ActionView::MissingTemplate.new(e.paths, e.path, e.prefixes, e.partial, "extension JSX or TSX")
|
62
67
|
end
|
63
68
|
|
64
69
|
def default_render
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: superglue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.alpha.
|
4
|
+
version: 2.0.0.alpha.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johny Ho
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|