react-store-input 0.1.0 → 0.1.3

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/dist/index.mjs CHANGED
@@ -69,20 +69,52 @@ function useSelector(store, selector, compare = (a, b) => a === b) {
69
69
  return state;
70
70
  }
71
71
 
72
- // src/use_store_input.tsx
73
- import {
74
- useCallback
75
- } from "react";
76
- import React from "react";
72
+ // src/use_store_controller.tsx
73
+ import { useEffect as useEffect2, useId, useRef as useRef2 } from "react";
74
+ function useStoreController(store, props) {
75
+ const ref = useRef2(null);
76
+ const dispatchKey = useId();
77
+ useEffect2(() => {
78
+ const element = ref.current;
79
+ if (!element) {
80
+ return;
81
+ }
82
+ if (typeof props.ref === "function") {
83
+ props.ref(element);
84
+ } else if (props.ref) {
85
+ props.ref.current = element;
86
+ }
87
+ }, []);
88
+ useSubscribe(store, (state, key) => {
89
+ if (key === dispatchKey) {
90
+ return;
91
+ }
92
+ if (!ref.current) return;
93
+ props.onSubscribe(state, ref.current);
94
+ });
95
+ const onChange = () => {
96
+ store.dispatch(
97
+ (state) => {
98
+ const element = ref.current;
99
+ if (!element) return;
100
+ props.onDispatch(state, element);
101
+ },
102
+ {
103
+ key: dispatchKey
104
+ }
105
+ );
106
+ };
107
+ return {
108
+ dispatchKey,
109
+ ref,
110
+ onChange
111
+ };
112
+ }
77
113
 
78
- // src/use_store_input_props.tsx
79
- import {
80
- useEffect as useEffect2,
81
- useId,
82
- useRef as useRef2
83
- } from "react";
114
+ // src/use_store_input.tsx
115
+ import "react";
84
116
  import { format } from "date-fns";
85
- function useStoreInputProps(store, props) {
117
+ function useStoreInput(store, props) {
86
118
  const toInputValue = (value) => {
87
119
  if (value === void 0 || value === null) {
88
120
  return "";
@@ -104,7 +136,7 @@ function useStoreInputProps(store, props) {
104
136
  if (props.type === "checkbox" || props.type === "radio") {
105
137
  return void 0;
106
138
  }
107
- return toInputValue(store.state[props.name]);
139
+ return toInputValue(props.getter(store.state));
108
140
  };
109
141
  const toInputChecked = (value) => {
110
142
  if (props.type === "radio") {
@@ -119,96 +151,93 @@ function useStoreInputProps(store, props) {
119
151
  if (props.type !== "checkbox" && props.type !== "radio") {
120
152
  return void 0;
121
153
  }
122
- return toInputChecked(store.state[props.name]);
154
+ return toInputChecked(props.getter(store.state));
123
155
  };
124
- function useSubscriptionRef() {
125
- const ref2 = useRef2(null);
126
- useEffect2(() => {
127
- return store.subscribe((state, key) => {
128
- if (key === dispatchKey) {
129
- return;
130
- }
131
- const input = ref2.current;
132
- if (!input) {
133
- return;
134
- }
135
- if (props.type === "checkbox" || props.type === "radio") {
136
- const checked = toInputChecked(state[props.name]);
137
- if (input.checked === checked) {
138
- return;
139
- }
140
- input.checked = checked;
141
- } else {
142
- const value = toInputValue(state[props.name]);
143
- if (input.value === value) {
144
- return;
145
- }
146
- input.value = value;
147
- }
148
- const event = new Event("input", { bubbles: true });
149
- input.dispatchEvent(event);
150
- });
151
- }, []);
152
- return ref2;
153
- }
154
156
  function toStateValue(value) {
155
- if (typeof store.state[props.name] === "number") {
157
+ const selected = props.getter(store.state);
158
+ if (typeof selected === "number") {
156
159
  return Number(value);
157
160
  }
158
- if (store.state[props.name] instanceof Date) {
161
+ if (selected instanceof Date) {
159
162
  return new Date(value);
160
163
  }
161
164
  return value;
162
165
  }
163
- function createChangeEventHandler() {
164
- return (e) => {
165
- const target = e.target;
166
- if (props.type === "checkbox") {
167
- store.dispatch((state) => {
168
- state[props.name] = target.checked;
169
- }, {
170
- key: dispatchKey
171
- });
166
+ const inputProps = useStoreController(store, {
167
+ ref: props.ref,
168
+ onSubscribe: (state, element) => {
169
+ if ("checked" in element && (props.type === "checkbox" || props.type === "radio")) {
170
+ const checked = toInputChecked(props.getter(state));
171
+ if (element.checked === checked) {
172
+ return;
173
+ }
174
+ element.checked = checked;
172
175
  } else {
173
- store.dispatch((state) => {
174
- state[props.name] = toStateValue(target.value);
175
- }, {
176
- key: dispatchKey
177
- });
176
+ const value = toInputValue(props.getter(state));
177
+ if (element.value === value) {
178
+ return;
179
+ }
180
+ element.value = value;
178
181
  }
179
- props.onChange?.(e);
180
- };
181
- }
182
- const dispatchKey = useId();
183
- const ref = useSubscriptionRef();
184
- const name = String(props.name);
185
- const defaultValue = getDefaultValue();
186
- const defaultChecked = getDefaultChecked();
187
- const onChange = createChangeEventHandler();
182
+ const event = new Event("input", { bubbles: true });
183
+ element.dispatchEvent(event);
184
+ },
185
+ onDispatch: (state, element) => {
186
+ if ("checked" in element && props.type === "checkbox") {
187
+ props.setter(state, element.checked);
188
+ } else {
189
+ props.setter(state, toStateValue(element.value));
190
+ }
191
+ }
192
+ });
188
193
  return {
189
- key: dispatchKey,
190
- ref,
191
- name,
192
- defaultValue,
193
- defaultChecked,
194
- onChange
194
+ ref: inputProps.ref,
195
+ dispatchKey: inputProps.dispatchKey,
196
+ defaultValue: getDefaultValue(),
197
+ defaultChecked: getDefaultChecked(),
198
+ onChange: (event) => {
199
+ inputProps.onChange();
200
+ props.onChange?.(event);
201
+ }
195
202
  };
196
203
  }
197
204
 
198
- // src/use_store_input.tsx
199
- 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 });
205
+ // src/use_store_input_with_name.tsx
206
+ function useStoreInputWithName(store, props) {
207
+ const inputProps = useStoreInput(store, {
208
+ ...props,
209
+ getter: (state) => {
210
+ if (props.getter) {
211
+ return props.getter(state);
212
+ }
213
+ return state[props.name];
209
214
  },
210
- []
211
- );
215
+ setter: (state, value) => {
216
+ if (props.setter) {
217
+ props.setter(state, value);
218
+ return;
219
+ }
220
+ state[props.name] = value;
221
+ }
222
+ });
223
+ return {
224
+ ...inputProps,
225
+ name: "name" in props ? String(props.name) : void 0
226
+ };
227
+ }
228
+
229
+ // src/use_store_component.tsx
230
+ import {
231
+ useCallback
232
+ } from "react";
233
+ import React from "react";
234
+ function useStoreComponent(store) {
235
+ const input = useCallback(function Component(props) {
236
+ return /* @__PURE__ */ React.createElement(Input, { store, ...props });
237
+ }, []);
238
+ const select = useCallback(function Component(props) {
239
+ return /* @__PURE__ */ React.createElement(Select, { store, ...props });
240
+ }, []);
212
241
  const textarea = useCallback(function Component(props) {
213
242
  return /* @__PURE__ */ React.createElement(Textarea, { store, ...props });
214
243
  }, []);
@@ -218,23 +247,32 @@ function useStoreInput(store) {
218
247
  textarea
219
248
  };
220
249
  }
221
- function Input({ store, ...props }) {
222
- const storeProps = useStoreInputProps(store, props);
250
+ function Input({
251
+ store,
252
+ ...props
253
+ }) {
254
+ const storeProps = useStoreInputWithName(store, props);
223
255
  return /* @__PURE__ */ React.createElement("input", { ...props, ...storeProps });
224
256
  }
225
- function Select({ store, ...props }) {
226
- const storeProps = useStoreInputProps(store, props);
257
+ function Select({
258
+ store,
259
+ ...props
260
+ }) {
261
+ const storeProps = useStoreInputWithName(store, props);
227
262
  return /* @__PURE__ */ React.createElement("select", { ...props, ...storeProps });
228
263
  }
229
- function Textarea({ store, ...props }) {
230
- const storeProps = useStoreInputProps(store, props);
264
+ function Textarea({
265
+ store,
266
+ ...props
267
+ }) {
268
+ const storeProps = useStoreInputWithName(store, props);
231
269
  return /* @__PURE__ */ React.createElement("textarea", { ...props, ...storeProps });
232
270
  }
233
271
 
234
272
  // src/create_render.tsx
235
273
  import React2 from "react";
236
- function createRender(store) {
237
- return function createRender2(selector, compare) {
274
+ function createRenderWithStore(store) {
275
+ return function createRender(selector, compare) {
238
276
  function Component() {
239
277
  const result = useSelector(store, (state) => state, compare);
240
278
  const content = selector(result);
@@ -247,15 +285,15 @@ function createRender(store) {
247
285
  // src/use_form_store.tsx
248
286
  function useFormStore(initialState) {
249
287
  const store = useStore(initialState);
250
- const storeInput = useStoreInput(store);
288
+ const storeComponent = useStoreComponent(store);
251
289
  return {
252
290
  get state() {
253
291
  return store.state;
254
292
  },
255
293
  dispatch: store.dispatch,
256
294
  subscribe: store.subscribe,
257
- render: createRender(store),
258
- ...storeInput
295
+ render: createRenderWithStore(store),
296
+ ...storeComponent
259
297
  };
260
298
  }
261
299
 
@@ -354,7 +392,9 @@ export {
354
392
  useFormStore,
355
393
  useSelector,
356
394
  useStore,
395
+ useStoreComponent,
396
+ useStoreController,
357
397
  useStoreInput,
358
- useStoreInputProps,
398
+ useStoreInputWithName,
359
399
  useSubscribe
360
400
  };
@@ -1,9 +1,9 @@
1
1
  import { CreateRender } from './create_render.mjs';
2
2
  import { Store } from './use_store.mjs';
3
- import { useStoreInput } from './use_store_input.mjs';
3
+ import { useStoreComponent } from './use_store_component.mjs';
4
4
  import 'react';
5
5
 
6
- type FormStore<TState> = Store<TState> & ReturnType<typeof useStoreInput<TState>> & {
6
+ type FormStore<TState> = Store<TState> & ReturnType<typeof useStoreComponent<TState>> & {
7
7
  render: CreateRender<TState>;
8
8
  };
9
9
  declare function useFormStore<TState>(initialState: TState): FormStore<TState>;
@@ -1,9 +1,9 @@
1
1
  import { CreateRender } from './create_render.js';
2
2
  import { Store } from './use_store.js';
3
- import { useStoreInput } from './use_store_input.js';
3
+ import { useStoreComponent } from './use_store_component.js';
4
4
  import 'react';
5
5
 
6
- type FormStore<TState> = Store<TState> & ReturnType<typeof useStoreInput<TState>> & {
6
+ type FormStore<TState> = Store<TState> & ReturnType<typeof useStoreComponent<TState>> & {
7
7
  render: CreateRender<TState>;
8
8
  };
9
9
  declare function useFormStore<TState>(initialState: TState): FormStore<TState>;
@@ -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);
@@ -118,14 +118,58 @@ function useStore(initialState) {
118
118
  };
119
119
  }
120
120
 
121
+ // src/use_store_component.tsx
122
+ var import_react7 = require("react");
123
+ var import_react8 = __toESM(require("react"));
124
+
121
125
  // src/use_store_input.tsx
122
126
  var import_react6 = require("react");
123
- var import_react7 = __toESM(require("react"));
127
+ var import_date_fns = require("date-fns");
124
128
 
125
- // src/use_store_input_props.tsx
129
+ // src/use_store_controller.tsx
126
130
  var import_react5 = require("react");
127
- var import_date_fns = require("date-fns");
128
- function useStoreInputProps(store, props) {
131
+ function useStoreController(store, props) {
132
+ const ref = (0, import_react5.useRef)(null);
133
+ const dispatchKey = (0, import_react5.useId)();
134
+ (0, import_react5.useEffect)(() => {
135
+ const element = ref.current;
136
+ if (!element) {
137
+ return;
138
+ }
139
+ if (typeof props.ref === "function") {
140
+ props.ref(element);
141
+ } else if (props.ref) {
142
+ props.ref.current = element;
143
+ }
144
+ }, []);
145
+ useSubscribe(store, (state, key) => {
146
+ if (key === dispatchKey) {
147
+ return;
148
+ }
149
+ if (!ref.current) return;
150
+ props.onSubscribe(state, ref.current);
151
+ });
152
+ const onChange = () => {
153
+ store.dispatch(
154
+ (state) => {
155
+ const element = ref.current;
156
+ if (!element) return;
157
+ props.onDispatch(state, element);
158
+ },
159
+ {
160
+ key: dispatchKey
161
+ }
162
+ );
163
+ };
164
+ return {
165
+ dispatchKey,
166
+ ref,
167
+ onChange
168
+ };
169
+ }
170
+
171
+ // src/use_store_input.tsx
172
+ function useStoreInput(store, props) {
129
173
  const toInputValue = (value) => {
130
174
  if (value === void 0 || value === null) {
131
175
  return "";
@@ -147,7 +191,7 @@ function useStoreInputProps(store, props) {
147
191
  if (props.type === "checkbox" || props.type === "radio") {
148
192
  return void 0;
149
193
  }
150
- return toInputValue(store.state[props.name]);
194
+ return toInputValue(props.getter(store.state));
151
195
  };
152
196
  const toInputChecked = (value) => {
153
197
  if (props.type === "radio") {
@@ -162,98 +206,91 @@ function useStoreInputProps(store, props) {
162
206
  if (props.type !== "checkbox" && props.type !== "radio") {
163
207
  return void 0;
164
208
  }
165
- return toInputChecked(store.state[props.name]);
209
+ return toInputChecked(props.getter(store.state));
166
210
  };
167
- function useSubscriptionRef() {
168
- const ref2 = (0, import_react5.useRef)(null);
169
- (0, import_react5.useEffect)(() => {
170
- return store.subscribe((state, key) => {
171
- if (key === dispatchKey) {
172
- return;
173
- }
174
- const input = ref2.current;
175
- if (!input) {
176
- return;
177
- }
178
- if (props.type === "checkbox" || props.type === "radio") {
179
- const checked = toInputChecked(state[props.name]);
180
- if (input.checked === checked) {
181
- return;
182
- }
183
- input.checked = checked;
184
- } else {
185
- const value = toInputValue(state[props.name]);
186
- if (input.value === value) {
187
- return;
188
- }
189
- input.value = value;
190
- }
191
- const event = new Event("input", { bubbles: true });
192
- input.dispatchEvent(event);
193
- });
194
- }, []);
195
- return ref2;
196
- }
197
211
  function toStateValue(value) {
198
- if (typeof store.state[props.name] === "number") {
212
+ const selected = props.getter(store.state);
213
+ if (typeof selected === "number") {
199
214
  return Number(value);
200
215
  }
201
- if (store.state[props.name] instanceof Date) {
216
+ if (selected instanceof Date) {
202
217
  return new Date(value);
203
218
  }
204
219
  return value;
205
220
  }
206
- function createChangeEventHandler() {
207
- return (e) => {
208
- const target = e.target;
209
- if (props.type === "checkbox") {
210
- store.dispatch((state) => {
211
- state[props.name] = target.checked;
212
- }, {
213
- key: dispatchKey
214
- });
221
+ const inputProps = useStoreController(store, {
222
+ ref: props.ref,
223
+ onSubscribe: (state, element) => {
224
+ if ("checked" in element && (props.type === "checkbox" || props.type === "radio")) {
225
+ const checked = toInputChecked(props.getter(state));
226
+ if (element.checked === checked) {
227
+ return;
228
+ }
229
+ element.checked = checked;
215
230
  } else {
216
- store.dispatch((state) => {
217
- state[props.name] = toStateValue(target.value);
218
- }, {
219
- key: dispatchKey
220
- });
231
+ const value = toInputValue(props.getter(state));
232
+ if (element.value === value) {
233
+ return;
234
+ }
235
+ element.value = value;
221
236
  }
222
- props.onChange?.(e);
223
- };
224
- }
225
- const dispatchKey = (0, import_react5.useId)();
226
- const ref = useSubscriptionRef();
227
- const name = String(props.name);
228
- const defaultValue = getDefaultValue();
229
- const defaultChecked = getDefaultChecked();
230
- const onChange = createChangeEventHandler();
237
+ const event = new Event("input", { bubbles: true });
238
+ element.dispatchEvent(event);
239
+ },
240
+ onDispatch: (state, element) => {
241
+ if ("checked" in element && props.type === "checkbox") {
242
+ props.setter(state, element.checked);
243
+ } else {
244
+ props.setter(state, toStateValue(element.value));
245
+ }
246
+ }
247
+ });
231
248
  return {
232
- key: dispatchKey,
233
- ref,
234
- name,
235
- defaultValue,
236
- defaultChecked,
237
- onChange
249
+ ref: inputProps.ref,
250
+ dispatchKey: inputProps.dispatchKey,
251
+ defaultValue: getDefaultValue(),
252
+ defaultChecked: getDefaultChecked(),
253
+ onChange: (event) => {
254
+ inputProps.onChange();
255
+ props.onChange?.(event);
256
+ }
238
257
  };
239
258
  }
240
259
 
241
- // src/use_store_input.tsx
242
- 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 });
260
+ // src/use_store_input_with_name.tsx
261
+ function useStoreInputWithName(store, props) {
262
+ const inputProps = useStoreInput(store, {
263
+ ...props,
264
+ getter: (state) => {
265
+ if (props.getter) {
266
+ return props.getter(state);
267
+ }
268
+ return state[props.name];
252
269
  },
253
- []
254
- );
255
- const textarea = (0, import_react6.useCallback)(function Component(props) {
256
- return /* @__PURE__ */ import_react7.default.createElement(Textarea, { store, ...props });
270
+ setter: (state, value) => {
271
+ if (props.setter) {
272
+ props.setter(state, value);
273
+ return;
274
+ }
275
+ state[props.name] = value;
276
+ }
277
+ });
278
+ return {
279
+ ...inputProps,
280
+ name: "name" in props ? String(props.name) : void 0
281
+ };
282
+ }
283
+
284
+ // src/use_store_component.tsx
285
+ function useStoreComponent(store) {
286
+ const input = (0, import_react7.useCallback)(function Component(props) {
287
+ return /* @__PURE__ */ import_react8.default.createElement(Input, { store, ...props });
288
+ }, []);
289
+ const select = (0, import_react7.useCallback)(function Component(props) {
290
+ return /* @__PURE__ */ import_react8.default.createElement(Select, { store, ...props });
291
+ }, []);
292
+ const textarea = (0, import_react7.useCallback)(function Component(props) {
293
+ return /* @__PURE__ */ import_react8.default.createElement(Textarea, { store, ...props });
257
294
  }, []);
258
295
  return {
259
296
  input,
@@ -261,31 +298,40 @@ function useStoreInput(store) {
261
298
  textarea
262
299
  };
263
300
  }
264
- function Input({ store, ...props }) {
265
- const storeProps = useStoreInputProps(store, props);
266
- return /* @__PURE__ */ import_react7.default.createElement("input", { ...props, ...storeProps });
301
+ function Input({
302
+ store,
303
+ ...props
304
+ }) {
305
+ const storeProps = useStoreInputWithName(store, props);
306
+ return /* @__PURE__ */ import_react8.default.createElement("input", { ...props, ...storeProps });
267
307
  }
268
- function Select({ store, ...props }) {
269
- const storeProps = useStoreInputProps(store, props);
270
- return /* @__PURE__ */ import_react7.default.createElement("select", { ...props, ...storeProps });
308
+ function Select({
309
+ store,
310
+ ...props
311
+ }) {
312
+ const storeProps = useStoreInputWithName(store, props);
313
+ return /* @__PURE__ */ import_react8.default.createElement("select", { ...props, ...storeProps });
271
314
  }
272
- function Textarea({ store, ...props }) {
273
- const storeProps = useStoreInputProps(store, props);
274
- return /* @__PURE__ */ import_react7.default.createElement("textarea", { ...props, ...storeProps });
315
+ function Textarea({
316
+ store,
317
+ ...props
318
+ }) {
319
+ const storeProps = useStoreInputWithName(store, props);
320
+ return /* @__PURE__ */ import_react8.default.createElement("textarea", { ...props, ...storeProps });
275
321
  }
276
322
 
277
323
  // src/use_form_store.tsx
278
324
  function useFormStore(initialState) {
279
325
  const store = useStore(initialState);
280
- const storeInput = useStoreInput(store);
326
+ const storeComponent = useStoreComponent(store);
281
327
  return {
282
328
  get state() {
283
329
  return store.state;
284
330
  },
285
331
  dispatch: store.dispatch,
286
332
  subscribe: store.subscribe,
287
- render: createRender(store),
288
- ...storeInput
333
+ render: createRenderWithStore(store),
334
+ ...storeComponent
289
335
  };
290
336
  }
291
337
  // Annotate the CommonJS export names for ESM import in node: