plug-code 1.1.16 → 1.1.17

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  Plug&Code License
2
2
 
3
- Copyright (c) 2026 [TU NOMBRE]
3
+ Copyright (c) 2026 AlaunS
4
4
 
5
5
  All rights reserved.
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plug-code",
3
- "version": "1.1.16",
3
+ "version": "1.1.17",
4
4
  "description": "",
5
5
  "main": "src/plug-code.tsx",
6
6
  "types": "types/plug-code.d.ts",
@@ -1,6 +1,6 @@
1
1
  import { produce } from "immer";
2
2
  import type { ObjectType } from "../types/general";
3
- import { useEffect, useState } from "react";
3
+ import { useEffect, useRef, useState } from "react";
4
4
  import { PlcPipeline } from "./plcPipeline";
5
5
  import type { PlcStore } from "./plcStore";
6
6
  import type { CommandFn, transformerType } from "../types/api";
@@ -28,7 +28,6 @@ export class PlcAPI<S extends ObjectType> {
28
28
 
29
29
  private transformers = new Map<string, transformerType[]>()
30
30
  private commands = new Map<string, CommandFn>();
31
- private installedFeatures = new Set<string>();
32
31
 
33
32
  constructor(store: PlcStore<S>) {
34
33
  this.store = store
@@ -122,57 +121,67 @@ export class PlcAPI<S extends ObjectType> {
122
121
  return () => lastValue
123
122
  }
124
123
 
125
- register(slot: SlotKey, node: () => React.ReactNode): void;
126
- register<K extends string>(slot: SlotKey, node: (data: any) => React.ReactNode, dependencyKey: K): void;
127
- register(slot: SlotKey, node: (data?: any) => React.ReactNode, dependencyKey?: string) {
124
+ register(slot: SlotKey, node: (props?: any) => React.ReactNode): void;
125
+ register<K extends string>(slot: SlotKey, node: (data: any, props?: any) => React.ReactNode, dependencyKey: K): void;
126
+ register(slot: SlotKey, node: (data?: any, props?: any) => React.ReactNode, dependencyKey?: string) {
128
127
  if (dependencyKey) {
129
- const ConnectedWrapper = () => {
130
- const [data, setData] = useState(() => this.substores.get(dependencyKey));
128
+ const ConnectedWrapper = (props: any) => {
129
+ const [storeData, setStoreData] = useState(() => this.substores.get(dependencyKey));
131
130
 
132
131
  useEffect(() => {
133
132
  const unsubscribe = this.store.subscribe(dependencyKey as any, () => {
134
- setData(this.substores.get(dependencyKey));
133
+ setStoreData(this.substores.get(dependencyKey));
135
134
  });
136
135
  return unsubscribe;
137
136
  }, []);
138
137
 
139
- return node(data);
138
+ return <>{node(storeData, props)}</>;
140
139
  };
141
140
 
142
141
  this.store.batch(() => {
143
- this.pipeline.register(slot as string, () => <ConnectedWrapper />);
142
+ this.pipeline.register(slot as string, ConnectedWrapper);
144
143
  });
145
144
  }
146
145
  else {
147
146
  this.store.batch(() => {
148
- this.pipeline.register(slot as string, node as () => React.ReactNode);
147
+ this.pipeline.register(slot as string, node);
149
148
  });
150
149
  }
151
150
  }
152
151
 
153
152
  scope<T = any>(key: string | "root"): {
154
153
  get: () => T;
155
- update: (updater: (draft: T) => void) => void;
156
- connect: (renderer: (data: T) => React.ReactNode) => React.FC;
157
- render: (slotName: SlotKey) => React.ReactNode | null;
154
+ update: (updater: (draft: T) => void, slot?: string, triggerKey?: string) => void;
155
+ connect: <P = {}, R = any>(
156
+ selector: (data: T, props: P) => R
157
+ ) => (WrappedComponent: React.ComponentType<P & R>) => React.FC<P>;
158
+
159
+ render: (slotName: SlotKey) => React.FC;
158
160
  receive: (context?: any) => any;
159
161
  root: PlcAPI<S>;
160
162
  } {
161
163
  return {
162
164
  get: (): T => this.getData(key),
163
165
 
164
- update: (updater: (draft: T) => void) => {
165
- this.update(key as any, updater);
166
+ update: (updater: (draft: T) => void, slot?: string, triggerKey?: string) => {
167
+ this.update(key as any, updater, slot, triggerKey);
166
168
  },
167
169
 
168
- connect: (renderer: (data: T) => React.ReactNode) => {
169
- return this.connect(key, renderer);
170
+ connect: <P = {}, R = any>(
171
+ selector: (data: T, props: P) => R
172
+ ) => {
173
+ return this.connect(key, selector);
170
174
  },
171
175
 
172
176
  render: (slotName: SlotKey) => {
173
- return this.connect(key, (localData) => {
174
- return this.pipeline.render(slotName as string, localData) as React.ReactNode;
175
- }) as any;
177
+ const ScopedSlotRenderer = ({ _scopeData }: { _scopeData: T }) => {
178
+ return <>{this.pipeline.render(slotName as string, _scopeData)}</>;
179
+ };
180
+
181
+ return this.connect(
182
+ key,
183
+ (data: T) => ({ _scopeData: data })
184
+ )(ScopedSlotRenderer) as any;
176
185
  },
177
186
 
178
187
  receive: (context: any = {}) => {
@@ -184,25 +193,53 @@ export class PlcAPI<S extends ObjectType> {
184
193
  };
185
194
  }
186
195
 
187
- connect<T = any>(key: string, renderer: (data: T) => React.ReactNode): React.FC {
188
- return () => {
189
- const [data, setData] = useState<T>(() => this.substores.get(key));
196
+ connect<State = any, OwnProps = {}, ResultProps = {}>(
197
+ key: string,
198
+ selector: (state: State, props: OwnProps) => ResultProps
199
+ ): (WrappedComponent: React.ComponentType<OwnProps & ResultProps>) => React.FC<OwnProps> {
200
+ return (WrappedComponent: React.ComponentType<OwnProps & ResultProps>) => {
201
+
202
+ const ConnectedComponent = (props: OwnProps) => {
203
+ const propsRef = useRef(props);
204
+ propsRef.current = props;
190
205
 
191
- useEffect(() => {
192
- const unsubscribe = this.store.subscribe(key as any, () => {
193
- setData(this.substores.get(key));
206
+ const [slice, setSlice] = useState<ResultProps>(() => {
207
+ const data = this.substores.get(key);
208
+ return selector(data, props);
194
209
  });
195
210
 
196
- return () => {
197
- unsubscribe();
198
- };
199
- }, []);
211
+ useEffect(() => {
212
+ const unsubscribe = this.store.subscribe(key as any, () => {
213
+ const currentData = this.substores.get(key);
214
+ const newSlice = selector(currentData, propsRef.current);
215
+
216
+ setSlice(prev => {
217
+ if (prev === newSlice) return prev;
218
+
219
+ if (typeof prev === 'object' && prev !== null && typeof newSlice === 'object' && newSlice !== null) {
220
+ const keysA = Object.keys(prev) as Array<keyof ResultProps>;
221
+ const keysB = Object.keys(newSlice) as Array<keyof ResultProps>;
222
+ if (keysA.length === keysB.length && keysA.every(k => prev[k] === newSlice[k])) {
223
+ return prev;
224
+ }
225
+ }
226
+
227
+ return newSlice;
228
+ });
229
+ });
230
+ return unsubscribe;
231
+ }, []);
232
+
233
+ if (slice === undefined && this.substores.get(key) === undefined) return null;
234
+ return <WrappedComponent {...props} {...slice} />;
235
+ };
236
+
237
+ const displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
238
+ ConnectedComponent.displayName = `Connect(${displayName})`;
200
239
 
201
- if (data === undefined) return null;
202
- return <>{renderer(data)}</>;
240
+ return ConnectedComponent;
203
241
  };
204
242
  }
205
-
206
243
  wrap(slot: SlotKey, fn: (next: () => React.ReactNode) => () => React.ReactNode) {
207
244
  this.store.batch(() => {
208
245
  this.pipeline.wrap(slot as string, fn)
@@ -215,8 +252,8 @@ export class PlcAPI<S extends ObjectType> {
215
252
  })
216
253
  }
217
254
 
218
- render(slot: SlotKey) {
219
- return this.pipeline.render(slot as string)
255
+ render(slot: SlotKey, props?: any) {
256
+ return this.pipeline.render(slot as string, props)
220
257
  }
221
258
 
222
259
  invalidate(slot?: SlotKey) {
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useContext } from "react";
2
2
  import { ScopeContext } from "../contexts/pipeline";
3
3
  import type { ObjectType } from "../types/general";
4
4
  import type { ScheduledSlot, Slot } from "../types/pipeline";
@@ -73,9 +73,15 @@ export class PlcPipeline<S extends ObjectType> {
73
73
  }
74
74
 
75
75
  private regenerateCache(slot: string) {
76
- const nodes = this.slots.get(slot)?.map((fn, i) => (
77
- <React.Fragment key={i}>{fn()}</React.Fragment>
78
- )) || [];
76
+ const nodes = this.slots.get(slot)?.map((fn, i) => {
77
+ const SlotBridge = () => {
78
+ const dynamicProps = useContext(ScopeContext);
79
+ return <React.Fragment>{fn(dynamicProps)}</React.Fragment>;
80
+ };
81
+
82
+ return <SlotBridge key={i} />;
83
+ }) || [];
84
+
79
85
  this.cache.set(slot, nodes);
80
86
  }
81
87
  }
@@ -1,3 +1,3 @@
1
1
 
2
- export type Slot = () => React.ReactNode
2
+ export type Slot = (props?: any) => React.ReactNode
3
3
  export type ScheduledSlot = { slot: string, fn: Slot, priority: number }
@@ -7,6 +7,8 @@ import * as React from 'react';
7
7
  export declare type ObjectType = Record<string, any>;
8
8
 
9
9
  export type Slot = () => React.ReactNode;
10
+ interface SlotRegistry {}
11
+ type SlotKey = keyof SlotRegistry | (string & {});
10
12
 
11
13
  /**
12
14
  * Función para ejecutar lógica de negocio (Acciones).
@@ -56,8 +58,8 @@ export declare class PlcAPI<S extends ObjectType> {
56
58
  override<K extends string>(key: K & "root", data: any, slot?: string): void
57
59
  // --- Gestión de UI (Slots & Rendering) ---
58
60
 
59
- register(slot: string, node: () => React.ReactNode): void;
60
- register<K extends string>(slot: string, node: (data: any) => React.ReactNode, dependencyKey: K): void;
61
+ register(slot: string, node: (props?: any) => React.ReactNode): void;
62
+ register<K extends string>(slot: string, node: (data: any, props?: any) => React.ReactNode, dependencyKey: K): void;
61
63
 
62
64
  /** Envuelve un slot existente (Decorador/Wrapper) */
63
65
  wrap(slot: string, fn: (next: () => React.ReactNode) => () => React.ReactNode): void;
@@ -88,15 +90,18 @@ export declare class PlcAPI<S extends ObjectType> {
88
90
  */
89
91
  scope<T = any>(key: string): {
90
92
  get: () => T;
91
- update: (updater: (draft: T) => void) => void;
92
- connect: (renderer: (data: T) => React.ReactNode) => React.FC;
93
- render: (slotName: string) => React.ReactNode | null;
93
+ update: (updater: (draft: T) => void, slot?: string, triggerKey?: string) => void;
94
+ connect: <P = {}, R = any>(
95
+ selector: (data: T, props: P) => R
96
+ ) => (WrappedComponent: React.ComponentType<P & R>) => React.FC<P>;
97
+
98
+ render: (slotName: SlotKey) => React.FC;
94
99
  receive: (context?: any) => any;
95
100
  root: PlcAPI<S>;
96
101
  };
97
102
 
98
103
  /** Conecta un componente a una parte del estado (HOC) */
99
- connect<T = any>(key: string, renderer: (data: T) => React.ReactNode): React.FC;
104
+ connect<State = any, OwnProps = {}, ResultProps = {}>(key: string, selector: (state: State, props: OwnProps) => ResultProps): (WrappedComponent: React.ComponentType<OwnProps & ResultProps>) => React.FC<OwnProps>;
100
105
 
101
106
  // --- Pipeline de Datos (Transforms) ---
102
107