react-better-model 0.2.2 → 1.0.0-beta
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/AGENTS.md +43 -0
- package/LICENSE +21 -4
- package/lib/ModelBase.d.ts +15 -0
- package/lib/ModelBase.d.ts.map +1 -0
- package/lib/ModelBase.js +91 -0
- package/lib/ModelBase.js.map +1 -0
- package/lib/ModelWithHooks.d.ts +9 -0
- package/lib/ModelWithHooks.d.ts.map +1 -0
- package/lib/ModelWithHooks.js +108 -0
- package/lib/ModelWithHooks.js.map +1 -0
- package/lib/common-types.d.ts +9 -0
- package/lib/common-types.d.ts.map +1 -0
- package/lib/{types.js → common-types.js} +1 -1
- package/lib/common-types.js.map +1 -0
- package/lib/create-model.d.ts +18 -0
- package/lib/create-model.d.ts.map +1 -0
- package/lib/create-model.js +78 -0
- package/lib/create-model.js.map +1 -0
- package/lib/create-model.test.d.ts +2 -0
- package/lib/create-model.test.d.ts.map +1 -0
- package/lib/create-model.test.js +80 -0
- package/lib/create-model.test.js.map +1 -0
- package/lib/index.d.ts +4 -8
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +22 -9
- package/lib/index.js.map +1 -1
- package/lib/src/ModelBase.d.ts +16 -0
- package/lib/src/ModelBase.d.ts.map +1 -0
- package/lib/src/ModelBase.js +97 -0
- package/lib/src/ModelBase.js.map +1 -0
- package/lib/src/ModelWithHooks.d.ts +8 -0
- package/lib/src/ModelWithHooks.d.ts.map +1 -0
- package/lib/src/ModelWithHooks.js +57 -0
- package/lib/src/ModelWithHooks.js.map +1 -0
- package/lib/src/common-types.d.ts +9 -0
- package/lib/src/common-types.d.ts.map +1 -0
- package/lib/src/common-types.js +3 -0
- package/lib/src/common-types.js.map +1 -0
- package/lib/src/create-model.d.ts +18 -0
- package/lib/src/create-model.d.ts.map +1 -0
- package/lib/src/create-model.js +78 -0
- package/lib/src/create-model.js.map +1 -0
- package/lib/src/index.d.ts +5 -0
- package/lib/src/index.d.ts.map +1 -0
- package/lib/src/index.js +34 -0
- package/lib/src/index.js.map +1 -0
- package/lib/src/utils.d.ts +4 -0
- package/lib/src/utils.d.ts.map +1 -0
- package/lib/src/utils.js +36 -0
- package/lib/src/utils.js.map +1 -0
- package/lib/tests/ModelBase.test.d.ts +2 -0
- package/lib/tests/ModelBase.test.d.ts.map +1 -0
- package/lib/tests/ModelBase.test.js +73 -0
- package/lib/tests/ModelBase.test.js.map +1 -0
- package/lib/tests/ModelWithHooks.test.d.ts +2 -0
- package/lib/tests/ModelWithHooks.test.d.ts.map +1 -0
- package/lib/tests/ModelWithHooks.test.js +108 -0
- package/lib/tests/ModelWithHooks.test.js.map +1 -0
- package/lib/tests/create-model.test.d.ts +2 -0
- package/lib/tests/create-model.test.d.ts.map +1 -0
- package/lib/tests/create-model.test.js +104 -0
- package/lib/tests/create-model.test.js.map +1 -0
- package/lib/tests/utils.test.d.ts +2 -0
- package/lib/tests/utils.test.d.ts.map +1 -0
- package/lib/tests/utils.test.js +30 -0
- package/lib/tests/utils.test.js.map +1 -0
- package/package.json +13 -11
- package/readme.md +212 -105
- package/lib/Model.d.ts +0 -23
- package/lib/Model.d.ts.map +0 -1
- package/lib/Model.js +0 -108
- package/lib/Model.js.map +0 -1
- package/lib/hooks/event-hooks.d.ts +0 -6
- package/lib/hooks/event-hooks.d.ts.map +0 -1
- package/lib/hooks/event-hooks.js +0 -19
- package/lib/hooks/event-hooks.js.map +0 -1
- package/lib/hooks/model-hooks.d.ts +0 -4
- package/lib/hooks/model-hooks.d.ts.map +0 -1
- package/lib/hooks/model-hooks.js +0 -9
- package/lib/hooks/model-hooks.js.map +0 -1
- package/lib/hooks/state-hooks.d.ts +0 -5
- package/lib/hooks/state-hooks.d.ts.map +0 -1
- package/lib/hooks/state-hooks.js +0 -19
- package/lib/hooks/state-hooks.js.map +0 -1
- package/lib/types.d.ts +0 -13
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js.map +0 -1
- package/lib/utils/compose-providers.d.ts +0 -3
- package/lib/utils/compose-providers.d.ts.map +0 -1
- package/lib/utils/compose-providers.js +0 -19
- package/lib/utils/compose-providers.js.map +0 -1
- package/lib/utils/create-model.d.ts +0 -21
- package/lib/utils/create-model.d.ts.map +0 -1
- package/lib/utils/create-model.js +0 -84
- package/lib/utils/create-model.js.map +0 -1
- package/lib/utils/js-event-types.d.ts +0 -6
- package/lib/utils/js-event-types.d.ts.map +0 -1
- package/lib/utils/js-event-types.js +0 -9
- package/lib/utils/js-event-types.js.map +0 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const react_1 = __importDefault(require("react"));
|
|
7
|
+
const react_2 = require("@testing-library/react");
|
|
8
|
+
const src_1 = require("../src");
|
|
9
|
+
class HookModel extends src_1.Model {
|
|
10
|
+
constructor(initial = { count: 0, flag: false }) {
|
|
11
|
+
super(initial);
|
|
12
|
+
this.state = initial;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const { Provider, useModel } = (0, src_1.createModel)(HookModel);
|
|
16
|
+
describe('ModelWithHooks', () => {
|
|
17
|
+
it('useState subscribes to one key and skips updates when the value is unchanged', () => {
|
|
18
|
+
const model = new HookModel();
|
|
19
|
+
const countRenders = jest.fn();
|
|
20
|
+
const flagRenders = jest.fn();
|
|
21
|
+
function CountView() {
|
|
22
|
+
const [count, setCount] = useModel().useState('count');
|
|
23
|
+
countRenders(count);
|
|
24
|
+
return (react_1.default.createElement("button", { "data-testid": "noop", onClick: () => setCount(count) },
|
|
25
|
+
"count: ",
|
|
26
|
+
count));
|
|
27
|
+
}
|
|
28
|
+
function FlagView() {
|
|
29
|
+
const [flag] = useModel().useState('flag');
|
|
30
|
+
flagRenders(flag);
|
|
31
|
+
return react_1.default.createElement("div", { "data-testid": "flag" }, String(flag));
|
|
32
|
+
}
|
|
33
|
+
const view = (0, react_2.render)(react_1.default.createElement(Provider, { value: model },
|
|
34
|
+
react_1.default.createElement(CountView, null),
|
|
35
|
+
react_1.default.createElement(FlagView, null)));
|
|
36
|
+
expect(countRenders).toHaveBeenCalledTimes(1);
|
|
37
|
+
expect(flagRenders).toHaveBeenCalledTimes(1);
|
|
38
|
+
react_2.fireEvent.click(view.getByTestId('noop'));
|
|
39
|
+
expect(countRenders).toHaveBeenCalledTimes(1);
|
|
40
|
+
(0, react_2.act)(() => {
|
|
41
|
+
model.setState({ flag: true });
|
|
42
|
+
});
|
|
43
|
+
expect(flagRenders).toHaveBeenCalledTimes(2);
|
|
44
|
+
expect(countRenders).toHaveBeenCalledTimes(1);
|
|
45
|
+
(0, react_2.act)(() => {
|
|
46
|
+
model.setState({ count: 5 });
|
|
47
|
+
});
|
|
48
|
+
expect(countRenders).toHaveBeenCalledTimes(2);
|
|
49
|
+
});
|
|
50
|
+
it('useMapper recomputes only when mapped keys change', () => {
|
|
51
|
+
const model = new HookModel();
|
|
52
|
+
const derivedRenders = jest.fn();
|
|
53
|
+
function Derived() {
|
|
54
|
+
const doubled = useModel().useMapper((state) => state.count * 2);
|
|
55
|
+
derivedRenders(doubled);
|
|
56
|
+
return react_1.default.createElement("div", { "data-testid": "derived" }, doubled);
|
|
57
|
+
}
|
|
58
|
+
(0, react_2.render)(react_1.default.createElement(Provider, { value: model },
|
|
59
|
+
react_1.default.createElement(Derived, null)));
|
|
60
|
+
expect(derivedRenders).toHaveBeenCalledTimes(1);
|
|
61
|
+
expect(derivedRenders).toHaveBeenLastCalledWith(0);
|
|
62
|
+
(0, react_2.act)(() => {
|
|
63
|
+
model.setState({ flag: true });
|
|
64
|
+
});
|
|
65
|
+
expect(derivedRenders).toHaveBeenCalledTimes(1);
|
|
66
|
+
(0, react_2.act)(() => {
|
|
67
|
+
model.setState({ count: 3 });
|
|
68
|
+
});
|
|
69
|
+
expect(derivedRenders).toHaveBeenCalledTimes(2);
|
|
70
|
+
expect(derivedRenders).toHaveBeenLastCalledWith(6);
|
|
71
|
+
});
|
|
72
|
+
it('useMapper re-tracks dependencies when mapper function changes', () => {
|
|
73
|
+
const model = new HookModel();
|
|
74
|
+
const renders = [];
|
|
75
|
+
function Derived({ keys }) {
|
|
76
|
+
const mapper = react_1.default.useCallback((state) => keys.map(k => state[k]).join(':'), [keys]);
|
|
77
|
+
const value = useModel().useMapper(mapper);
|
|
78
|
+
renders.push(value);
|
|
79
|
+
return react_1.default.createElement("div", { "data-testid": "derived" }, value);
|
|
80
|
+
}
|
|
81
|
+
const view = (0, react_2.render)(react_1.default.createElement(Provider, { value: model },
|
|
82
|
+
react_1.default.createElement(Derived, { keys: ['count'] })));
|
|
83
|
+
(0, react_2.act)(() => model.setState({ count: 1 }));
|
|
84
|
+
expect(renders.pop()).toBe('1');
|
|
85
|
+
view.rerender(react_1.default.createElement(Provider, { value: model },
|
|
86
|
+
react_1.default.createElement(Derived, { keys: ['flag'] })));
|
|
87
|
+
(0, react_2.act)(() => model.setState({ flag: true }));
|
|
88
|
+
expect(renders.pop()).toBe('true');
|
|
89
|
+
});
|
|
90
|
+
it('useEvent subscribes and dispatches typed events', () => {
|
|
91
|
+
const onPing = jest.fn();
|
|
92
|
+
function Listener() {
|
|
93
|
+
const dispatch = useModel().useEvent('ping', onPing);
|
|
94
|
+
return (react_1.default.createElement("button", { "data-testid": "ping", onClick: () => dispatch(9) }, "ping"));
|
|
95
|
+
}
|
|
96
|
+
const view = (0, react_2.render)(react_1.default.createElement(Provider, null,
|
|
97
|
+
react_1.default.createElement(Listener, null)));
|
|
98
|
+
react_2.fireEvent.click(view.getByTestId('ping'));
|
|
99
|
+
expect(onPing).toHaveBeenCalledTimes(1);
|
|
100
|
+
expect(onPing).toHaveBeenCalledWith(9);
|
|
101
|
+
view.unmount();
|
|
102
|
+
(0, react_2.act)(() => {
|
|
103
|
+
// Subscription should be cleaned up on unmount.
|
|
104
|
+
view.unmount();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=ModelWithHooks.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelWithHooks.test.js","sourceRoot":"","sources":["../../tests/ModelWithHooks.test.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-model.test.d.ts","sourceRoot":"","sources":["../../tests/create-model.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const react_1 = __importDefault(require("react"));
|
|
16
|
+
const react_2 = require("@testing-library/react");
|
|
17
|
+
const src_1 = require("../src");
|
|
18
|
+
class CounterModel extends src_1.Model {
|
|
19
|
+
constructor(initial = { count: 0 }) {
|
|
20
|
+
super(initial);
|
|
21
|
+
this.increment = () => this.setState({ count: this.state.count + 1 });
|
|
22
|
+
this.state = initial;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
describe('createModel', () => {
|
|
26
|
+
it('creates a single model instance per Provider lifecycle', () => {
|
|
27
|
+
class CountingModel extends src_1.Model {
|
|
28
|
+
constructor(initial = { value: 0 }) {
|
|
29
|
+
super(initial);
|
|
30
|
+
this.state = initial;
|
|
31
|
+
CountingModel.instances += 1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
CountingModel.instances = 0;
|
|
35
|
+
const { Provider, useModel } = (0, src_1.createModel)(CountingModel);
|
|
36
|
+
let lastModel;
|
|
37
|
+
function Consumer() {
|
|
38
|
+
const model = useModel();
|
|
39
|
+
lastModel = model;
|
|
40
|
+
return react_1.default.createElement("div", { "data-testid": "value" }, model.state.value);
|
|
41
|
+
}
|
|
42
|
+
const view = (0, react_2.render)(react_1.default.createElement(Provider, null,
|
|
43
|
+
react_1.default.createElement(Consumer, null)));
|
|
44
|
+
expect(CountingModel.instances).toBe(1);
|
|
45
|
+
const firstModel = lastModel;
|
|
46
|
+
view.rerender(react_1.default.createElement(Provider, null,
|
|
47
|
+
react_1.default.createElement(Consumer, null)));
|
|
48
|
+
expect(lastModel).toBe(firstModel);
|
|
49
|
+
expect(CountingModel.instances).toBe(1);
|
|
50
|
+
});
|
|
51
|
+
it('uses a provided model instance and wires onChange callbacks', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
52
|
+
const { Provider, useModel } = (0, src_1.createModel)(CounterModel);
|
|
53
|
+
const provided = new CounterModel();
|
|
54
|
+
const handleChange = jest.fn();
|
|
55
|
+
function Consumer() {
|
|
56
|
+
const model = useModel();
|
|
57
|
+
return (react_1.default.createElement("button", { "data-testid": "increment", onClick: () => model.increment() }, "increment"));
|
|
58
|
+
}
|
|
59
|
+
const { getByTestId } = (0, react_2.render)(react_1.default.createElement(Provider, { value: provided, onChange: handleChange },
|
|
60
|
+
react_1.default.createElement(Consumer, null)));
|
|
61
|
+
yield (0, react_2.act)(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
62
|
+
/* allow useEffect to register subscriptions */
|
|
63
|
+
}));
|
|
64
|
+
react_2.fireEvent.click(getByTestId('increment'));
|
|
65
|
+
yield (0, react_2.waitFor)(() => expect(handleChange).toHaveBeenCalledTimes(1));
|
|
66
|
+
expect(handleChange).toHaveBeenCalledWith({ count: 1 }, { count: 0 });
|
|
67
|
+
expect(provided.state.count).toBe(1);
|
|
68
|
+
}));
|
|
69
|
+
it('syncs external state prop into the model instance', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
70
|
+
const { Provider, useModel } = (0, src_1.createModel)(CounterModel);
|
|
71
|
+
function Consumer() {
|
|
72
|
+
const model = useModel();
|
|
73
|
+
const [count] = model.useState('count');
|
|
74
|
+
return react_1.default.createElement("div", { "data-testid": "count" }, count);
|
|
75
|
+
}
|
|
76
|
+
const view = (0, react_2.render)(react_1.default.createElement(Provider, { state: { count: 5 } },
|
|
77
|
+
react_1.default.createElement(Consumer, null)));
|
|
78
|
+
yield (0, react_2.waitFor)(() => expect(view.getByTestId('count').textContent).toBe('5'));
|
|
79
|
+
view.rerender(react_1.default.createElement(Provider, { state: { count: 7 } },
|
|
80
|
+
react_1.default.createElement(Consumer, null)));
|
|
81
|
+
yield (0, react_2.waitFor)(() => expect(view.getByTestId('count').textContent).toBe('7'));
|
|
82
|
+
}));
|
|
83
|
+
it('useModelInstance creates a memoized instance with optional initial state', () => {
|
|
84
|
+
class InitializableModel extends src_1.Model {
|
|
85
|
+
constructor(initialState = { value: 1 }) {
|
|
86
|
+
super(initialState);
|
|
87
|
+
this.state = initialState;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const { useModelInstance } = (0, src_1.createModel)(InitializableModel);
|
|
91
|
+
const seen = [];
|
|
92
|
+
function Consumer({ value }) {
|
|
93
|
+
const instance = useModelInstance(value !== undefined ? { value } : undefined);
|
|
94
|
+
seen.push(instance);
|
|
95
|
+
return react_1.default.createElement("div", { "data-testid": "value" }, instance.state.value);
|
|
96
|
+
}
|
|
97
|
+
const view = (0, react_2.render)(react_1.default.createElement(Consumer, null));
|
|
98
|
+
expect(view.getByTestId('value').textContent).toBe('1');
|
|
99
|
+
view.rerender(react_1.default.createElement(Consumer, { value: 5 }));
|
|
100
|
+
expect(view.getByTestId('value').textContent).toBe('1');
|
|
101
|
+
expect(seen[0]).toBe(seen[1]);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
//# sourceMappingURL=create-model.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-model.test.js","sourceRoot":"","sources":["../../tests/create-model.test.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../tests/utils.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../src/utils");
|
|
4
|
+
describe('shallowEqual', () => {
|
|
5
|
+
it('returns true for the same reference', () => {
|
|
6
|
+
const obj = { a: 1 };
|
|
7
|
+
expect((0, utils_1.shallowEqual)(obj, obj)).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
it('returns true for shallowly equal objects with different references', () => {
|
|
10
|
+
const a = { x: 1, y: 'hi' };
|
|
11
|
+
const b = { x: 1, y: 'hi' };
|
|
12
|
+
expect((0, utils_1.shallowEqual)(a, b)).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
it('returns false when a value differs', () => {
|
|
15
|
+
const a = { x: 1 };
|
|
16
|
+
const b = { x: 2 };
|
|
17
|
+
expect((0, utils_1.shallowEqual)(a, b)).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
it('returns false when keys differ', () => {
|
|
20
|
+
const a = { x: 1 };
|
|
21
|
+
const b = { x: 1, y: 2 };
|
|
22
|
+
expect((0, utils_1.shallowEqual)(a, b)).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
it('uses Object.is semantics (NaN equals NaN)', () => {
|
|
25
|
+
const a = { x: NaN };
|
|
26
|
+
const b = { x: NaN };
|
|
27
|
+
expect((0, utils_1.shallowEqual)(a, b)).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=utils.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../tests/utils.test.ts"],"names":[],"mappings":";;AAAA,wCAA2C;AAE3C,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;QACpB,MAAM,CAAC,IAAA,oBAAY,EAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAA;QAC3B,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAA;QAC3B,MAAM,CAAC,IAAA,oBAAY,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;QAClB,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;QAClB,MAAM,CAAC,IAAA,oBAAY,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;QAClB,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;QACxB,MAAM,CAAC,IAAA,oBAAY,EAAC,CAAQ,EAAE,CAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAA;QACpB,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAA;QACpB,MAAM,CAAC,IAAA,oBAAY,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,36 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-better-model",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "1.0.0-beta",
|
|
4
|
+
"description": "Model to manage state outside component and share it with children via context",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"React",
|
|
9
9
|
"Shared",
|
|
10
10
|
"Model",
|
|
11
|
-
"
|
|
11
|
+
"State",
|
|
12
12
|
"Events"
|
|
13
13
|
],
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
|
-
"url": "git@github.com
|
|
16
|
+
"url": "git+ssh://git@github.com/ingvardm/react-model-hooks.git"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
|
-
"lib"
|
|
19
|
+
"lib",
|
|
20
|
+
"AGENTS.md"
|
|
20
21
|
],
|
|
21
22
|
"scripts": {
|
|
22
23
|
"build": "npx tsc",
|
|
23
|
-
"prepare": "yarn build"
|
|
24
|
+
"prepare": "yarn build",
|
|
25
|
+
"test": "npx jest --runInBand"
|
|
24
26
|
},
|
|
25
|
-
"author": "Igor
|
|
26
|
-
"license": "
|
|
27
|
+
"author": "Igor Pougatch <ingvardm@gmail.com>",
|
|
28
|
+
"license": "Unlicense",
|
|
27
29
|
"peerDependencies": {
|
|
28
|
-
"react": "
|
|
30
|
+
"react": "^18.0.0"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
|
-
"@types/react": "^
|
|
33
|
+
"@types/react": "^18.0.0",
|
|
32
34
|
"typescript": "^4.4.4"
|
|
33
35
|
},
|
|
34
36
|
"dependencies": {},
|
|
35
37
|
"private": false
|
|
36
|
-
}
|
|
38
|
+
}
|