react-store-input 0.1.1 → 0.1.4

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,51 @@ 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
+ ref,
109
+ onChange
110
+ };
111
+ }
77
112
 
78
- // src/use_store_input_props.tsx
79
- import {
80
- useEffect as useEffect2,
81
- useId,
82
- useRef as useRef2
83
- } from "react";
113
+ // src/use_store_input.tsx
114
+ import "react";
84
115
  import { format } from "date-fns";
85
- function useStoreInputProps(store, props) {
116
+ function useStoreInput(store, props) {
86
117
  const toInputValue = (value) => {
87
118
  if (value === void 0 || value === null) {
88
119
  return "";
@@ -104,7 +135,7 @@ function useStoreInputProps(store, props) {
104
135
  if (props.type === "checkbox" || props.type === "radio") {
105
136
  return void 0;
106
137
  }
107
- return toInputValue(store.state[props.name]);
138
+ return toInputValue(props.getter(store.state));
108
139
  };
109
140
  const toInputChecked = (value) => {
110
141
  if (props.type === "radio") {
@@ -119,95 +150,86 @@ function useStoreInputProps(store, props) {
119
150
  if (props.type !== "checkbox" && props.type !== "radio") {
120
151
  return void 0;
121
152
  }
122
- return toInputChecked(store.state[props.name]);
153
+ return toInputChecked(props.getter(store.state));
123
154
  };
124
- function useSubscriptionRef() {
125
- const ref2 = useRef2(null);
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
- }
136
- return store.subscribe((state, key) => {
137
- if (key === dispatchKey) {
138
- return;
139
- }
140
- if (props.type === "checkbox" || props.type === "radio") {
141
- const checked = toInputChecked(state[props.name]);
142
- if (input.checked === checked) {
143
- return;
144
- }
145
- input.checked = checked;
146
- } else {
147
- const value = toInputValue(state[props.name]);
148
- if (input.value === value) {
149
- return;
150
- }
151
- input.value = value;
152
- }
153
- const event = new Event("input", { bubbles: true });
154
- input.dispatchEvent(event);
155
- });
156
- }, []);
157
- return ref2;
158
- }
159
155
  function toStateValue(value) {
160
- if (typeof store.state[props.name] === "number") {
156
+ const selected = props.getter(store.state);
157
+ if (typeof selected === "number") {
161
158
  return Number(value);
162
159
  }
163
- if (store.state[props.name] instanceof Date) {
160
+ if (selected instanceof Date) {
164
161
  return new Date(value);
165
162
  }
166
163
  return value;
167
164
  }
168
- function createChangeEventHandler() {
169
- return (e) => {
170
- const target = e.target;
171
- if (props.type === "checkbox") {
172
- store.dispatch(
173
- (state) => {
174
- state[props.name] = target.checked;
175
- },
176
- {
177
- key: dispatchKey
178
- }
179
- );
165
+ const inputProps = useStoreController(store, {
166
+ ref: props.ref,
167
+ onSubscribe: (state, element) => {
168
+ if ("checked" in element && (props.type === "checkbox" || props.type === "radio")) {
169
+ const checked = toInputChecked(props.getter(state));
170
+ if (element.checked === checked) {
171
+ return;
172
+ }
173
+ element.checked = checked;
180
174
  } else {
181
- store.dispatch(
182
- (state) => {
183
- state[props.name] = toStateValue(target.value);
184
- },
185
- {
186
- key: dispatchKey
187
- }
188
- );
175
+ const value = toInputValue(props.getter(state));
176
+ if (element.value === value) {
177
+ return;
178
+ }
179
+ element.value = value;
189
180
  }
190
- props.onChange?.(e);
191
- };
192
- }
193
- const dispatchKey = useId();
194
- const ref = useSubscriptionRef();
195
- const name = String(props.name);
196
- const defaultValue = getDefaultValue();
197
- const defaultChecked = getDefaultChecked();
198
- const onChange = createChangeEventHandler();
181
+ const event = new Event("input", { bubbles: true });
182
+ element.dispatchEvent(event);
183
+ },
184
+ onDispatch: (state, element) => {
185
+ if ("checked" in element && props.type === "checkbox") {
186
+ props.setter(state, element.checked);
187
+ } else {
188
+ props.setter(state, toStateValue(element.value));
189
+ }
190
+ }
191
+ });
199
192
  return {
200
- key: dispatchKey,
201
- ref,
202
- name,
203
- defaultValue,
204
- defaultChecked,
205
- onChange
193
+ ref: inputProps.ref,
194
+ defaultValue: getDefaultValue(),
195
+ defaultChecked: getDefaultChecked(),
196
+ onChange: (event) => {
197
+ inputProps.onChange();
198
+ props.onChange?.(event);
199
+ }
206
200
  };
207
201
  }
208
202
 
209
- // src/use_store_input.tsx
210
- function useStoreInput(store) {
203
+ // src/use_store_input_with_name.tsx
204
+ function useStoreInputWithName(store, props) {
205
+ const inputProps = useStoreInput(store, {
206
+ ...props,
207
+ getter: (state) => {
208
+ if (props.getter) {
209
+ return props.getter(state);
210
+ }
211
+ return state[props.name];
212
+ },
213
+ setter: (state, value) => {
214
+ if (props.setter) {
215
+ props.setter(state, value);
216
+ return;
217
+ }
218
+ state[props.name] = value;
219
+ }
220
+ });
221
+ return {
222
+ ...inputProps,
223
+ name: "name" in props ? String(props.name) : void 0
224
+ };
225
+ }
226
+
227
+ // src/use_store_component.tsx
228
+ import {
229
+ useCallback
230
+ } from "react";
231
+ import React from "react";
232
+ function useStoreComponent(store) {
211
233
  const input = useCallback(function Component(props) {
212
234
  return /* @__PURE__ */ React.createElement(Input, { store, ...props });
213
235
  }, []);
@@ -225,23 +247,29 @@ function useStoreInput(store) {
225
247
  }
226
248
  function Input({
227
249
  store,
250
+ getter,
251
+ setter,
228
252
  ...props
229
253
  }) {
230
- const storeProps = useStoreInputProps(store, props);
254
+ const storeProps = useStoreInputWithName(store, { ...props, getter, setter });
231
255
  return /* @__PURE__ */ React.createElement("input", { ...props, ...storeProps });
232
256
  }
233
257
  function Select({
234
258
  store,
259
+ getter,
260
+ setter,
235
261
  ...props
236
262
  }) {
237
- const storeProps = useStoreInputProps(store, props);
263
+ const storeProps = useStoreInputWithName(store, { ...props, getter, setter });
238
264
  return /* @__PURE__ */ React.createElement("select", { ...props, ...storeProps });
239
265
  }
240
266
  function Textarea({
241
267
  store,
268
+ getter,
269
+ setter,
242
270
  ...props
243
271
  }) {
244
- const storeProps = useStoreInputProps(store, props);
272
+ const storeProps = useStoreInputWithName(store, { ...props, getter, setter });
245
273
  return /* @__PURE__ */ React.createElement("textarea", { ...props, ...storeProps });
246
274
  }
247
275
 
@@ -261,7 +289,7 @@ function createRenderWithStore(store) {
261
289
  // src/use_form_store.tsx
262
290
  function useFormStore(initialState) {
263
291
  const store = useStore(initialState);
264
- const storeInput = useStoreInput(store);
292
+ const storeComponent = useStoreComponent(store);
265
293
  return {
266
294
  get state() {
267
295
  return store.state;
@@ -269,7 +297,7 @@ function useFormStore(initialState) {
269
297
  dispatch: store.dispatch,
270
298
  subscribe: store.subscribe,
271
299
  render: createRenderWithStore(store),
272
- ...storeInput
300
+ ...storeComponent
273
301
  };
274
302
  }
275
303
 
@@ -368,7 +396,9 @@ export {
368
396
  useFormStore,
369
397
  useSelector,
370
398
  useStore,
399
+ useStoreComponent,
400
+ useStoreController,
371
401
  useStoreInput,
372
- useStoreInputProps,
402
+ useStoreInputWithName,
373
403
  useSubscribe
374
404
  };
@@ -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>;
@@ -118,14 +118,57 @@ 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
+ ref,
166
+ onChange
167
+ };
168
+ }
169
+
170
+ // src/use_store_input.tsx
171
+ function useStoreInput(store, props) {
129
172
  const toInputValue = (value) => {
130
173
  if (value === void 0 || value === null) {
131
174
  return "";
@@ -147,7 +190,7 @@ function useStoreInputProps(store, props) {
147
190
  if (props.type === "checkbox" || props.type === "radio") {
148
191
  return void 0;
149
192
  }
150
- return toInputValue(store.state[props.name]);
193
+ return toInputValue(props.getter(store.state));
151
194
  };
152
195
  const toInputChecked = (value) => {
153
196
  if (props.type === "radio") {
@@ -162,103 +205,90 @@ function useStoreInputProps(store, props) {
162
205
  if (props.type !== "checkbox" && props.type !== "radio") {
163
206
  return void 0;
164
207
  }
165
- return toInputChecked(store.state[props.name]);
208
+ return toInputChecked(props.getter(store.state));
166
209
  };
167
- function useSubscriptionRef() {
168
- const ref2 = (0, import_react5.useRef)(null);
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
- }
179
- return store.subscribe((state, key) => {
180
- if (key === dispatchKey) {
181
- return;
182
- }
183
- if (props.type === "checkbox" || props.type === "radio") {
184
- const checked = toInputChecked(state[props.name]);
185
- if (input.checked === checked) {
186
- return;
187
- }
188
- input.checked = checked;
189
- } else {
190
- const value = toInputValue(state[props.name]);
191
- if (input.value === value) {
192
- return;
193
- }
194
- input.value = value;
195
- }
196
- const event = new Event("input", { bubbles: true });
197
- input.dispatchEvent(event);
198
- });
199
- }, []);
200
- return ref2;
201
- }
202
210
  function toStateValue(value) {
203
- if (typeof store.state[props.name] === "number") {
211
+ const selected = props.getter(store.state);
212
+ if (typeof selected === "number") {
204
213
  return Number(value);
205
214
  }
206
- if (store.state[props.name] instanceof Date) {
215
+ if (selected instanceof Date) {
207
216
  return new Date(value);
208
217
  }
209
218
  return value;
210
219
  }
211
- function createChangeEventHandler() {
212
- return (e) => {
213
- const target = e.target;
214
- if (props.type === "checkbox") {
215
- store.dispatch(
216
- (state) => {
217
- state[props.name] = target.checked;
218
- },
219
- {
220
- key: dispatchKey
221
- }
222
- );
220
+ const inputProps = useStoreController(store, {
221
+ ref: props.ref,
222
+ onSubscribe: (state, element) => {
223
+ if ("checked" in element && (props.type === "checkbox" || props.type === "radio")) {
224
+ const checked = toInputChecked(props.getter(state));
225
+ if (element.checked === checked) {
226
+ return;
227
+ }
228
+ element.checked = checked;
223
229
  } else {
224
- store.dispatch(
225
- (state) => {
226
- state[props.name] = toStateValue(target.value);
227
- },
228
- {
229
- key: dispatchKey
230
- }
231
- );
230
+ const value = toInputValue(props.getter(state));
231
+ if (element.value === value) {
232
+ return;
233
+ }
234
+ element.value = value;
232
235
  }
233
- props.onChange?.(e);
234
- };
235
- }
236
- const dispatchKey = (0, import_react5.useId)();
237
- const ref = useSubscriptionRef();
238
- const name = String(props.name);
239
- const defaultValue = getDefaultValue();
240
- const defaultChecked = getDefaultChecked();
241
- const onChange = createChangeEventHandler();
236
+ const event = new Event("input", { bubbles: true });
237
+ element.dispatchEvent(event);
238
+ },
239
+ onDispatch: (state, element) => {
240
+ if ("checked" in element && props.type === "checkbox") {
241
+ props.setter(state, element.checked);
242
+ } else {
243
+ props.setter(state, toStateValue(element.value));
244
+ }
245
+ }
246
+ });
242
247
  return {
243
- key: dispatchKey,
244
- ref,
245
- name,
246
- defaultValue,
247
- defaultChecked,
248
- onChange
248
+ ref: inputProps.ref,
249
+ defaultValue: getDefaultValue(),
250
+ defaultChecked: getDefaultChecked(),
251
+ onChange: (event) => {
252
+ inputProps.onChange();
253
+ props.onChange?.(event);
254
+ }
249
255
  };
250
256
  }
251
257
 
252
- // src/use_store_input.tsx
253
- function useStoreInput(store) {
254
- const input = (0, import_react6.useCallback)(function Component(props) {
255
- return /* @__PURE__ */ import_react7.default.createElement(Input, { store, ...props });
258
+ // src/use_store_input_with_name.tsx
259
+ function useStoreInputWithName(store, props) {
260
+ const inputProps = useStoreInput(store, {
261
+ ...props,
262
+ getter: (state) => {
263
+ if (props.getter) {
264
+ return props.getter(state);
265
+ }
266
+ return state[props.name];
267
+ },
268
+ setter: (state, value) => {
269
+ if (props.setter) {
270
+ props.setter(state, value);
271
+ return;
272
+ }
273
+ state[props.name] = value;
274
+ }
275
+ });
276
+ return {
277
+ ...inputProps,
278
+ name: "name" in props ? String(props.name) : void 0
279
+ };
280
+ }
281
+
282
+ // src/use_store_component.tsx
283
+ function useStoreComponent(store) {
284
+ const input = (0, import_react7.useCallback)(function Component(props) {
285
+ return /* @__PURE__ */ import_react8.default.createElement(Input, { store, ...props });
256
286
  }, []);
257
- const select = (0, import_react6.useCallback)(function Component(props) {
258
- return /* @__PURE__ */ import_react7.default.createElement(Select, { store, ...props });
287
+ const select = (0, import_react7.useCallback)(function Component(props) {
288
+ return /* @__PURE__ */ import_react8.default.createElement(Select, { store, ...props });
259
289
  }, []);
260
- const textarea = (0, import_react6.useCallback)(function Component(props) {
261
- return /* @__PURE__ */ import_react7.default.createElement(Textarea, { store, ...props });
290
+ const textarea = (0, import_react7.useCallback)(function Component(props) {
291
+ return /* @__PURE__ */ import_react8.default.createElement(Textarea, { store, ...props });
262
292
  }, []);
263
293
  return {
264
294
  input,
@@ -268,30 +298,36 @@ function useStoreInput(store) {
268
298
  }
269
299
  function Input({
270
300
  store,
301
+ getter,
302
+ setter,
271
303
  ...props
272
304
  }) {
273
- const storeProps = useStoreInputProps(store, props);
274
- return /* @__PURE__ */ import_react7.default.createElement("input", { ...props, ...storeProps });
305
+ const storeProps = useStoreInputWithName(store, { ...props, getter, setter });
306
+ return /* @__PURE__ */ import_react8.default.createElement("input", { ...props, ...storeProps });
275
307
  }
276
308
  function Select({
277
309
  store,
310
+ getter,
311
+ setter,
278
312
  ...props
279
313
  }) {
280
- const storeProps = useStoreInputProps(store, props);
281
- return /* @__PURE__ */ import_react7.default.createElement("select", { ...props, ...storeProps });
314
+ const storeProps = useStoreInputWithName(store, { ...props, getter, setter });
315
+ return /* @__PURE__ */ import_react8.default.createElement("select", { ...props, ...storeProps });
282
316
  }
283
317
  function Textarea({
284
318
  store,
319
+ getter,
320
+ setter,
285
321
  ...props
286
322
  }) {
287
- const storeProps = useStoreInputProps(store, props);
288
- return /* @__PURE__ */ import_react7.default.createElement("textarea", { ...props, ...storeProps });
323
+ const storeProps = useStoreInputWithName(store, { ...props, getter, setter });
324
+ return /* @__PURE__ */ import_react8.default.createElement("textarea", { ...props, ...storeProps });
289
325
  }
290
326
 
291
327
  // src/use_form_store.tsx
292
328
  function useFormStore(initialState) {
293
329
  const store = useStore(initialState);
294
- const storeInput = useStoreInput(store);
330
+ const storeComponent = useStoreComponent(store);
295
331
  return {
296
332
  get state() {
297
333
  return store.state;
@@ -299,7 +335,7 @@ function useFormStore(initialState) {
299
335
  dispatch: store.dispatch,
300
336
  subscribe: store.subscribe,
301
337
  render: createRenderWithStore(store),
302
- ...storeInput
338
+ ...storeComponent
303
339
  };
304
340
  }
305
341
  // Annotate the CommonJS export names for ESM import in node: