react-store-input 0.1.0 → 0.1.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.
package/README.md CHANGED
@@ -8,6 +8,8 @@ At the same time, it allows you to use all the attributes originally provided by
8
8
 
9
9
  ## Get Started
10
10
 
11
+ This is a simple example of how to use this package.
12
+
11
13
  ```tsx
12
14
  import { useFormStore } from "dn-react-input";
13
15
 
@@ -37,3 +39,184 @@ export default function App() {
37
39
  );
38
40
  }
39
41
  ```
42
+
43
+ ## How to define state?
44
+
45
+ You can define any state you want as an object when calling `useStore`.
46
+
47
+ ```tsx
48
+ function Component() {
49
+ ...
50
+
51
+ const store = useStore({
52
+ email: "",
53
+ password: "",
54
+ rememberMe: false,
55
+ });
56
+
57
+ ...
58
+ }
59
+ ```
60
+
61
+ It's a single source of truth for your form state.
62
+
63
+ ## How to get input values?
64
+
65
+ You can access the current values of the input elements through the `state` property of the store.
66
+
67
+ ```tsx
68
+ function Component() {
69
+ ...
70
+
71
+ const submit = () => {
72
+ const { email, password, rememberMe } = store.state;
73
+ };
74
+
75
+ ...
76
+ }
77
+ ```
78
+
79
+ ## How to add input elements?
80
+
81
+ You can add input elements using the `Input` component provided by the store. There are 'Select' and 'Textarea' components as well.
82
+
83
+ ```tsx
84
+ import { Input } from "dn-react-input";
85
+
86
+ function Component() {
87
+ ...
88
+
89
+ return (
90
+ <form>
91
+ <Input store={store} name="email" type="email" />
92
+ <Input store={store} name="password" type="password" />
93
+ <Input store={store} name="rememberMe" type="checkbox" />
94
+ </form>
95
+ );
96
+ }
97
+ ```
98
+
99
+ If you want to avoid passing the store to each input component, use `useStoreInput`. This hook provides input components that are already connected to the store.
100
+
101
+ ```tsx
102
+ import { useStoreInput } from "dn-react-input";
103
+
104
+ function Component() {
105
+ ...
106
+ const Input = useStoreInput(store);
107
+
108
+ return (
109
+ <form>
110
+ <Input.input name="email" type="email" />
111
+ <Input.input name="password" type="password" />
112
+ <Input.input name="rememberMe" type="checkbox" />
113
+ </form>
114
+ );
115
+ }
116
+ ```
117
+
118
+ `useFormStore` is a facade that combines `useStore` and `useStoreInput` for convenience.
119
+
120
+ ```tsx
121
+ import { useFormStore } from "dn-react-input";
122
+
123
+ function Component() {
124
+ ...
125
+ const store = useFormStore({
126
+ email: "",
127
+ password: "",
128
+ rememberMe: false,
129
+ });
130
+
131
+ return (
132
+ <form>
133
+ <store.input name="email" type="email" />
134
+ <store.input name="password" type="password" />
135
+ <store.input name="rememberMe" type="checkbox" />
136
+ </form>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ## How to render components on state changes?
142
+
143
+ If you want to render a component only when specific parts of the state change, use the `useSelector` hook.
144
+
145
+ ```tsx
146
+ import { useSelector } from "dn-react-input";
147
+
148
+ function Component() {
149
+ ...
150
+ const email = useSelector(store, (state) => state.email);
151
+
152
+ return <div>Your email is: {email}</div>;
153
+ }
154
+ ```
155
+
156
+ If you want to render components in an inline manner, use the `createRender` function. By using this, you can avoid creating separate components for each part of the state you want to track.
157
+
158
+ ```tsx
159
+ import { createRender } from "dn-react-input";
160
+
161
+ function Component() {
162
+ ...
163
+ return (
164
+ <div>
165
+ {createRender(store, (state) => <p>{state.email}</p>)}
166
+ {createRender(store, (state) => <p>{state.password}</p>)}
167
+ </div>
168
+ );
169
+ }
170
+ ```
171
+
172
+ ## How to subscribe to state changes?
173
+
174
+ You can subscribe to state changes using the `subscribe` method of the store.
175
+
176
+ ```tsx
177
+ function Component() {
178
+ ...
179
+ useEffect(() => {
180
+ const unsubscribe = store.subscribe((state) => {
181
+ console.log(`State changed`, state);
182
+ });
183
+
184
+ return () => {
185
+ unsubscribe();
186
+ };
187
+ }, []);
188
+
189
+ ...
190
+ }
191
+ ```
192
+
193
+ ## How to update state manually?
194
+
195
+ You can update the state manually using the `dispatch` method of the store.
196
+
197
+ ```tsx
198
+ function Component() {
199
+ ...
200
+ const updateEmail = () => {
201
+ store.dispatch({ email: "ohjinsu98@icloud.com" });
202
+ };
203
+
204
+ return <button onClick={updateEmail}>Update Email</button>;
205
+ }
206
+ ```
207
+
208
+ The `dispatch` method uses immerjs internally to update the state, so you can also use a function to update the state based on the previous state.
209
+
210
+ ```tsx
211
+ function Component() {
212
+ ...
213
+
214
+ const updateEmail = () => {
215
+ store.dispatch((state) => {
216
+ state.email = "ohjinsu98@icloud.com";
217
+ });
218
+ };
219
+
220
+ return <button onClick={updateEmail}>Update Email</button>;
221
+ }
222
+ ```
@@ -1,7 +1,8 @@
1
- import { ReactNode } from 'react';
1
+ import React__default, { ReactNode } from 'react';
2
2
  import { Store } from './use_store.mjs';
3
3
 
4
4
  type CreateRender<TState> = (selector: (state: TState) => ReactNode, compare?: (a: TState, b: TState) => boolean) => ReactNode;
5
- declare function createRender<TState>(store: Store<TState>): CreateRender<TState>;
5
+ declare function createRender<TState>(store: Store<TState>, selector: (state: TState) => ReactNode, compare?: (a: TState, b: TState) => boolean): React__default.JSX.Element;
6
+ declare function createRenderWithStore<TState>(store: Store<TState>): CreateRender<TState>;
6
7
 
7
- export { type CreateRender, createRender };
8
+ export { type CreateRender, createRender, createRenderWithStore };
@@ -1,7 +1,8 @@
1
- import { ReactNode } from 'react';
1
+ import React__default, { ReactNode } from 'react';
2
2
  import { Store } from './use_store.js';
3
3
 
4
4
  type CreateRender<TState> = (selector: (state: TState) => ReactNode, compare?: (a: TState, b: TState) => boolean) => ReactNode;
5
- declare function createRender<TState>(store: Store<TState>): CreateRender<TState>;
5
+ declare function createRender<TState>(store: Store<TState>, selector: (state: TState) => ReactNode, compare?: (a: TState, b: TState) => boolean): React__default.JSX.Element;
6
+ declare function createRenderWithStore<TState>(store: Store<TState>): CreateRender<TState>;
6
7
 
7
- export { type CreateRender, createRender };
8
+ export { type CreateRender, createRender, createRenderWithStore };
@@ -30,7 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/create_render.tsx
31
31
  var create_render_exports = {};
32
32
  __export(create_render_exports, {
33
- createRender: () => createRender
33
+ createRender: () => createRender,
34
+ createRenderWithStore: () => createRenderWithStore
34
35
  });
35
36
  module.exports = __toCommonJS(create_render_exports);
36
37
 
@@ -63,7 +64,15 @@ function useSelector(store, selector, compare = (a, b) => a === b) {
63
64
 
64
65
  // src/create_render.tsx
65
66
  var import_react3 = __toESM(require("react"));
66
- function createRender(store) {
67
+ function createRender(store, selector, compare) {
68
+ function Component() {
69
+ const result = useSelector(store, (state) => state, compare);
70
+ const content = selector(result);
71
+ return /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, content);
72
+ }
73
+ return /* @__PURE__ */ import_react3.default.createElement(Component, null);
74
+ }
75
+ function createRenderWithStore(store) {
67
76
  return function createRender2(selector, compare) {
68
77
  function Component() {
69
78
  const result = useSelector(store, (state) => state, compare);
@@ -75,5 +84,6 @@ function createRender(store) {
75
84
  }
76
85
  // Annotate the CommonJS export names for ESM import in node:
77
86
  0 && (module.exports = {
78
- createRender
87
+ createRender,
88
+ createRenderWithStore
79
89
  });
@@ -27,7 +27,15 @@ function useSelector(store, selector, compare = (a, b) => a === b) {
27
27
 
28
28
  // src/create_render.tsx
29
29
  import React from "react";
30
- function createRender(store) {
30
+ function createRender(store, selector, compare) {
31
+ function Component() {
32
+ const result = useSelector(store, (state) => state, compare);
33
+ const content = selector(result);
34
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, content);
35
+ }
36
+ return /* @__PURE__ */ React.createElement(Component, null);
37
+ }
38
+ function createRenderWithStore(store) {
31
39
  return function createRender2(selector, compare) {
32
40
  function Component() {
33
41
  const result = useSelector(store, (state) => state, compare);
@@ -38,5 +46,6 @@ function createRender(store) {
38
46
  };
39
47
  }
40
48
  export {
41
- createRender
49
+ createRender,
50
+ createRenderWithStore
42
51
  };
package/dist/index.js CHANGED
@@ -164,14 +164,19 @@ function useStoreInputProps(store, props) {
164
164
  function useSubscriptionRef() {
165
165
  const ref2 = (0, import_react4.useRef)(null);
166
166
  (0, import_react4.useEffect)(() => {
167
+ const input = ref2.current;
168
+ if (!input) {
169
+ return;
170
+ }
171
+ if (typeof props.ref === "function") {
172
+ props.ref(input);
173
+ } else if (props.ref) {
174
+ props.ref.current = input;
175
+ }
167
176
  return store.subscribe((state, key) => {
168
177
  if (key === dispatchKey) {
169
178
  return;
170
179
  }
171
- const input = ref2.current;
172
- if (!input) {
173
- return;
174
- }
175
180
  if (props.type === "checkbox" || props.type === "radio") {
176
181
  const checked = toInputChecked(state[props.name]);
177
182
  if (input.checked === checked) {
@@ -204,17 +209,23 @@ function useStoreInputProps(store, props) {
204
209
  return (e) => {
205
210
  const target = e.target;
206
211
  if (props.type === "checkbox") {
207
- store.dispatch((state) => {
208
- state[props.name] = target.checked;
209
- }, {
210
- key: dispatchKey
211
- });
212
+ store.dispatch(
213
+ (state) => {
214
+ state[props.name] = target.checked;
215
+ },
216
+ {
217
+ key: dispatchKey
218
+ }
219
+ );
212
220
  } else {
213
- store.dispatch((state) => {
214
- state[props.name] = toStateValue(target.value);
215
- }, {
216
- key: dispatchKey
217
- });
221
+ store.dispatch(
222
+ (state) => {
223
+ state[props.name] = toStateValue(target.value);
224
+ },
225
+ {
226
+ key: dispatchKey
227
+ }
228
+ );
218
229
  }
219
230
  props.onChange?.(e);
220
231
  };
@@ -237,18 +248,12 @@ function useStoreInputProps(store, props) {
237
248
 
238
249
  // src/use_store_input.tsx
239
250
  function useStoreInput(store) {
240
- const input = (0, import_react5.useCallback)(
241
- function Component(props) {
242
- return /* @__PURE__ */ import_react6.default.createElement(Input, { store, ...props });
243
- },
244
- []
245
- );
246
- const select = (0, import_react5.useCallback)(
247
- function Component(props) {
248
- return /* @__PURE__ */ import_react6.default.createElement(Select, { store, ...props });
249
- },
250
- []
251
- );
251
+ const input = (0, import_react5.useCallback)(function Component(props) {
252
+ return /* @__PURE__ */ import_react6.default.createElement(Input, { store, ...props });
253
+ }, []);
254
+ const select = (0, import_react5.useCallback)(function Component(props) {
255
+ return /* @__PURE__ */ import_react6.default.createElement(Select, { store, ...props });
256
+ }, []);
252
257
  const textarea = (0, import_react5.useCallback)(function Component(props) {
253
258
  return /* @__PURE__ */ import_react6.default.createElement(Textarea, { store, ...props });
254
259
  }, []);
@@ -258,23 +263,32 @@ function useStoreInput(store) {
258
263
  textarea
259
264
  };
260
265
  }
261
- function Input({ store, ...props }) {
266
+ function Input({
267
+ store,
268
+ ...props
269
+ }) {
262
270
  const storeProps = useStoreInputProps(store, props);
263
271
  return /* @__PURE__ */ import_react6.default.createElement("input", { ...props, ...storeProps });
264
272
  }
265
- function Select({ store, ...props }) {
273
+ function Select({
274
+ store,
275
+ ...props
276
+ }) {
266
277
  const storeProps = useStoreInputProps(store, props);
267
278
  return /* @__PURE__ */ import_react6.default.createElement("select", { ...props, ...storeProps });
268
279
  }
269
- function Textarea({ store, ...props }) {
280
+ function Textarea({
281
+ store,
282
+ ...props
283
+ }) {
270
284
  const storeProps = useStoreInputProps(store, props);
271
285
  return /* @__PURE__ */ import_react6.default.createElement("textarea", { ...props, ...storeProps });
272
286
  }
273
287
 
274
288
  // src/create_render.tsx
275
289
  var import_react7 = __toESM(require("react"));
276
- function createRender(store) {
277
- return function createRender2(selector, compare) {
290
+ function createRenderWithStore(store) {
291
+ return function createRender(selector, compare) {
278
292
  function Component() {
279
293
  const result = useSelector(store, (state) => state, compare);
280
294
  const content = selector(result);
@@ -294,7 +308,7 @@ function useFormStore(initialState) {
294
308
  },
295
309
  dispatch: store.dispatch,
296
310
  subscribe: store.subscribe,
297
- render: createRender(store),
311
+ render: createRenderWithStore(store),
298
312
  ...storeInput
299
313
  };
300
314
  }
package/dist/index.mjs CHANGED
@@ -124,14 +124,19 @@ function useStoreInputProps(store, props) {
124
124
  function useSubscriptionRef() {
125
125
  const ref2 = useRef2(null);
126
126
  useEffect2(() => {
127
+ const input = ref2.current;
128
+ if (!input) {
129
+ return;
130
+ }
131
+ if (typeof props.ref === "function") {
132
+ props.ref(input);
133
+ } else if (props.ref) {
134
+ props.ref.current = input;
135
+ }
127
136
  return store.subscribe((state, key) => {
128
137
  if (key === dispatchKey) {
129
138
  return;
130
139
  }
131
- const input = ref2.current;
132
- if (!input) {
133
- return;
134
- }
135
140
  if (props.type === "checkbox" || props.type === "radio") {
136
141
  const checked = toInputChecked(state[props.name]);
137
142
  if (input.checked === checked) {
@@ -164,17 +169,23 @@ function useStoreInputProps(store, props) {
164
169
  return (e) => {
165
170
  const target = e.target;
166
171
  if (props.type === "checkbox") {
167
- store.dispatch((state) => {
168
- state[props.name] = target.checked;
169
- }, {
170
- key: dispatchKey
171
- });
172
+ store.dispatch(
173
+ (state) => {
174
+ state[props.name] = target.checked;
175
+ },
176
+ {
177
+ key: dispatchKey
178
+ }
179
+ );
172
180
  } else {
173
- store.dispatch((state) => {
174
- state[props.name] = toStateValue(target.value);
175
- }, {
176
- key: dispatchKey
177
- });
181
+ store.dispatch(
182
+ (state) => {
183
+ state[props.name] = toStateValue(target.value);
184
+ },
185
+ {
186
+ key: dispatchKey
187
+ }
188
+ );
178
189
  }
179
190
  props.onChange?.(e);
180
191
  };
@@ -197,18 +208,12 @@ function useStoreInputProps(store, props) {
197
208
 
198
209
  // src/use_store_input.tsx
199
210
  function useStoreInput(store) {
200
- const input = useCallback(
201
- function Component(props) {
202
- return /* @__PURE__ */ React.createElement(Input, { store, ...props });
203
- },
204
- []
205
- );
206
- const select = useCallback(
207
- function Component(props) {
208
- return /* @__PURE__ */ React.createElement(Select, { store, ...props });
209
- },
210
- []
211
- );
211
+ const input = useCallback(function Component(props) {
212
+ return /* @__PURE__ */ React.createElement(Input, { store, ...props });
213
+ }, []);
214
+ const select = useCallback(function Component(props) {
215
+ return /* @__PURE__ */ React.createElement(Select, { store, ...props });
216
+ }, []);
212
217
  const textarea = useCallback(function Component(props) {
213
218
  return /* @__PURE__ */ React.createElement(Textarea, { store, ...props });
214
219
  }, []);
@@ -218,23 +223,32 @@ function useStoreInput(store) {
218
223
  textarea
219
224
  };
220
225
  }
221
- function Input({ store, ...props }) {
226
+ function Input({
227
+ store,
228
+ ...props
229
+ }) {
222
230
  const storeProps = useStoreInputProps(store, props);
223
231
  return /* @__PURE__ */ React.createElement("input", { ...props, ...storeProps });
224
232
  }
225
- function Select({ store, ...props }) {
233
+ function Select({
234
+ store,
235
+ ...props
236
+ }) {
226
237
  const storeProps = useStoreInputProps(store, props);
227
238
  return /* @__PURE__ */ React.createElement("select", { ...props, ...storeProps });
228
239
  }
229
- function Textarea({ store, ...props }) {
240
+ function Textarea({
241
+ store,
242
+ ...props
243
+ }) {
230
244
  const storeProps = useStoreInputProps(store, props);
231
245
  return /* @__PURE__ */ React.createElement("textarea", { ...props, ...storeProps });
232
246
  }
233
247
 
234
248
  // src/create_render.tsx
235
249
  import React2 from "react";
236
- function createRender(store) {
237
- return function createRender2(selector, compare) {
250
+ function createRenderWithStore(store) {
251
+ return function createRender(selector, compare) {
238
252
  function Component() {
239
253
  const result = useSelector(store, (state) => state, compare);
240
254
  const content = selector(result);
@@ -254,7 +268,7 @@ function useFormStore(initialState) {
254
268
  },
255
269
  dispatch: store.dispatch,
256
270
  subscribe: store.subscribe,
257
- render: createRender(store),
271
+ render: createRenderWithStore(store),
258
272
  ...storeInput
259
273
  };
260
274
  }
@@ -63,8 +63,8 @@ function useSelector(store, selector, compare = (a, b) => a === b) {
63
63
 
64
64
  // src/create_render.tsx
65
65
  var import_react3 = __toESM(require("react"));
66
- function createRender(store) {
67
- return function createRender2(selector, compare) {
66
+ function createRenderWithStore(store) {
67
+ return function createRender(selector, compare) {
68
68
  function Component() {
69
69
  const result = useSelector(store, (state) => state, compare);
70
70
  const content = selector(result);
@@ -167,14 +167,19 @@ function useStoreInputProps(store, props) {
167
167
  function useSubscriptionRef() {
168
168
  const ref2 = (0, import_react5.useRef)(null);
169
169
  (0, import_react5.useEffect)(() => {
170
+ const input = ref2.current;
171
+ if (!input) {
172
+ return;
173
+ }
174
+ if (typeof props.ref === "function") {
175
+ props.ref(input);
176
+ } else if (props.ref) {
177
+ props.ref.current = input;
178
+ }
170
179
  return store.subscribe((state, key) => {
171
180
  if (key === dispatchKey) {
172
181
  return;
173
182
  }
174
- const input = ref2.current;
175
- if (!input) {
176
- return;
177
- }
178
183
  if (props.type === "checkbox" || props.type === "radio") {
179
184
  const checked = toInputChecked(state[props.name]);
180
185
  if (input.checked === checked) {
@@ -207,17 +212,23 @@ function useStoreInputProps(store, props) {
207
212
  return (e) => {
208
213
  const target = e.target;
209
214
  if (props.type === "checkbox") {
210
- store.dispatch((state) => {
211
- state[props.name] = target.checked;
212
- }, {
213
- key: dispatchKey
214
- });
215
+ store.dispatch(
216
+ (state) => {
217
+ state[props.name] = target.checked;
218
+ },
219
+ {
220
+ key: dispatchKey
221
+ }
222
+ );
215
223
  } else {
216
- store.dispatch((state) => {
217
- state[props.name] = toStateValue(target.value);
218
- }, {
219
- key: dispatchKey
220
- });
224
+ store.dispatch(
225
+ (state) => {
226
+ state[props.name] = toStateValue(target.value);
227
+ },
228
+ {
229
+ key: dispatchKey
230
+ }
231
+ );
221
232
  }
222
233
  props.onChange?.(e);
223
234
  };
@@ -240,18 +251,12 @@ function useStoreInputProps(store, props) {
240
251
 
241
252
  // src/use_store_input.tsx
242
253
  function useStoreInput(store) {
243
- const input = (0, import_react6.useCallback)(
244
- function Component(props) {
245
- return /* @__PURE__ */ import_react7.default.createElement(Input, { store, ...props });
246
- },
247
- []
248
- );
249
- const select = (0, import_react6.useCallback)(
250
- function Component(props) {
251
- return /* @__PURE__ */ import_react7.default.createElement(Select, { store, ...props });
252
- },
253
- []
254
- );
254
+ const input = (0, import_react6.useCallback)(function Component(props) {
255
+ return /* @__PURE__ */ import_react7.default.createElement(Input, { store, ...props });
256
+ }, []);
257
+ const select = (0, import_react6.useCallback)(function Component(props) {
258
+ return /* @__PURE__ */ import_react7.default.createElement(Select, { store, ...props });
259
+ }, []);
255
260
  const textarea = (0, import_react6.useCallback)(function Component(props) {
256
261
  return /* @__PURE__ */ import_react7.default.createElement(Textarea, { store, ...props });
257
262
  }, []);
@@ -261,15 +266,24 @@ function useStoreInput(store) {
261
266
  textarea
262
267
  };
263
268
  }
264
- function Input({ store, ...props }) {
269
+ function Input({
270
+ store,
271
+ ...props
272
+ }) {
265
273
  const storeProps = useStoreInputProps(store, props);
266
274
  return /* @__PURE__ */ import_react7.default.createElement("input", { ...props, ...storeProps });
267
275
  }
268
- function Select({ store, ...props }) {
276
+ function Select({
277
+ store,
278
+ ...props
279
+ }) {
269
280
  const storeProps = useStoreInputProps(store, props);
270
281
  return /* @__PURE__ */ import_react7.default.createElement("select", { ...props, ...storeProps });
271
282
  }
272
- function Textarea({ store, ...props }) {
283
+ function Textarea({
284
+ store,
285
+ ...props
286
+ }) {
273
287
  const storeProps = useStoreInputProps(store, props);
274
288
  return /* @__PURE__ */ import_react7.default.createElement("textarea", { ...props, ...storeProps });
275
289
  }
@@ -284,7 +298,7 @@ function useFormStore(initialState) {
284
298
  },
285
299
  dispatch: store.dispatch,
286
300
  subscribe: store.subscribe,
287
- render: createRender(store),
301
+ render: createRenderWithStore(store),
288
302
  ...storeInput
289
303
  };
290
304
  }
@@ -27,8 +27,8 @@ function useSelector(store, selector, compare = (a, b) => a === b) {
27
27
 
28
28
  // src/create_render.tsx
29
29
  import React from "react";
30
- function createRender(store) {
31
- return function createRender2(selector, compare) {
30
+ function createRenderWithStore(store) {
31
+ return function createRender(selector, compare) {
32
32
  function Component() {
33
33
  const result = useSelector(store, (state) => state, compare);
34
34
  const content = selector(result);
@@ -137,14 +137,19 @@ function useStoreInputProps(store, props) {
137
137
  function useSubscriptionRef() {
138
138
  const ref2 = useRef2(null);
139
139
  useEffect2(() => {
140
+ const input = ref2.current;
141
+ if (!input) {
142
+ return;
143
+ }
144
+ if (typeof props.ref === "function") {
145
+ props.ref(input);
146
+ } else if (props.ref) {
147
+ props.ref.current = input;
148
+ }
140
149
  return store.subscribe((state, key) => {
141
150
  if (key === dispatchKey) {
142
151
  return;
143
152
  }
144
- const input = ref2.current;
145
- if (!input) {
146
- return;
147
- }
148
153
  if (props.type === "checkbox" || props.type === "radio") {
149
154
  const checked = toInputChecked(state[props.name]);
150
155
  if (input.checked === checked) {
@@ -177,17 +182,23 @@ function useStoreInputProps(store, props) {
177
182
  return (e) => {
178
183
  const target = e.target;
179
184
  if (props.type === "checkbox") {
180
- store.dispatch((state) => {
181
- state[props.name] = target.checked;
182
- }, {
183
- key: dispatchKey
184
- });
185
+ store.dispatch(
186
+ (state) => {
187
+ state[props.name] = target.checked;
188
+ },
189
+ {
190
+ key: dispatchKey
191
+ }
192
+ );
185
193
  } else {
186
- store.dispatch((state) => {
187
- state[props.name] = toStateValue(target.value);
188
- }, {
189
- key: dispatchKey
190
- });
194
+ store.dispatch(
195
+ (state) => {
196
+ state[props.name] = toStateValue(target.value);
197
+ },
198
+ {
199
+ key: dispatchKey
200
+ }
201
+ );
191
202
  }
192
203
  props.onChange?.(e);
193
204
  };
@@ -210,18 +221,12 @@ function useStoreInputProps(store, props) {
210
221
 
211
222
  // src/use_store_input.tsx
212
223
  function useStoreInput(store) {
213
- const input = useCallback(
214
- function Component(props) {
215
- return /* @__PURE__ */ React2.createElement(Input, { store, ...props });
216
- },
217
- []
218
- );
219
- const select = useCallback(
220
- function Component(props) {
221
- return /* @__PURE__ */ React2.createElement(Select, { store, ...props });
222
- },
223
- []
224
- );
224
+ const input = useCallback(function Component(props) {
225
+ return /* @__PURE__ */ React2.createElement(Input, { store, ...props });
226
+ }, []);
227
+ const select = useCallback(function Component(props) {
228
+ return /* @__PURE__ */ React2.createElement(Select, { store, ...props });
229
+ }, []);
225
230
  const textarea = useCallback(function Component(props) {
226
231
  return /* @__PURE__ */ React2.createElement(Textarea, { store, ...props });
227
232
  }, []);
@@ -231,15 +236,24 @@ function useStoreInput(store) {
231
236
  textarea
232
237
  };
233
238
  }
234
- function Input({ store, ...props }) {
239
+ function Input({
240
+ store,
241
+ ...props
242
+ }) {
235
243
  const storeProps = useStoreInputProps(store, props);
236
244
  return /* @__PURE__ */ React2.createElement("input", { ...props, ...storeProps });
237
245
  }
238
- function Select({ store, ...props }) {
246
+ function Select({
247
+ store,
248
+ ...props
249
+ }) {
239
250
  const storeProps = useStoreInputProps(store, props);
240
251
  return /* @__PURE__ */ React2.createElement("select", { ...props, ...storeProps });
241
252
  }
242
- function Textarea({ store, ...props }) {
253
+ function Textarea({
254
+ store,
255
+ ...props
256
+ }) {
243
257
  const storeProps = useStoreInputProps(store, props);
244
258
  return /* @__PURE__ */ React2.createElement("textarea", { ...props, ...storeProps });
245
259
  }
@@ -254,7 +268,7 @@ function useFormStore(initialState) {
254
268
  },
255
269
  dispatch: store.dispatch,
256
270
  subscribe: store.subscribe,
257
- render: createRender(store),
271
+ render: createRenderWithStore(store),
258
272
  ...storeInput
259
273
  };
260
274
  }
@@ -1,7 +1,7 @@
1
- import React__default, { InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes } from 'react';
1
+ import React__default, { DetailedHTMLProps, InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes } from 'react';
2
2
  import { Store } from './use_store.mjs';
3
3
 
4
- type StoreInputProps<TElement extends HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, TState> = Omit<TElement extends HTMLInputElement ? InputHTMLAttributes<HTMLInputElement> : TElement extends HTMLSelectElement ? SelectHTMLAttributes<HTMLSelectElement> : TextareaHTMLAttributes<HTMLTextAreaElement>, "name"> & {
4
+ type StoreInputProps<TElement extends HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, TState> = Omit<TElement extends HTMLInputElement ? DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> : TElement extends HTMLSelectElement ? DetailedHTMLProps<SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement> : DetailedHTMLProps<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "name"> & {
5
5
  name: keyof TState;
6
6
  };
7
7
  declare function useStoreInput<TState>(store: Store<TState>): {
@@ -1,7 +1,7 @@
1
- import React__default, { InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes } from 'react';
1
+ import React__default, { DetailedHTMLProps, InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes } from 'react';
2
2
  import { Store } from './use_store.js';
3
3
 
4
- type StoreInputProps<TElement extends HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, TState> = Omit<TElement extends HTMLInputElement ? InputHTMLAttributes<HTMLInputElement> : TElement extends HTMLSelectElement ? SelectHTMLAttributes<HTMLSelectElement> : TextareaHTMLAttributes<HTMLTextAreaElement>, "name"> & {
4
+ type StoreInputProps<TElement extends HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, TState> = Omit<TElement extends HTMLInputElement ? DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> : TElement extends HTMLSelectElement ? DetailedHTMLProps<SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement> : DetailedHTMLProps<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "name"> & {
5
5
  name: keyof TState;
6
6
  };
7
7
  declare function useStoreInput<TState>(store: Store<TState>): {
@@ -84,14 +84,19 @@ function useStoreInputProps(store, props) {
84
84
  function useSubscriptionRef() {
85
85
  const ref2 = (0, import_react.useRef)(null);
86
86
  (0, import_react.useEffect)(() => {
87
+ const input = ref2.current;
88
+ if (!input) {
89
+ return;
90
+ }
91
+ if (typeof props.ref === "function") {
92
+ props.ref(input);
93
+ } else if (props.ref) {
94
+ props.ref.current = input;
95
+ }
87
96
  return store.subscribe((state, key) => {
88
97
  if (key === dispatchKey) {
89
98
  return;
90
99
  }
91
- const input = ref2.current;
92
- if (!input) {
93
- return;
94
- }
95
100
  if (props.type === "checkbox" || props.type === "radio") {
96
101
  const checked = toInputChecked(state[props.name]);
97
102
  if (input.checked === checked) {
@@ -124,17 +129,23 @@ function useStoreInputProps(store, props) {
124
129
  return (e) => {
125
130
  const target = e.target;
126
131
  if (props.type === "checkbox") {
127
- store.dispatch((state) => {
128
- state[props.name] = target.checked;
129
- }, {
130
- key: dispatchKey
131
- });
132
+ store.dispatch(
133
+ (state) => {
134
+ state[props.name] = target.checked;
135
+ },
136
+ {
137
+ key: dispatchKey
138
+ }
139
+ );
132
140
  } else {
133
- store.dispatch((state) => {
134
- state[props.name] = toStateValue(target.value);
135
- }, {
136
- key: dispatchKey
137
- });
141
+ store.dispatch(
142
+ (state) => {
143
+ state[props.name] = toStateValue(target.value);
144
+ },
145
+ {
146
+ key: dispatchKey
147
+ }
148
+ );
138
149
  }
139
150
  props.onChange?.(e);
140
151
  };
@@ -157,18 +168,12 @@ function useStoreInputProps(store, props) {
157
168
 
158
169
  // src/use_store_input.tsx
159
170
  function useStoreInput(store) {
160
- const input = (0, import_react2.useCallback)(
161
- function Component(props) {
162
- return /* @__PURE__ */ import_react3.default.createElement(Input, { store, ...props });
163
- },
164
- []
165
- );
166
- const select = (0, import_react2.useCallback)(
167
- function Component(props) {
168
- return /* @__PURE__ */ import_react3.default.createElement(Select, { store, ...props });
169
- },
170
- []
171
- );
171
+ const input = (0, import_react2.useCallback)(function Component(props) {
172
+ return /* @__PURE__ */ import_react3.default.createElement(Input, { store, ...props });
173
+ }, []);
174
+ const select = (0, import_react2.useCallback)(function Component(props) {
175
+ return /* @__PURE__ */ import_react3.default.createElement(Select, { store, ...props });
176
+ }, []);
172
177
  const textarea = (0, import_react2.useCallback)(function Component(props) {
173
178
  return /* @__PURE__ */ import_react3.default.createElement(Textarea, { store, ...props });
174
179
  }, []);
@@ -178,15 +183,24 @@ function useStoreInput(store) {
178
183
  textarea
179
184
  };
180
185
  }
181
- function Input({ store, ...props }) {
186
+ function Input({
187
+ store,
188
+ ...props
189
+ }) {
182
190
  const storeProps = useStoreInputProps(store, props);
183
191
  return /* @__PURE__ */ import_react3.default.createElement("input", { ...props, ...storeProps });
184
192
  }
185
- function Select({ store, ...props }) {
193
+ function Select({
194
+ store,
195
+ ...props
196
+ }) {
186
197
  const storeProps = useStoreInputProps(store, props);
187
198
  return /* @__PURE__ */ import_react3.default.createElement("select", { ...props, ...storeProps });
188
199
  }
189
- function Textarea({ store, ...props }) {
200
+ function Textarea({
201
+ store,
202
+ ...props
203
+ }) {
190
204
  const storeProps = useStoreInputProps(store, props);
191
205
  return /* @__PURE__ */ import_react3.default.createElement("textarea", { ...props, ...storeProps });
192
206
  }
@@ -53,14 +53,19 @@ function useStoreInputProps(store, props) {
53
53
  function useSubscriptionRef() {
54
54
  const ref2 = useRef(null);
55
55
  useEffect(() => {
56
+ const input = ref2.current;
57
+ if (!input) {
58
+ return;
59
+ }
60
+ if (typeof props.ref === "function") {
61
+ props.ref(input);
62
+ } else if (props.ref) {
63
+ props.ref.current = input;
64
+ }
56
65
  return store.subscribe((state, key) => {
57
66
  if (key === dispatchKey) {
58
67
  return;
59
68
  }
60
- const input = ref2.current;
61
- if (!input) {
62
- return;
63
- }
64
69
  if (props.type === "checkbox" || props.type === "radio") {
65
70
  const checked = toInputChecked(state[props.name]);
66
71
  if (input.checked === checked) {
@@ -93,17 +98,23 @@ function useStoreInputProps(store, props) {
93
98
  return (e) => {
94
99
  const target = e.target;
95
100
  if (props.type === "checkbox") {
96
- store.dispatch((state) => {
97
- state[props.name] = target.checked;
98
- }, {
99
- key: dispatchKey
100
- });
101
+ store.dispatch(
102
+ (state) => {
103
+ state[props.name] = target.checked;
104
+ },
105
+ {
106
+ key: dispatchKey
107
+ }
108
+ );
101
109
  } else {
102
- store.dispatch((state) => {
103
- state[props.name] = toStateValue(target.value);
104
- }, {
105
- key: dispatchKey
106
- });
110
+ store.dispatch(
111
+ (state) => {
112
+ state[props.name] = toStateValue(target.value);
113
+ },
114
+ {
115
+ key: dispatchKey
116
+ }
117
+ );
107
118
  }
108
119
  props.onChange?.(e);
109
120
  };
@@ -126,18 +137,12 @@ function useStoreInputProps(store, props) {
126
137
 
127
138
  // src/use_store_input.tsx
128
139
  function useStoreInput(store) {
129
- const input = useCallback(
130
- function Component(props) {
131
- return /* @__PURE__ */ React.createElement(Input, { store, ...props });
132
- },
133
- []
134
- );
135
- const select = useCallback(
136
- function Component(props) {
137
- return /* @__PURE__ */ React.createElement(Select, { store, ...props });
138
- },
139
- []
140
- );
140
+ const input = useCallback(function Component(props) {
141
+ return /* @__PURE__ */ React.createElement(Input, { store, ...props });
142
+ }, []);
143
+ const select = useCallback(function Component(props) {
144
+ return /* @__PURE__ */ React.createElement(Select, { store, ...props });
145
+ }, []);
141
146
  const textarea = useCallback(function Component(props) {
142
147
  return /* @__PURE__ */ React.createElement(Textarea, { store, ...props });
143
148
  }, []);
@@ -147,15 +152,24 @@ function useStoreInput(store) {
147
152
  textarea
148
153
  };
149
154
  }
150
- function Input({ store, ...props }) {
155
+ function Input({
156
+ store,
157
+ ...props
158
+ }) {
151
159
  const storeProps = useStoreInputProps(store, props);
152
160
  return /* @__PURE__ */ React.createElement("input", { ...props, ...storeProps });
153
161
  }
154
- function Select({ store, ...props }) {
162
+ function Select({
163
+ store,
164
+ ...props
165
+ }) {
155
166
  const storeProps = useStoreInputProps(store, props);
156
167
  return /* @__PURE__ */ React.createElement("select", { ...props, ...storeProps });
157
168
  }
158
- function Textarea({ store, ...props }) {
169
+ function Textarea({
170
+ store,
171
+ ...props
172
+ }) {
159
173
  const storeProps = useStoreInputProps(store, props);
160
174
  return /* @__PURE__ */ React.createElement("textarea", { ...props, ...storeProps });
161
175
  }
@@ -1,9 +1,10 @@
1
1
  import * as React from 'react';
2
- import { HTMLInputTypeAttribute, ChangeEventHandler } from 'react';
2
+ import { Ref, HTMLInputTypeAttribute, ChangeEventHandler } from 'react';
3
3
  import { Store } from './use_store.mjs';
4
4
 
5
5
  type InputType = HTMLInputTypeAttribute;
6
6
  type InputProps<TElement, TState> = {
7
+ ref?: Ref<TElement>;
7
8
  name: keyof TState;
8
9
  type?: InputType;
9
10
  defaultValue?: string | number | readonly string[];
@@ -1,9 +1,10 @@
1
1
  import * as React from 'react';
2
- import { HTMLInputTypeAttribute, ChangeEventHandler } from 'react';
2
+ import { Ref, HTMLInputTypeAttribute, ChangeEventHandler } from 'react';
3
3
  import { Store } from './use_store.js';
4
4
 
5
5
  type InputType = HTMLInputTypeAttribute;
6
6
  type InputProps<TElement, TState> = {
7
+ ref?: Ref<TElement>;
7
8
  name: keyof TState;
8
9
  type?: InputType;
9
10
  defaultValue?: string | number | readonly string[];
@@ -67,14 +67,19 @@ function useStoreInputProps(store, props) {
67
67
  function useSubscriptionRef() {
68
68
  const ref2 = (0, import_react.useRef)(null);
69
69
  (0, import_react.useEffect)(() => {
70
+ const input = ref2.current;
71
+ if (!input) {
72
+ return;
73
+ }
74
+ if (typeof props.ref === "function") {
75
+ props.ref(input);
76
+ } else if (props.ref) {
77
+ props.ref.current = input;
78
+ }
70
79
  return store.subscribe((state, key) => {
71
80
  if (key === dispatchKey) {
72
81
  return;
73
82
  }
74
- const input = ref2.current;
75
- if (!input) {
76
- return;
77
- }
78
83
  if (props.type === "checkbox" || props.type === "radio") {
79
84
  const checked = toInputChecked(state[props.name]);
80
85
  if (input.checked === checked) {
@@ -107,17 +112,23 @@ function useStoreInputProps(store, props) {
107
112
  return (e) => {
108
113
  const target = e.target;
109
114
  if (props.type === "checkbox") {
110
- store.dispatch((state) => {
111
- state[props.name] = target.checked;
112
- }, {
113
- key: dispatchKey
114
- });
115
+ store.dispatch(
116
+ (state) => {
117
+ state[props.name] = target.checked;
118
+ },
119
+ {
120
+ key: dispatchKey
121
+ }
122
+ );
115
123
  } else {
116
- store.dispatch((state) => {
117
- state[props.name] = toStateValue(target.value);
118
- }, {
119
- key: dispatchKey
120
- });
124
+ store.dispatch(
125
+ (state) => {
126
+ state[props.name] = toStateValue(target.value);
127
+ },
128
+ {
129
+ key: dispatchKey
130
+ }
131
+ );
121
132
  }
122
133
  props.onChange?.(e);
123
134
  };
@@ -47,14 +47,19 @@ function useStoreInputProps(store, props) {
47
47
  function useSubscriptionRef() {
48
48
  const ref2 = useRef(null);
49
49
  useEffect(() => {
50
+ const input = ref2.current;
51
+ if (!input) {
52
+ return;
53
+ }
54
+ if (typeof props.ref === "function") {
55
+ props.ref(input);
56
+ } else if (props.ref) {
57
+ props.ref.current = input;
58
+ }
50
59
  return store.subscribe((state, key) => {
51
60
  if (key === dispatchKey) {
52
61
  return;
53
62
  }
54
- const input = ref2.current;
55
- if (!input) {
56
- return;
57
- }
58
63
  if (props.type === "checkbox" || props.type === "radio") {
59
64
  const checked = toInputChecked(state[props.name]);
60
65
  if (input.checked === checked) {
@@ -87,17 +92,23 @@ function useStoreInputProps(store, props) {
87
92
  return (e) => {
88
93
  const target = e.target;
89
94
  if (props.type === "checkbox") {
90
- store.dispatch((state) => {
91
- state[props.name] = target.checked;
92
- }, {
93
- key: dispatchKey
94
- });
95
+ store.dispatch(
96
+ (state) => {
97
+ state[props.name] = target.checked;
98
+ },
99
+ {
100
+ key: dispatchKey
101
+ }
102
+ );
95
103
  } else {
96
- store.dispatch((state) => {
97
- state[props.name] = toStateValue(target.value);
98
- }, {
99
- key: dispatchKey
100
- });
104
+ store.dispatch(
105
+ (state) => {
106
+ state[props.name] = toStateValue(target.value);
107
+ },
108
+ {
109
+ key: dispatchKey
110
+ }
111
+ );
101
112
  }
102
113
  props.onChange?.(e);
103
114
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-store-input",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "types": "./dist/index.d.ts",
5
5
  "main": "./dist/index.mjs",
6
6
  "module": "./dist/index.js",