juxscript 1.0.62 → 1.0.63

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.
Files changed (141) hide show
  1. package/bin/cli.js +161 -293
  2. package/docs/v2comps/HEADLESS.md +83 -0
  3. package/docs/v2comps/ISOMORPHISM.md +10 -0
  4. package/juxconfig.example.js +63 -58
  5. package/lib/componentsv2/base/BaseEngine.js +258 -0
  6. package/lib/componentsv2/base/BaseEngine.js.map +1 -0
  7. package/lib/componentsv2/base/BaseEngine.ts +303 -0
  8. package/lib/componentsv2/base/BaseSkin.js +108 -0
  9. package/lib/componentsv2/base/BaseSkin.js.map +1 -0
  10. package/lib/componentsv2/base/BaseSkin.ts +137 -0
  11. package/lib/componentsv2/base/GlobalBus.js +56 -0
  12. package/lib/componentsv2/base/GlobalBus.js.map +1 -0
  13. package/lib/componentsv2/base/GlobalBus.ts +60 -0
  14. package/lib/componentsv2/base/State.js +68 -0
  15. package/lib/componentsv2/base/State.js.map +1 -0
  16. package/lib/componentsv2/base/State.ts +62 -0
  17. package/lib/componentsv2/grid/component.js +41 -0
  18. package/lib/componentsv2/grid/component.js.map +1 -0
  19. package/lib/componentsv2/grid/component.ts +67 -0
  20. package/lib/componentsv2/grid/engine.js +73 -0
  21. package/lib/componentsv2/grid/engine.js.map +1 -0
  22. package/lib/componentsv2/grid/engine.ts +110 -0
  23. package/lib/componentsv2/grid/skin.js +95 -0
  24. package/lib/componentsv2/grid/skin.js.map +1 -0
  25. package/lib/componentsv2/grid/skin.ts +105 -0
  26. package/lib/componentsv2/grid/structure.css +58 -0
  27. package/lib/componentsv2/index.js +218 -0
  28. package/lib/componentsv2/index.js.map +1 -0
  29. package/lib/componentsv2/index.ts +253 -0
  30. package/lib/componentsv2/input/component.js +21 -0
  31. package/lib/componentsv2/input/component.js.map +1 -0
  32. package/lib/componentsv2/input/component.ts +28 -0
  33. package/lib/componentsv2/input/engine.js +50 -0
  34. package/lib/componentsv2/input/engine.js.map +1 -0
  35. package/lib/componentsv2/input/engine.ts +76 -0
  36. package/lib/componentsv2/input/skin.js +91 -0
  37. package/lib/componentsv2/input/skin.js.map +1 -0
  38. package/lib/componentsv2/input/skin.ts +91 -0
  39. package/lib/componentsv2/input/structure.css +47 -0
  40. package/lib/componentsv2/list/component.js +83 -0
  41. package/lib/componentsv2/list/component.js.map +1 -0
  42. package/lib/componentsv2/list/component.ts +97 -0
  43. package/lib/componentsv2/list/engine.js +261 -0
  44. package/lib/componentsv2/list/engine.js.map +1 -0
  45. package/lib/componentsv2/list/engine.ts +345 -0
  46. package/lib/componentsv2/list/skin.js +343 -0
  47. package/lib/componentsv2/list/skin.js.map +1 -0
  48. package/lib/componentsv2/list/skin.ts +367 -0
  49. package/lib/componentsv2/list/structure.css +359 -0
  50. package/lib/componentsv2/plugins/ClientSQLitePlugin.js +130 -0
  51. package/lib/componentsv2/plugins/ClientSQLitePlugin.js.map +1 -0
  52. package/lib/componentsv2/plugins/ClientSQLitePlugin.ts +154 -0
  53. package/lib/componentsv2/plugins/IndexedDBPlugin.js +75 -0
  54. package/lib/componentsv2/plugins/IndexedDBPlugin.js.map +1 -0
  55. package/lib/componentsv2/plugins/IndexedDBPlugin.ts +96 -0
  56. package/lib/componentsv2/plugins/LocalStoragePlugin.js +65 -0
  57. package/lib/componentsv2/plugins/LocalStoragePlugin.js.map +1 -0
  58. package/lib/componentsv2/plugins/LocalStoragePlugin.ts +86 -0
  59. package/lib/componentsv2/plugins/ServerSQLitePlugin.js +70 -0
  60. package/lib/componentsv2/plugins/ServerSQLitePlugin.js.map +1 -0
  61. package/lib/componentsv2/plugins/ServerSQLitePlugin.ts +99 -0
  62. package/lib/componentsv2/stubs/ComponentComposition.ts.stub +32 -0
  63. package/lib/componentsv2/stubs/ComponentEngine.ts.stub +36 -0
  64. package/lib/componentsv2/stubs/ComponentSkin.ts.stub +34 -0
  65. package/lib/componentsv2/stubs/ComponentStructure.css.stub +13 -0
  66. package/lib/componentsv2/tools/CreateSkin.js +62 -0
  67. package/lib/componentsv2/tools/DocSpam.js +134 -0
  68. package/lib/componentsv2/tools/FluencyAudit.js +141 -0
  69. package/lib/componentsv2/tools/OptionsAudit.js +177 -0
  70. package/lib/componentsv2/tools/Scaffold.js +140 -0
  71. package/lib/utils/fetch.js +428 -0
  72. package/lib/utils/fetch.js.map +1 -0
  73. package/machinery/build.js +2 -1
  74. package/machinery/compiler.js +200 -37
  75. package/machinery/config.js +93 -6
  76. package/machinery/diagnose.js +72 -0
  77. package/machinery/jux-module-pattern.md +118 -0
  78. package/machinery/server.js +23 -7
  79. package/machinery/verifier.js +143 -0
  80. package/machinery/watcher.js +53 -64
  81. package/package.json +11 -2
  82. package/lib/components/alert.ts +0 -200
  83. package/lib/components/app.ts +0 -258
  84. package/lib/components/badge.ts +0 -101
  85. package/lib/components/base/BaseComponent.ts +0 -417
  86. package/lib/components/base/FormInput.ts +0 -227
  87. package/lib/components/button.ts +0 -178
  88. package/lib/components/card.ts +0 -173
  89. package/lib/components/chart.ts +0 -231
  90. package/lib/components/checkbox.ts +0 -242
  91. package/lib/components/code.ts +0 -123
  92. package/lib/components/container.ts +0 -140
  93. package/lib/components/data.ts +0 -135
  94. package/lib/components/datepicker.ts +0 -234
  95. package/lib/components/dialog.ts +0 -172
  96. package/lib/components/divider.ts +0 -100
  97. package/lib/components/dropdown.ts +0 -186
  98. package/lib/components/element.ts +0 -267
  99. package/lib/components/error-handler.ts +0 -285
  100. package/lib/components/fileupload.ts +0 -309
  101. package/lib/components/grid.ts +0 -291
  102. package/lib/components/guard.ts +0 -92
  103. package/lib/components/heading.ts +0 -96
  104. package/lib/components/helpers.ts +0 -41
  105. package/lib/components/hero.ts +0 -224
  106. package/lib/components/icon.ts +0 -160
  107. package/lib/components/icons.ts +0 -175
  108. package/lib/components/include.ts +0 -440
  109. package/lib/components/input.ts +0 -457
  110. package/lib/components/list.ts +0 -419
  111. package/lib/components/loading.ts +0 -100
  112. package/lib/components/menu.ts +0 -260
  113. package/lib/components/modal.ts +0 -239
  114. package/lib/components/nav.ts +0 -257
  115. package/lib/components/paragraph.ts +0 -97
  116. package/lib/components/progress.ts +0 -139
  117. package/lib/components/radio.ts +0 -278
  118. package/lib/components/req.ts +0 -302
  119. package/lib/components/script.ts +0 -43
  120. package/lib/components/select.ts +0 -252
  121. package/lib/components/sidebar.ts +0 -167
  122. package/lib/components/style.ts +0 -43
  123. package/lib/components/switch.ts +0 -246
  124. package/lib/components/table.ts +0 -1249
  125. package/lib/components/tabs.ts +0 -250
  126. package/lib/components/theme-toggle.ts +0 -300
  127. package/lib/components/token-calculator.ts +0 -313
  128. package/lib/components/tooltip.ts +0 -144
  129. package/lib/components/view.ts +0 -190
  130. package/lib/components/write.ts +0 -272
  131. package/lib/jux.ts +0 -365
  132. package/lib/layouts/default.css +0 -260
  133. package/lib/layouts/figma.css +0 -334
  134. package/lib/reactivity/state.ts +0 -78
  135. package/machinery/bundleAssets.js +0 -0
  136. package/machinery/bundleJux.js +0 -0
  137. package/machinery/bundleVendors.js +0 -0
  138. package/presets/default/all.jux +0 -343
  139. package/presets/default/index.jux +0 -90
  140. package/presets/default/layout.jux +0 -57
  141. package/presets/default/style.css +0 -1612
@@ -1,260 +0,0 @@
1
- /* Default Layout Grid (Notion-style) */
2
-
3
- #app {
4
-
5
- display: grid;
6
- grid-template-areas:
7
- "header header"
8
- "sidebar main"
9
- "footer footer";
10
- grid-template-columns: 250px 1fr;
11
- grid-template-rows: auto 1fr auto;
12
- min-height: 100vh;
13
- }
14
-
15
- /* Header */
16
- #appheader {
17
- grid-area: header;
18
- position: sticky;
19
- top: 0;
20
- z-index: 100;
21
- background: var(--color-surface-elevated);
22
- border-bottom: var(--border-width) solid var(--color-border);
23
- display: flex;
24
- align-items: center;
25
- padding: var(--space-md) var(--space-lg);
26
- gap: var(--space-lg);
27
- }
28
-
29
- #appheader-logo {
30
- flex-shrink: 0;
31
- }
32
-
33
- #appheader-nav {
34
- flex: 1;
35
- display: flex;
36
- gap: var(--space-md);
37
- }
38
-
39
- #appheader-actions {
40
- flex-shrink: 0;
41
- display: flex;
42
- gap: var(--space-sm);
43
- }
44
-
45
- /* Subheader - Hidden in default layout */
46
- #appsubheader {
47
- display: none;
48
- }
49
-
50
- #appsubheader-breadcrumbs,
51
- #appsubheader-tabs,
52
- #appsubheader-actions {
53
- display: none;
54
- }
55
-
56
- /* Sidebar */
57
- #appsidebar {
58
- grid-area: sidebar;
59
- overflow-y: auto;
60
- background: var(--color-surface-base);
61
- border-right: var(--border-width) solid var(--color-border);
62
- transition: transform var(--transition-base);
63
- display: flex;
64
- flex-direction: column;
65
- }
66
-
67
- #appsidebar-header {
68
- padding: var(--space-md);
69
- border-bottom: var(--border-width) solid var(--color-border);
70
- flex-shrink: 0;
71
- }
72
-
73
- #appsidebar-content {
74
- flex: 1;
75
- overflow-y: auto;
76
- padding: var(--space-sm);
77
- }
78
-
79
- #appsidebar-footer {
80
- padding: var(--space-md);
81
- border-top: var(--border-width) solid var(--color-border);
82
- flex-shrink: 0;
83
- }
84
-
85
- /* Main */
86
- #appmain {
87
- grid-area: main;
88
- overflow-y: auto;
89
- padding: var(--space-xl);
90
- background: var(--color-background);
91
- }
92
-
93
- /* Aside - Hidden in default layout */
94
- #appaside {
95
- display: none;
96
- }
97
-
98
- #appaside-header,
99
- #appaside-content,
100
- #appaside-footer {
101
- display: none;
102
- }
103
-
104
- /* Footer */
105
- #appfooter {
106
- grid-area: footer;
107
- background: var(--color-surface-elevated);
108
- border-top: var(--border-width) solid var(--color-border);
109
- padding: var(--space-lg) var(--space-xl);
110
- display: flex;
111
- justify-content: space-between;
112
- align-items: center;
113
- }
114
-
115
- #appfooter-content {
116
- flex: 1;
117
- }
118
-
119
- #appfooter-legal {
120
- flex-shrink: 0;
121
- font-size: var(--font-size-sm);
122
- color: var(--color-text-secondary);
123
- }
124
-
125
- /* Modal */
126
- #appmodal {
127
- position: fixed;
128
- top: 0;
129
- left: 0;
130
- right: 0;
131
- bottom: 0;
132
- z-index: 2000;
133
- display: none;
134
- }
135
-
136
- #appmodal[aria-hidden="false"] {
137
- display: flex;
138
- align-items: center;
139
- justify-content: center;
140
- }
141
-
142
- #appmodal-backdrop {
143
- position: absolute;
144
- inset: 0;
145
- background: rgba(0, 0, 0, 0.6);
146
- backdrop-filter: blur(4px);
147
- }
148
-
149
- #appmodal-container {
150
- position: relative;
151
- background: var(--color-surface-elevated);
152
- border-radius: var(--radius-lg);
153
- box-shadow: var(--shadow-2xl);
154
- max-width: 90vw;
155
- max-height: 90vh;
156
- display: flex;
157
- flex-direction: column;
158
- overflow: hidden;
159
- }
160
-
161
- #appmodal-header {
162
- padding: var(--space-lg);
163
- border-bottom: var(--border-width) solid var(--color-border);
164
- flex-shrink: 0;
165
- }
166
-
167
- #appmodal-content {
168
- flex: 1;
169
- overflow-y: auto;
170
- padding: var(--space-lg);
171
- }
172
-
173
- #appmodal-footer {
174
- padding: var(--space-lg);
175
- border-top: var(--border-width) solid var(--color-border);
176
- flex-shrink: 0;
177
- display: flex;
178
- gap: var(--space-sm);
179
- justify-content: flex-end;
180
- }
181
-
182
- /* Tablet (portrait) */
183
- @media (max-width: 1024px) {
184
- #app {
185
- grid-template-columns: 200px 1fr;
186
- }
187
-
188
- #appmain {
189
- padding: var(--space-lg);
190
- }
191
-
192
- #appheader {
193
- padding: var(--space-sm) var(--space-md);
194
- gap: var(--space-md);
195
- }
196
- }
197
-
198
- /* Mobile */
199
- @media (max-width: 768px) {
200
- #app {
201
- grid-template-areas:
202
- "header"
203
- "main"
204
- "footer";
205
- grid-template-columns: 1fr;
206
- }
207
-
208
- #appsidebar {
209
- position: fixed;
210
- top: 60px;
211
- left: 0;
212
- bottom: 0;
213
- width: 280px;
214
- max-width: 80vw;
215
- z-index: 99;
216
- transform: translateX(-100%);
217
- box-shadow: var(--shadow-xl);
218
- }
219
-
220
- #appsidebar.visible {
221
- transform: translateX(0);
222
- }
223
-
224
- #appmain {
225
- padding: var(--space-md);
226
- }
227
-
228
- #appheader {
229
- padding: var(--space-xs) var(--space-md);
230
- }
231
-
232
- #appfooter {
233
- padding: var(--space-md) var(--space-lg);
234
- flex-direction: column;
235
- gap: var(--space-sm);
236
- text-align: center;
237
- }
238
- }
239
-
240
- /* Small mobile */
241
- @media (max-width: 480px) {
242
- #appsidebar {
243
- width: 100%;
244
- max-width: 100vw;
245
- }
246
-
247
- #appmain {
248
- padding: var(--space-sm);
249
- }
250
-
251
- #appfooter {
252
- padding: var(--space-sm) var(--space-md);
253
- font-size: var(--font-size-sm);
254
- }
255
-
256
- #appmodal-container {
257
- max-width: 95vw;
258
- max-height: 95vh;
259
- }
260
- }
@@ -1,334 +0,0 @@
1
- /* Figma Layout: All 7 containers */
2
- #app {
3
- display: grid;
4
- grid-template-areas:
5
- "header header header"
6
- "subheader subheader subheader"
7
- "sidebar main aside"
8
- "footer footer footer";
9
- grid-template-columns: 250px 1fr 300px;
10
- grid-template-rows: 60px auto 1fr 60px;
11
- min-height: 100vh;
12
- }
13
-
14
- /* Header */
15
- #appheader {
16
- grid-area: header;
17
- background: var(--color-surface-elevated);
18
- border-bottom: var(--border-width) solid var(--color-border);
19
- display: flex;
20
- align-items: center;
21
- padding: var(--space-sm) var(--space-lg);
22
- gap: var(--space-lg);
23
- }
24
-
25
- #appheader-logo {
26
- flex-shrink: 0;
27
- }
28
-
29
- #appheader-nav {
30
- flex: 1;
31
- display: flex;
32
- gap: var(--space-md);
33
- }
34
-
35
- #appheader-actions {
36
- flex-shrink: 0;
37
- display: flex;
38
- gap: var(--space-sm);
39
- }
40
-
41
- /* Subheader */
42
- #appsubheader {
43
- grid-area: subheader;
44
- background: var(--color-surface-base);
45
- border-bottom: var(--border-width) solid var(--color-border);
46
- padding: var(--space-sm) var(--space-md);
47
- display: flex;
48
- align-items: center;
49
- gap: var(--space-lg);
50
- }
51
-
52
- #appsubheader-breadcrumbs {
53
- flex: 0 0 auto;
54
- display: flex;
55
- align-items: center;
56
- gap: var(--space-xs);
57
- }
58
-
59
- #appsubheader-tabs {
60
- flex: 1;
61
- display: flex;
62
- gap: var(--space-sm);
63
- }
64
-
65
- #appsubheader-actions {
66
- flex-shrink: 0;
67
- display: flex;
68
- gap: var(--space-sm);
69
- }
70
-
71
- /* Sidebar */
72
- #appsidebar {
73
- grid-area: sidebar;
74
- overflow-y: auto;
75
- background: var(--color-surface-base);
76
- border-right: var(--border-width) solid var(--color-border);
77
- transition: transform var(--transition-base);
78
- display: flex;
79
- flex-direction: column;
80
- }
81
-
82
- #appsidebar-header {
83
- padding: var(--space-md);
84
- border-bottom: var(--border-width) solid var(--color-border);
85
- flex-shrink: 0;
86
- }
87
-
88
- #appsidebar-content {
89
- flex: 1;
90
- overflow-y: auto;
91
- padding: var(--space-sm);
92
- }
93
-
94
- #appsidebar-footer {
95
- padding: var(--space-md);
96
- border-top: var(--border-width) solid var(--color-border);
97
- flex-shrink: 0;
98
- }
99
-
100
- /* Main */
101
- #appmain {
102
- grid-area: main;
103
- overflow: auto;
104
- background: var(--color-background);
105
- padding: var(--space-xl);
106
- }
107
-
108
- /* Aside (Right Sidebar) */
109
- #appaside {
110
- grid-area: aside;
111
- overflow-y: auto;
112
- background: var(--color-surface-base);
113
- border-left: var(--border-width) solid var(--color-border);
114
- transition: transform var(--transition-base);
115
- display: flex;
116
- flex-direction: column;
117
- }
118
-
119
- #appaside-header {
120
- padding: var(--space-md);
121
- border-bottom: var(--border-width) solid var(--color-border);
122
- flex-shrink: 0;
123
- }
124
-
125
- #appaside-content {
126
- flex: 1;
127
- overflow-y: auto;
128
- padding: var(--space-md);
129
- }
130
-
131
- #appaside-footer {
132
- padding: var(--space-md);
133
- border-top: var(--border-width) solid var(--color-border);
134
- flex-shrink: 0;
135
- }
136
-
137
- /* Footer */
138
- #appfooter {
139
- grid-area: footer;
140
- background: var(--color-surface-elevated);
141
- border-top: var(--border-width) solid var(--color-border);
142
- padding: var(--space-sm) var(--space-md);
143
- display: flex;
144
- justify-content: space-between;
145
- align-items: center;
146
- }
147
-
148
- #appfooter-content {
149
- flex: 1;
150
- }
151
-
152
- #appfooter-legal {
153
- flex-shrink: 0;
154
- font-size: var(--font-size-sm);
155
- color: var(--color-text-secondary);
156
- }
157
-
158
- /* Modal */
159
- #appmodal {
160
- position: fixed;
161
- top: 0;
162
- left: 0;
163
- right: 0;
164
- bottom: 0;
165
- z-index: 2000;
166
- display: none;
167
- }
168
-
169
- #appmodal[aria-hidden="false"] {
170
- display: flex;
171
- align-items: center;
172
- justify-content: center;
173
- }
174
-
175
- #appmodal-backdrop {
176
- position: absolute;
177
- inset: 0;
178
- background: rgba(0, 0, 0, 0.6);
179
- backdrop-filter: blur(4px);
180
- }
181
-
182
- #appmodal-container {
183
- position: relative;
184
- background: var(--color-surface-elevated);
185
- border-radius: var(--radius-lg);
186
- box-shadow: var(--shadow-2xl);
187
- max-width: 90vw;
188
- max-height: 90vh;
189
- display: flex;
190
- flex-direction: column;
191
- overflow: hidden;
192
- }
193
-
194
- #appmodal-header {
195
- padding: var(--space-lg);
196
- border-bottom: var(--border-width) solid var(--color-border);
197
- flex-shrink: 0;
198
- }
199
-
200
- #appmodal-content {
201
- flex: 1;
202
- overflow-y: auto;
203
- padding: var(--space-lg);
204
- }
205
-
206
- #appmodal-footer {
207
- padding: var(--space-lg);
208
- border-top: var(--border-width) solid var(--color-border);
209
- flex-shrink: 0;
210
- display: flex;
211
- gap: var(--space-sm);
212
- justify-content: flex-end;
213
- }
214
-
215
- /* Tablet (landscape) */
216
- @media (max-width: 1280px) {
217
- #app {
218
- grid-template-columns: 200px 1fr 250px;
219
- }
220
- }
221
-
222
- /* Tablet (portrait) - hide aside */
223
- @media (max-width: 1024px) {
224
- #app {
225
- grid-template-areas:
226
- "header header"
227
- "subheader subheader"
228
- "sidebar main"
229
- "footer footer";
230
- grid-template-columns: 200px 1fr;
231
- }
232
-
233
- #appaside {
234
- position: fixed;
235
- top: 120px;
236
- right: 0;
237
- bottom: 60px;
238
- width: 280px;
239
- z-index: 98;
240
- transform: translateX(100%);
241
- box-shadow: var(--shadow-xl);
242
- }
243
-
244
- #appaside.visible {
245
- transform: translateX(0);
246
- }
247
-
248
- #appsubheader {
249
- padding: var(--space-xs) var(--space-sm);
250
- gap: var(--space-md);
251
- }
252
- }
253
-
254
- /* Mobile */
255
- @media (max-width: 768px) {
256
- #app {
257
- grid-template-areas:
258
- "header"
259
- "subheader"
260
- "main"
261
- "footer";
262
- grid-template-columns: 1fr;
263
- grid-template-rows: 60px auto 1fr 60px;
264
- }
265
-
266
- #appsidebar {
267
- position: fixed;
268
- top: 60px;
269
- left: 0;
270
- bottom: 60px;
271
- width: 280px;
272
- max-width: 80vw;
273
- z-index: 99;
274
- transform: translateX(-100%);
275
- box-shadow: var(--shadow-xl);
276
- }
277
-
278
- #appsidebar.visible {
279
- transform: translateX(0);
280
- }
281
-
282
- #appaside {
283
- top: 60px;
284
- width: 280px;
285
- max-width: 80vw;
286
- }
287
-
288
- #appmain {
289
- padding: var(--space-md);
290
- }
291
-
292
- #appheader {
293
- padding: var(--space-xs) var(--space-md);
294
- gap: var(--space-md);
295
- }
296
-
297
- #appsubheader {
298
- padding: var(--space-xs) var(--space-sm);
299
- font-size: var(--font-size-sm);
300
- flex-wrap: wrap;
301
- }
302
-
303
- #appfooter {
304
- padding: var(--space-xs) var(--space-sm);
305
- font-size: var(--font-size-sm);
306
- flex-direction: column;
307
- gap: var(--space-xs);
308
- text-align: center;
309
- }
310
- }
311
-
312
- /* Small mobile */
313
- @media (max-width: 480px) {
314
- #appsidebar,
315
- #appaside {
316
- width: 100%;
317
- max-width: 100vw;
318
- }
319
-
320
- #appmain {
321
- padding: var(--space-sm);
322
- }
323
-
324
- #appheader,
325
- #appsubheader,
326
- #appfooter {
327
- padding: var(--space-xs) var(--space-sm);
328
- }
329
-
330
- #appmodal-container {
331
- max-width: 95vw;
332
- max-height: 95vh;
333
- }
334
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * Simple reactive state container
3
- */
4
- export class State<T> {
5
- private _value: T;
6
- private _subscribers: Set<(value: T) => void> = new Set();
7
-
8
- constructor(initialValue: T) {
9
- this._value = initialValue;
10
- }
11
-
12
- /**
13
- * Get current value
14
- */
15
- get value(): T {
16
- return this._value;
17
- }
18
-
19
- /**
20
- * Set new value and notify subscribers
21
- */
22
- set(newValue: T): void {
23
- this._value = newValue;
24
- this._notify();
25
- }
26
-
27
- /**
28
- * Subscribe to value changes
29
- */
30
- subscribe(callback: (value: T) => void): () => void {
31
- this._subscribers.add(callback);
32
- // Call immediately with current value
33
- callback(this._value);
34
- // Return unsubscribe function
35
- return () => this._subscribers.delete(callback);
36
- }
37
-
38
- /**
39
- * Notify all subscribers
40
- */
41
- private _notify(): void {
42
- this._subscribers.forEach(callback => callback(this._value));
43
- }
44
-
45
- /**
46
- * Helper methods for numeric state
47
- */
48
- increment(): void {
49
- if (typeof this._value === 'number') {
50
- this.set((this._value + 1) as T);
51
- }
52
- }
53
-
54
- decrement(): void {
55
- if (typeof this._value === 'number') {
56
- this.set((this._value - 1) as T);
57
- }
58
- }
59
-
60
- add(amount: number): void {
61
- if (typeof this._value === 'number') {
62
- this.set((this._value + amount) as T);
63
- }
64
- }
65
-
66
- subtract(amount: number): void {
67
- if (typeof this._value === 'number') {
68
- this.set((this._value - amount) as T);
69
- }
70
- }
71
- }
72
-
73
- /**
74
- * Factory function to create reactive state
75
- */
76
- export function state<T>(initialValue: T): State<T> {
77
- return new State(initialValue);
78
- }
File without changes
File without changes
File without changes