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.
@@ -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);
@@ -82,20 +82,60 @@ function useStore(initialState) {
82
82
  };
83
83
  }
84
84
 
85
- // src/use_store_input.tsx
85
+ // src/use_store_component.tsx
86
86
  import {
87
87
  useCallback
88
88
  } from "react";
89
89
  import React2 from "react";
90
90
 
91
- // src/use_store_input_props.tsx
92
- import {
93
- useEffect as useEffect2,
94
- useId,
95
- useRef as useRef2
96
- } from "react";
91
+ // src/use_store_input.tsx
92
+ import "react";
97
93
  import { format } from "date-fns";
98
- function useStoreInputProps(store, props) {
94
+
95
+ // src/use_store_controller.tsx
96
+ import { useEffect as useEffect2, useId, useRef as useRef2 } from "react";
97
+ function useStoreController(store, props) {
98
+ const ref = useRef2(null);
99
+ const dispatchKey = useId();
100
+ useEffect2(() => {
101
+ const element = ref.current;
102
+ if (!element) {
103
+ return;
104
+ }
105
+ if (typeof props.ref === "function") {
106
+ props.ref(element);
107
+ } else if (props.ref) {
108
+ props.ref.current = element;
109
+ }
110
+ }, []);
111
+ useSubscribe(store, (state, key) => {
112
+ if (key === dispatchKey) {
113
+ return;
114
+ }
115
+ if (!ref.current) return;
116
+ props.onSubscribe(state, ref.current);
117
+ });
118
+ const onChange = () => {
119
+ store.dispatch(
120
+ (state) => {
121
+ const element = ref.current;
122
+ if (!element) return;
123
+ props.onDispatch(state, element);
124
+ },
125
+ {
126
+ key: dispatchKey
127
+ }
128
+ );
129
+ };
130
+ return {
131
+ dispatchKey,
132
+ ref,
133
+ onChange
134
+ };
135
+ }
136
+
137
+ // src/use_store_input.tsx
138
+ function useStoreInput(store, props) {
99
139
  const toInputValue = (value) => {
100
140
  if (value === void 0 || value === null) {
101
141
  return "";
@@ -117,7 +157,7 @@ function useStoreInputProps(store, props) {
117
157
  if (props.type === "checkbox" || props.type === "radio") {
118
158
  return void 0;
119
159
  }
120
- return toInputValue(store.state[props.name]);
160
+ return toInputValue(props.getter(store.state));
121
161
  };
122
162
  const toInputChecked = (value) => {
123
163
  if (props.type === "radio") {
@@ -132,96 +172,89 @@ function useStoreInputProps(store, props) {
132
172
  if (props.type !== "checkbox" && props.type !== "radio") {
133
173
  return void 0;
134
174
  }
135
- return toInputChecked(store.state[props.name]);
175
+ return toInputChecked(props.getter(store.state));
136
176
  };
137
- function useSubscriptionRef() {
138
- const ref2 = useRef2(null);
139
- useEffect2(() => {
140
- return store.subscribe((state, key) => {
141
- if (key === dispatchKey) {
142
- return;
143
- }
144
- const input = ref2.current;
145
- if (!input) {
146
- return;
147
- }
148
- if (props.type === "checkbox" || props.type === "radio") {
149
- const checked = toInputChecked(state[props.name]);
150
- if (input.checked === checked) {
151
- return;
152
- }
153
- input.checked = checked;
154
- } else {
155
- const value = toInputValue(state[props.name]);
156
- if (input.value === value) {
157
- return;
158
- }
159
- input.value = value;
160
- }
161
- const event = new Event("input", { bubbles: true });
162
- input.dispatchEvent(event);
163
- });
164
- }, []);
165
- return ref2;
166
- }
167
177
  function toStateValue(value) {
168
- if (typeof store.state[props.name] === "number") {
178
+ const selected = props.getter(store.state);
179
+ if (typeof selected === "number") {
169
180
  return Number(value);
170
181
  }
171
- if (store.state[props.name] instanceof Date) {
182
+ if (selected instanceof Date) {
172
183
  return new Date(value);
173
184
  }
174
185
  return value;
175
186
  }
176
- function createChangeEventHandler() {
177
- return (e) => {
178
- const target = e.target;
179
- if (props.type === "checkbox") {
180
- store.dispatch((state) => {
181
- state[props.name] = target.checked;
182
- }, {
183
- key: dispatchKey
184
- });
187
+ const inputProps = useStoreController(store, {
188
+ ref: props.ref,
189
+ onSubscribe: (state, element) => {
190
+ if ("checked" in element && (props.type === "checkbox" || props.type === "radio")) {
191
+ const checked = toInputChecked(props.getter(state));
192
+ if (element.checked === checked) {
193
+ return;
194
+ }
195
+ element.checked = checked;
185
196
  } else {
186
- store.dispatch((state) => {
187
- state[props.name] = toStateValue(target.value);
188
- }, {
189
- key: dispatchKey
190
- });
197
+ const value = toInputValue(props.getter(state));
198
+ if (element.value === value) {
199
+ return;
200
+ }
201
+ element.value = value;
191
202
  }
192
- props.onChange?.(e);
193
- };
194
- }
195
- const dispatchKey = useId();
196
- const ref = useSubscriptionRef();
197
- const name = String(props.name);
198
- const defaultValue = getDefaultValue();
199
- const defaultChecked = getDefaultChecked();
200
- const onChange = createChangeEventHandler();
203
+ const event = new Event("input", { bubbles: true });
204
+ element.dispatchEvent(event);
205
+ },
206
+ onDispatch: (state, element) => {
207
+ if ("checked" in element && props.type === "checkbox") {
208
+ props.setter(state, element.checked);
209
+ } else {
210
+ props.setter(state, toStateValue(element.value));
211
+ }
212
+ }
213
+ });
201
214
  return {
202
- key: dispatchKey,
203
- ref,
204
- name,
205
- defaultValue,
206
- defaultChecked,
207
- onChange
215
+ ref: inputProps.ref,
216
+ dispatchKey: inputProps.dispatchKey,
217
+ defaultValue: getDefaultValue(),
218
+ defaultChecked: getDefaultChecked(),
219
+ onChange: (event) => {
220
+ inputProps.onChange();
221
+ props.onChange?.(event);
222
+ }
208
223
  };
209
224
  }
210
225
 
211
- // src/use_store_input.tsx
212
- 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 });
226
+ // src/use_store_input_with_name.tsx
227
+ function useStoreInputWithName(store, props) {
228
+ const inputProps = useStoreInput(store, {
229
+ ...props,
230
+ getter: (state) => {
231
+ if (props.getter) {
232
+ return props.getter(state);
233
+ }
234
+ return state[props.name];
222
235
  },
223
- []
224
- );
236
+ setter: (state, value) => {
237
+ if (props.setter) {
238
+ props.setter(state, value);
239
+ return;
240
+ }
241
+ state[props.name] = value;
242
+ }
243
+ });
244
+ return {
245
+ ...inputProps,
246
+ name: "name" in props ? String(props.name) : void 0
247
+ };
248
+ }
249
+
250
+ // src/use_store_component.tsx
251
+ function useStoreComponent(store) {
252
+ const input = useCallback(function Component(props) {
253
+ return /* @__PURE__ */ React2.createElement(Input, { store, ...props });
254
+ }, []);
255
+ const select = useCallback(function Component(props) {
256
+ return /* @__PURE__ */ React2.createElement(Select, { store, ...props });
257
+ }, []);
225
258
  const textarea = useCallback(function Component(props) {
226
259
  return /* @__PURE__ */ React2.createElement(Textarea, { store, ...props });
227
260
  }, []);
@@ -231,31 +264,40 @@ function useStoreInput(store) {
231
264
  textarea
232
265
  };
233
266
  }
234
- function Input({ store, ...props }) {
235
- const storeProps = useStoreInputProps(store, props);
267
+ function Input({
268
+ store,
269
+ ...props
270
+ }) {
271
+ const storeProps = useStoreInputWithName(store, props);
236
272
  return /* @__PURE__ */ React2.createElement("input", { ...props, ...storeProps });
237
273
  }
238
- function Select({ store, ...props }) {
239
- const storeProps = useStoreInputProps(store, props);
274
+ function Select({
275
+ store,
276
+ ...props
277
+ }) {
278
+ const storeProps = useStoreInputWithName(store, props);
240
279
  return /* @__PURE__ */ React2.createElement("select", { ...props, ...storeProps });
241
280
  }
242
- function Textarea({ store, ...props }) {
243
- const storeProps = useStoreInputProps(store, props);
281
+ function Textarea({
282
+ store,
283
+ ...props
284
+ }) {
285
+ const storeProps = useStoreInputWithName(store, props);
244
286
  return /* @__PURE__ */ React2.createElement("textarea", { ...props, ...storeProps });
245
287
  }
246
288
 
247
289
  // src/use_form_store.tsx
248
290
  function useFormStore(initialState) {
249
291
  const store = useStore(initialState);
250
- const storeInput = useStoreInput(store);
292
+ const storeComponent = useStoreComponent(store);
251
293
  return {
252
294
  get state() {
253
295
  return store.state;
254
296
  },
255
297
  dispatch: store.dispatch,
256
298
  subscribe: store.subscribe,
257
- render: createRender(store),
258
- ...storeInput
299
+ render: createRenderWithStore(store),
300
+ ...storeComponent
259
301
  };
260
302
  }
261
303
  export {
@@ -0,0 +1,21 @@
1
+ import React__default, { DetailedHTMLProps, InputHTMLAttributes } from 'react';
2
+ import { Store } from './use_store.mjs';
3
+
4
+ type StoreComponentProps<TInputElement, TState> = Omit<DetailedHTMLProps<InputHTMLAttributes<TInputElement>, TInputElement>, "name"> & {
5
+ name?: keyof TState;
6
+ getter?: (state: TState) => unknown;
7
+ setter?: (state: TState, value: unknown) => void;
8
+ };
9
+ declare function useStoreComponent<TState>(store: Store<TState>): {
10
+ input: React__default.FC<StoreComponentProps<HTMLInputElement, TState>>;
11
+ select: React__default.FC<StoreComponentProps<HTMLSelectElement, TState>>;
12
+ textarea: React__default.FC<StoreComponentProps<HTMLTextAreaElement, TState>>;
13
+ };
14
+ type StoreComponentPropsWithStore<TElement extends HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, TState> = StoreComponentProps<TElement, TState> & {
15
+ store: Store<TState>;
16
+ };
17
+ declare function Input<TState>({ store, ...props }: StoreComponentPropsWithStore<HTMLInputElement, TState>): React__default.JSX.Element;
18
+ declare function Select<TState>({ store, ...props }: StoreComponentPropsWithStore<HTMLSelectElement, TState>): React__default.JSX.Element;
19
+ declare function Textarea<TState>({ store, ...props }: StoreComponentPropsWithStore<HTMLTextAreaElement, TState>): React__default.JSX.Element;
20
+
21
+ export { Input, Select, type StoreComponentProps, type StoreComponentPropsWithStore, Textarea, useStoreComponent };
@@ -0,0 +1,21 @@
1
+ import React__default, { DetailedHTMLProps, InputHTMLAttributes } from 'react';
2
+ import { Store } from './use_store.js';
3
+
4
+ type StoreComponentProps<TInputElement, TState> = Omit<DetailedHTMLProps<InputHTMLAttributes<TInputElement>, TInputElement>, "name"> & {
5
+ name?: keyof TState;
6
+ getter?: (state: TState) => unknown;
7
+ setter?: (state: TState, value: unknown) => void;
8
+ };
9
+ declare function useStoreComponent<TState>(store: Store<TState>): {
10
+ input: React__default.FC<StoreComponentProps<HTMLInputElement, TState>>;
11
+ select: React__default.FC<StoreComponentProps<HTMLSelectElement, TState>>;
12
+ textarea: React__default.FC<StoreComponentProps<HTMLTextAreaElement, TState>>;
13
+ };
14
+ type StoreComponentPropsWithStore<TElement extends HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, TState> = StoreComponentProps<TElement, TState> & {
15
+ store: Store<TState>;
16
+ };
17
+ declare function Input<TState>({ store, ...props }: StoreComponentPropsWithStore<HTMLInputElement, TState>): React__default.JSX.Element;
18
+ declare function Select<TState>({ store, ...props }: StoreComponentPropsWithStore<HTMLSelectElement, TState>): React__default.JSX.Element;
19
+ declare function Textarea<TState>({ store, ...props }: StoreComponentPropsWithStore<HTMLTextAreaElement, TState>): React__default.JSX.Element;
20
+
21
+ export { Input, Select, type StoreComponentProps, type StoreComponentPropsWithStore, Textarea, useStoreComponent };
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/use_store_component.tsx
31
+ var use_store_component_exports = {};
32
+ __export(use_store_component_exports, {
33
+ Input: () => Input,
34
+ Select: () => Select,
35
+ Textarea: () => Textarea,
36
+ useStoreComponent: () => useStoreComponent
37
+ });
38
+ module.exports = __toCommonJS(use_store_component_exports);
39
+ var import_react4 = require("react");
40
+ var import_react5 = __toESM(require("react"));
41
+
42
+ // src/use_store_input.tsx
43
+ var import_react3 = require("react");
44
+ var import_date_fns = require("date-fns");
45
+
46
+ // src/use_store_controller.tsx
47
+ var import_react2 = require("react");
48
+
49
+ // src/use_subscribe.tsx
50
+ var import_react = require("react");
51
+ function useSubscribe(store, subscriber) {
52
+ (0, import_react.useEffect)(() => {
53
+ const unsubscribe = store.subscribe(subscriber);
54
+ return () => {
55
+ unsubscribe();
56
+ };
57
+ }, [store]);
58
+ }
59
+
60
+ // src/use_store_controller.tsx
61
+ function useStoreController(store, props) {
62
+ const ref = (0, import_react2.useRef)(null);
63
+ const dispatchKey = (0, import_react2.useId)();
64
+ (0, import_react2.useEffect)(() => {
65
+ const element = ref.current;
66
+ if (!element) {
67
+ return;
68
+ }
69
+ if (typeof props.ref === "function") {
70
+ props.ref(element);
71
+ } else if (props.ref) {
72
+ props.ref.current = element;
73
+ }
74
+ }, []);
75
+ useSubscribe(store, (state, key) => {
76
+ if (key === dispatchKey) {
77
+ return;
78
+ }
79
+ if (!ref.current) return;
80
+ props.onSubscribe(state, ref.current);
81
+ });
82
+ const onChange = () => {
83
+ store.dispatch(
84
+ (state) => {
85
+ const element = ref.current;
86
+ if (!element) return;
87
+ props.onDispatch(state, element);
88
+ },
89
+ {
90
+ key: dispatchKey
91
+ }
92
+ );
93
+ };
94
+ return {
95
+ dispatchKey,
96
+ ref,
97
+ onChange
98
+ };
99
+ }
100
+
101
+ // src/use_store_input.tsx
102
+ function useStoreInput(store, props) {
103
+ const toInputValue = (value) => {
104
+ if (value === void 0 || value === null) {
105
+ return "";
106
+ }
107
+ if (props.type === "datetime-local") {
108
+ if (value instanceof Date) {
109
+ return (0, import_date_fns.format)(value, "yyyy-MM-dd'T'HH:mm:ss");
110
+ }
111
+ if (typeof value === "string") {
112
+ return toInputValue(new Date(value));
113
+ }
114
+ }
115
+ return String(value);
116
+ };
117
+ const getDefaultValue = () => {
118
+ if (props.defaultValue !== void 0) {
119
+ return props.defaultValue;
120
+ }
121
+ if (props.type === "checkbox" || props.type === "radio") {
122
+ return void 0;
123
+ }
124
+ return toInputValue(props.getter(store.state));
125
+ };
126
+ const toInputChecked = (value) => {
127
+ if (props.type === "radio") {
128
+ return value !== void 0 && value === props.value;
129
+ }
130
+ return Boolean(value);
131
+ };
132
+ const getDefaultChecked = () => {
133
+ if (props.defaultChecked) {
134
+ return props.defaultChecked;
135
+ }
136
+ if (props.type !== "checkbox" && props.type !== "radio") {
137
+ return void 0;
138
+ }
139
+ return toInputChecked(props.getter(store.state));
140
+ };
141
+ function toStateValue(value) {
142
+ const selected = props.getter(store.state);
143
+ if (typeof selected === "number") {
144
+ return Number(value);
145
+ }
146
+ if (selected instanceof Date) {
147
+ return new Date(value);
148
+ }
149
+ return value;
150
+ }
151
+ const inputProps = useStoreController(store, {
152
+ ref: props.ref,
153
+ onSubscribe: (state, element) => {
154
+ if ("checked" in element && (props.type === "checkbox" || props.type === "radio")) {
155
+ const checked = toInputChecked(props.getter(state));
156
+ if (element.checked === checked) {
157
+ return;
158
+ }
159
+ element.checked = checked;
160
+ } else {
161
+ const value = toInputValue(props.getter(state));
162
+ if (element.value === value) {
163
+ return;
164
+ }
165
+ element.value = value;
166
+ }
167
+ const event = new Event("input", { bubbles: true });
168
+ element.dispatchEvent(event);
169
+ },
170
+ onDispatch: (state, element) => {
171
+ if ("checked" in element && props.type === "checkbox") {
172
+ props.setter(state, element.checked);
173
+ } else {
174
+ props.setter(state, toStateValue(element.value));
175
+ }
176
+ }
177
+ });
178
+ return {
179
+ ref: inputProps.ref,
180
+ dispatchKey: inputProps.dispatchKey,
181
+ defaultValue: getDefaultValue(),
182
+ defaultChecked: getDefaultChecked(),
183
+ onChange: (event) => {
184
+ inputProps.onChange();
185
+ props.onChange?.(event);
186
+ }
187
+ };
188
+ }
189
+
190
+ // src/use_store_input_with_name.tsx
191
+ function useStoreInputWithName(store, props) {
192
+ const inputProps = useStoreInput(store, {
193
+ ...props,
194
+ getter: (state) => {
195
+ if (props.getter) {
196
+ return props.getter(state);
197
+ }
198
+ return state[props.name];
199
+ },
200
+ setter: (state, value) => {
201
+ if (props.setter) {
202
+ props.setter(state, value);
203
+ return;
204
+ }
205
+ state[props.name] = value;
206
+ }
207
+ });
208
+ return {
209
+ ...inputProps,
210
+ name: "name" in props ? String(props.name) : void 0
211
+ };
212
+ }
213
+
214
+ // src/use_store_component.tsx
215
+ function useStoreComponent(store) {
216
+ const input = (0, import_react4.useCallback)(function Component(props) {
217
+ return /* @__PURE__ */ import_react5.default.createElement(Input, { store, ...props });
218
+ }, []);
219
+ const select = (0, import_react4.useCallback)(function Component(props) {
220
+ return /* @__PURE__ */ import_react5.default.createElement(Select, { store, ...props });
221
+ }, []);
222
+ const textarea = (0, import_react4.useCallback)(function Component(props) {
223
+ return /* @__PURE__ */ import_react5.default.createElement(Textarea, { store, ...props });
224
+ }, []);
225
+ return {
226
+ input,
227
+ select,
228
+ textarea
229
+ };
230
+ }
231
+ function Input({
232
+ store,
233
+ ...props
234
+ }) {
235
+ const storeProps = useStoreInputWithName(store, props);
236
+ return /* @__PURE__ */ import_react5.default.createElement("input", { ...props, ...storeProps });
237
+ }
238
+ function Select({
239
+ store,
240
+ ...props
241
+ }) {
242
+ const storeProps = useStoreInputWithName(store, props);
243
+ return /* @__PURE__ */ import_react5.default.createElement("select", { ...props, ...storeProps });
244
+ }
245
+ function Textarea({
246
+ store,
247
+ ...props
248
+ }) {
249
+ const storeProps = useStoreInputWithName(store, props);
250
+ return /* @__PURE__ */ import_react5.default.createElement("textarea", { ...props, ...storeProps });
251
+ }
252
+ // Annotate the CommonJS export names for ESM import in node:
253
+ 0 && (module.exports = {
254
+ Input,
255
+ Select,
256
+ Textarea,
257
+ useStoreComponent
258
+ });