@primer-io/primer-js 0.3.2 → 0.3.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/CHANGELOG.md +117 -0
- package/dist/custom-elements.json +484 -169
- package/dist/jsx/index.d.ts +39 -1
- package/dist/primer-loader.d.ts +62 -4
- package/dist/primer-loader.js +26 -7
- package/dist/primer-react-wrappers.js +25 -6
- package/dist/vscode.html-custom-data.json +19 -2
- package/dist/web-types.json +54 -5
- package/package.json +6 -2
- package/src/controllers/reactive-state/README.md +210 -0
|
@@ -115,8 +115,11 @@
|
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
"name": "primer-dialog",
|
|
118
|
-
"description": "\n---\n",
|
|
119
|
-
"attributes": [
|
|
118
|
+
"description": "\n---\n\n\n### **Events:**\n - **primer-dialog-close**\n\n### **Methods:**\n - **startExitAnimation(): _void_** - Public method to trigger exit animation programmatically",
|
|
119
|
+
"attributes": [
|
|
120
|
+
{ "name": "size", "values": [{ "name": "flex" }, { "name": "large" }] },
|
|
121
|
+
{ "name": "showCloseButton", "values": [] }
|
|
122
|
+
],
|
|
120
123
|
"references": []
|
|
121
124
|
},
|
|
122
125
|
{
|
|
@@ -364,6 +367,20 @@
|
|
|
364
367
|
],
|
|
365
368
|
"references": []
|
|
366
369
|
},
|
|
370
|
+
{
|
|
371
|
+
"name": "primer-portal-dialog",
|
|
372
|
+
"description": "\n---\n\n\n### **Methods:**\n - **openDialog(): _void_** - Opens the content dialog\n- **closeDialog(): _void_** - Closes the dialog with animation",
|
|
373
|
+
"attributes": [
|
|
374
|
+
{ "name": "size", "values": [{ "name": "flex" }, { "name": "large" }] },
|
|
375
|
+
{ "name": "showCloseButton", "values": [] },
|
|
376
|
+
{ "name": "onOpen", "values": [{ "name": "() => void" }] },
|
|
377
|
+
{
|
|
378
|
+
"name": "secureHtmlContent",
|
|
379
|
+
"values": [{ "name": "SecureHtmlContentAccess" }]
|
|
380
|
+
}
|
|
381
|
+
],
|
|
382
|
+
"references": []
|
|
383
|
+
},
|
|
367
384
|
{
|
|
368
385
|
"name": "primer-checkout-complete",
|
|
369
386
|
"description": "\n---\n",
|
package/dist/web-types.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
|
|
3
3
|
"name": "@primer-io/primer-js",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.4",
|
|
5
5
|
"description-markup": "markdown",
|
|
6
6
|
"contributions": {
|
|
7
7
|
"html": {
|
|
@@ -253,11 +253,26 @@
|
|
|
253
253
|
},
|
|
254
254
|
{
|
|
255
255
|
"name": "primer-dialog",
|
|
256
|
-
"description": "\n---\n",
|
|
256
|
+
"description": "\n---\n\n\n### **Events:**\n - **primer-dialog-close**\n\n### **Methods:**\n - **startExitAnimation(): _void_** - Public method to trigger exit animation programmatically",
|
|
257
257
|
"doc-url": "",
|
|
258
|
-
"attributes": [
|
|
259
|
-
|
|
260
|
-
|
|
258
|
+
"attributes": [
|
|
259
|
+
{
|
|
260
|
+
"name": "size",
|
|
261
|
+
"value": { "type": "'flex' | 'large'", "default": "'flex'" }
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"name": "showCloseButton",
|
|
265
|
+
"value": { "type": "boolean", "default": "true" }
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
"events": [{ "name": "primer-dialog-close", "type": "CustomEvent" }],
|
|
269
|
+
"js": {
|
|
270
|
+
"properties": [
|
|
271
|
+
{ "name": "size", "type": "'flex' | 'large'" },
|
|
272
|
+
{ "name": "showCloseButton", "type": "boolean" }
|
|
273
|
+
],
|
|
274
|
+
"events": [{ "name": "primer-dialog-close", "type": "CustomEvent" }]
|
|
275
|
+
}
|
|
261
276
|
},
|
|
262
277
|
{
|
|
263
278
|
"name": "primer-error-message",
|
|
@@ -892,6 +907,40 @@
|
|
|
892
907
|
"events": []
|
|
893
908
|
}
|
|
894
909
|
},
|
|
910
|
+
{
|
|
911
|
+
"name": "primer-portal-dialog",
|
|
912
|
+
"description": "\n---\n\n\n### **Methods:**\n - **openDialog(): _void_** - Opens the content dialog\n- **closeDialog(): _void_** - Closes the dialog with animation",
|
|
913
|
+
"doc-url": "",
|
|
914
|
+
"attributes": [
|
|
915
|
+
{
|
|
916
|
+
"name": "size",
|
|
917
|
+
"value": { "type": "'flex' | 'large'", "default": "'large'" }
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
"name": "showCloseButton",
|
|
921
|
+
"value": { "type": "boolean", "default": "false" }
|
|
922
|
+
},
|
|
923
|
+
{ "name": "onOpen", "value": { "type": "() => void | undefined" } },
|
|
924
|
+
{
|
|
925
|
+
"name": "secureHtmlContent",
|
|
926
|
+
"value": { "type": "SecureHtmlContentAccess | undefined" }
|
|
927
|
+
}
|
|
928
|
+
],
|
|
929
|
+
"events": [],
|
|
930
|
+
"js": {
|
|
931
|
+
"properties": [
|
|
932
|
+
{ "name": "size", "type": "'flex' | 'large'" },
|
|
933
|
+
{ "name": "showCloseButton", "type": "boolean" },
|
|
934
|
+
{ "name": "onOpen", "type": "() => void | undefined" },
|
|
935
|
+
{
|
|
936
|
+
"name": "secureHtmlContent",
|
|
937
|
+
"type": "SecureHtmlContentAccess | undefined"
|
|
938
|
+
},
|
|
939
|
+
{ "name": "open", "type": "boolean" }
|
|
940
|
+
],
|
|
941
|
+
"events": []
|
|
942
|
+
}
|
|
943
|
+
},
|
|
895
944
|
{
|
|
896
945
|
"name": "primer-checkout-complete",
|
|
897
946
|
"description": "\n---\n",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@primer-io/primer-js",
|
|
3
3
|
"description": "Primer Composable Checkout is a web component-based SDK for building secure, customizable, and PCI-compliant checkout experiences. Designed with a modular architecture, it integrates seamlessly with any JavaScript framework and supports multiple payment methods.",
|
|
4
4
|
"license": "BSD-3-Clause",
|
|
5
|
-
"version": "0.3.
|
|
5
|
+
"version": "0.3.4",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/primer-loader.js",
|
|
8
8
|
"types": "./dist/primer-loader.d.ts",
|
|
@@ -35,6 +35,10 @@
|
|
|
35
35
|
},
|
|
36
36
|
"./src/*": "./src/*"
|
|
37
37
|
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"prepack": "clean-package",
|
|
40
|
+
"postpack": "clean-package restore"
|
|
41
|
+
},
|
|
38
42
|
"peerDependencies": {
|
|
39
43
|
"react": "^18.2.0 || ^19.0.0"
|
|
40
44
|
},
|
|
@@ -45,4 +49,4 @@
|
|
|
45
49
|
},
|
|
46
50
|
"customElements": "dist/custom-elements.json",
|
|
47
51
|
"web-types": "./dist/web-types.json"
|
|
48
|
-
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Reactive State Management Library
|
|
2
|
+
|
|
3
|
+
A TypeScript library for state management in reactive controllers that solves common issues:
|
|
4
|
+
|
|
5
|
+
- Enforces type safety for state, actions, and reducers
|
|
6
|
+
- Catches missing action handlers at compile time
|
|
7
|
+
- Enables splitting state into smaller contexts for optimal performance
|
|
8
|
+
- Provides a consistent pattern for state management across controllers
|
|
9
|
+
|
|
10
|
+
## Key Concepts
|
|
11
|
+
|
|
12
|
+
### Action Types
|
|
13
|
+
|
|
14
|
+
Actions are defined as discriminated unions with a `type` property:
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
type UserAction =
|
|
18
|
+
| { type: 'SET_NAME'; payload: string }
|
|
19
|
+
| { type: 'SET_EMAIL'; payload: string }
|
|
20
|
+
| { type: 'RESET' };
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Handlers Map
|
|
24
|
+
|
|
25
|
+
Action handlers are defined in a map where every action type must have a corresponding handler:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
const handlers: ActionHandlerMap<UserState, UserAction, null> = {
|
|
29
|
+
SET_NAME: (state, action) => ({ ...state, name: action.payload }),
|
|
30
|
+
SET_EMAIL: (state, action) => ({ ...state, email: action.payload }),
|
|
31
|
+
RESET: () => initialUserState,
|
|
32
|
+
};
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If you forget to handle an action, TypeScript will generate a compile-time error.
|
|
36
|
+
|
|
37
|
+
## Core Components
|
|
38
|
+
|
|
39
|
+
### `ReactiveStateController`
|
|
40
|
+
|
|
41
|
+
Base class for creating state controllers:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
class ReactiveStateController<
|
|
45
|
+
Host extends ReactiveControllerHost,
|
|
46
|
+
State,
|
|
47
|
+
Action extends { type: string },
|
|
48
|
+
Callbacks = ReducerCallbacks<State, Action> | null,
|
|
49
|
+
> {
|
|
50
|
+
constructor(
|
|
51
|
+
host: Host,
|
|
52
|
+
initialState: State,
|
|
53
|
+
reducer: TypedReducer<State, Action, Callbacks>,
|
|
54
|
+
initialCallbacks: Callbacks,
|
|
55
|
+
stateHandler?: (state: State) => void,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Public API for accessing state
|
|
59
|
+
public get currentState(): Readonly<State>;
|
|
60
|
+
|
|
61
|
+
// Dispatch actions to update state
|
|
62
|
+
protected dispatch(action: Action): void;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `CompositeStateController`
|
|
67
|
+
|
|
68
|
+
For managing multiple state slices to avoid excessive re-renders:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
class CompositeStateController<Host extends ReactiveControllerHost> {
|
|
72
|
+
// Add sub-controllers for different state slices
|
|
73
|
+
addController<State, Action, Callbacks>(
|
|
74
|
+
controller: ReactiveStateController<Host, State, Action, Callbacks>,
|
|
75
|
+
): void;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### `createReducer`
|
|
80
|
+
|
|
81
|
+
Creates a type-safe reducer from handlers:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
function createReducer<State, Action extends { type: string }, Callbacks>(
|
|
85
|
+
handlers: ActionHandlerMap<State, Action, Callbacks>,
|
|
86
|
+
): TypedReducer<State, Action, Callbacks>;
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Simple Example
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// 1. Define your state interface
|
|
93
|
+
interface CounterState {
|
|
94
|
+
count: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 2. Define possible actions
|
|
98
|
+
type CounterAction =
|
|
99
|
+
| { type: 'INCREMENT' }
|
|
100
|
+
| { type: 'DECREMENT' }
|
|
101
|
+
| { type: 'SET_COUNT'; payload: number };
|
|
102
|
+
|
|
103
|
+
// 3. Create initial state
|
|
104
|
+
const initialState: CounterState = { count: 0 };
|
|
105
|
+
|
|
106
|
+
// 4. Define action handlers
|
|
107
|
+
const handlers: ActionHandlerMap<CounterState, CounterAction, null> = {
|
|
108
|
+
INCREMENT: (state) => ({ ...state, count: state.count + 1 }),
|
|
109
|
+
DECREMENT: (state) => ({ ...state, count: state.count - 1 }),
|
|
110
|
+
SET_COUNT: (state, action) => ({ ...state, count: action.payload }),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// 5. Create a reducer
|
|
114
|
+
const counterReducer = createReducer(handlers);
|
|
115
|
+
|
|
116
|
+
// 6. Create your controller
|
|
117
|
+
class CounterController extends ReactiveStateController<
|
|
118
|
+
ReactiveControllerHost,
|
|
119
|
+
CounterState,
|
|
120
|
+
CounterAction,
|
|
121
|
+
null
|
|
122
|
+
> {
|
|
123
|
+
constructor(host: ReactiveControllerHost) {
|
|
124
|
+
super(host, initialState, counterReducer, null);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Public API methods
|
|
128
|
+
increment() {
|
|
129
|
+
this.dispatch({ type: 'INCREMENT' });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
decrement() {
|
|
133
|
+
this.dispatch({ type: 'DECREMENT' });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
setCount(count: number) {
|
|
137
|
+
this.dispatch({ type: 'SET_COUNT', payload: count });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Public getter for the count
|
|
141
|
+
get count(): number {
|
|
142
|
+
return this.currentState.count;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Advanced Usage: State Splitting
|
|
148
|
+
|
|
149
|
+
For complex components, splitting state improves performance by preventing unnecessary re-renders:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// 1. Define separate state slices
|
|
153
|
+
interface CoreState {
|
|
154
|
+
/* core properties */
|
|
155
|
+
}
|
|
156
|
+
interface FormState {
|
|
157
|
+
/* form properties that change frequently */
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 2. Create separate controllers for each slice
|
|
161
|
+
class CoreController extends ReactiveStateController<
|
|
162
|
+
Host,
|
|
163
|
+
CoreState,
|
|
164
|
+
CoreAction,
|
|
165
|
+
null
|
|
166
|
+
> {
|
|
167
|
+
/* ... */
|
|
168
|
+
}
|
|
169
|
+
class FormController extends ReactiveStateController<
|
|
170
|
+
Host,
|
|
171
|
+
FormState,
|
|
172
|
+
FormAction,
|
|
173
|
+
null
|
|
174
|
+
> {
|
|
175
|
+
/* ... */
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 3. Combine with CompositeStateController
|
|
179
|
+
class ComplexController extends CompositeStateController<Host> {
|
|
180
|
+
private coreController: CoreController;
|
|
181
|
+
private formController: FormController;
|
|
182
|
+
|
|
183
|
+
constructor(host: Host) {
|
|
184
|
+
super(host);
|
|
185
|
+
|
|
186
|
+
this.coreController = new CoreController(host /* ... */);
|
|
187
|
+
this.formController = new FormController(host /* ... */);
|
|
188
|
+
|
|
189
|
+
this.addController(this.coreController);
|
|
190
|
+
this.addController(this.formController);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Expose state slices through getters
|
|
194
|
+
get coreState(): Readonly<CoreState> {
|
|
195
|
+
return this.coreController.currentState;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
get formState(): Readonly<FormState> {
|
|
199
|
+
return this.formController.currentState;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Benefits
|
|
205
|
+
|
|
206
|
+
- **Type Safety**: Ensures all action types are handled correctly
|
|
207
|
+
- **Performance**: Granular state updates through context splitting
|
|
208
|
+
- **Maintainability**: Consistent patterns across all controllers
|
|
209
|
+
- **Debugging**: Predictable state updates through pure reducer functions
|
|
210
|
+
- **Testability**: Easy to test state transitions in isolation
|