@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.
@@ -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",
@@ -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.2",
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
- "events": [],
260
- "js": { "properties": [], "events": [] }
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.2",
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