@pepperi-addons/ngx-lib-react 0.5.6 → 0.5.8

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/SERVICES.md ADDED
@@ -0,0 +1,419 @@
1
+ # Using PEP-NgxLib Utilities in React
2
+
3
+ ## ⚠️ IMPORTANT: No Angular Service Classes Are Exported
4
+
5
+ `@pepperi-addons/ngx-lib-react` does **not** export Angular service classes such
6
+ as `PepHttpService`, `PepSessionService`, or `PepCustomizationService`.
7
+
8
+ Directly exporting those services would pull Angular and its DI runtime into
9
+ your React bundle, causing:
10
+
11
+ - Massive bundle size increase
12
+ - Build errors / version conflicts
13
+ - Runtime errors in React-only environments
14
+
15
+ Instead, the React package exposes:
16
+
17
+ 1. **Standalone HTTP helpers** with no Angular dependency.
18
+ 2. **Bridge-based helpers** that call selected Angular services via the
19
+ Elements bundle at runtime (through `window.pepperi.services`).
20
+
21
+ ## ✅ Alternatives for React
22
+
23
+ Instead of Angular services, use these React-friendly alternatives:
24
+
25
+ ### For UUID Generation
26
+ ```typescript
27
+ // Use crypto.randomUUID() (modern browsers)
28
+ const uuid = crypto.randomUUID();
29
+
30
+ // Or use a library like 'uuid'
31
+ import { v4 as uuidv4 } from 'uuid';
32
+ const uuid = uuidv4();
33
+ ```
34
+
35
+ ### For Email/URL Validation
36
+ ```typescript
37
+ // Use native JavaScript
38
+ const isValidEmail = (email: string) => {
39
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
40
+ };
41
+
42
+ const isValidUrl = (url: string) => {
43
+ try {
44
+ new URL(url);
45
+ return true;
46
+ } catch {
47
+ return false;
48
+ }
49
+ };
50
+
51
+ // Or use a library like 'validator'
52
+ import validator from 'validator';
53
+ const isValid = validator.isEmail('test@example.com');
54
+ ```
55
+
56
+ ### For Cookie Management
57
+ ```typescript
58
+ // Use js-cookie library
59
+ import Cookies from 'js-cookie';
60
+
61
+ Cookies.set('myCookie', 'value', { expires: 7 });
62
+ const value = Cookies.get('myCookie');
63
+ Cookies.remove('myCookie');
64
+ ```
65
+
66
+ ### For Color Utilities
67
+ ```typescript
68
+ // Use a library like 'color' or 'tinycolor2'
69
+ import Color from 'color';
70
+
71
+ const rgb = Color('#FF5733').rgb().object();
72
+ const contrast = Color('#FF5733').isDark() ? '#FFFFFF' : '#000000';
73
+ ```
74
+
75
+ ## Summary
76
+
77
+ **No Angular service classes are exported from this package.** Use:
78
+
79
+ 1. **HTTP helper functions** for API calls (`pepHttpGet`, `pepHttpPost`, etc.).
80
+ 2. **Bridge-based helpers** to access `PepHttpService`, `PepSessionService`,
81
+ and `PepCustomizationService` via the Elements bundle.
82
+ 3. **Custom element components** for UI (`PepDialog`, `PepSnackBar`, etc.).
83
+ 4. **Standard JavaScript libraries** for utilities (uuid, validator,
84
+ js-cookie, color, etc.).
85
+
86
+ ## Bridge-Based Service Helpers (via Elements bundle)
87
+
88
+ In addition to the standalone HTTP helpers, the React package exposes
89
+ **bridge-based helpers** that call selected Angular services at runtime via the
90
+ Angular Elements bundle. This lets you reuse existing Pepperi logic without
91
+ importing Angular into the React build.
92
+
93
+ > These helpers require that the Elements bundle is loaded and
94
+ > `NgxLibElementsModule` has run, so that `window.pepperi.services` is
95
+ > populated (see README for how to load the Elements scripts).
96
+
97
+ ### PepHttpService helpers
98
+
99
+ ```ts
100
+ import {
101
+ pepHttpGetViaService,
102
+ pepHttpPostViaService,
103
+ pepHttpGetWapi,
104
+ pepHttpPostWapi,
105
+ pepHttpGetPapi,
106
+ pepHttpPostPapi,
107
+ } from '@pepperi-addons/ngx-lib-react';
108
+
109
+ // PAPI example
110
+ const accounts = await pepHttpGetPapi<any[]>('/accounts');
111
+
112
+ // WAPI example
113
+ const created = await pepHttpPostWapi('/transactions', { Amount: 10 });
114
+ ```
115
+
116
+ ### PepSessionService helpers
117
+
118
+ ```ts
119
+ import {
120
+ pepGetIdpToken,
121
+ pepGetWapiBaseUrl,
122
+ pepGetPapiBaseUrl,
123
+ pepSessionGetObject,
124
+ pepSessionSetObject,
125
+ pepSessionRemoveObject,
126
+ } from '@pepperi-addons/ngx-lib-react';
127
+
128
+ const token = pepGetIdpToken();
129
+ const wapiBaseUrl = pepGetWapiBaseUrl();
130
+ const papiBaseUrl = pepGetPapiBaseUrl();
131
+
132
+ pepSessionSetObject('myKey', { foo: 'bar' });
133
+ const value = pepSessionGetObject<{ foo: string }>('myKey');
134
+ pepSessionRemoveObject('myKey');
135
+ ```
136
+
137
+ ### PepCustomizationService helpers (theme & layout)
138
+
139
+ ```ts
140
+ import {
141
+ pepGetBrandingTheme,
142
+ pepGetThemeVariables,
143
+ pepSetThemeVariables,
144
+ pepGetThemeVariable,
145
+ pepGetTopBarHeight,
146
+ pepHideFooter,
147
+ pepShowFooter,
148
+ } from '@pepperi-addons/ngx-lib-react';
149
+
150
+ const theme = pepGetBrandingTheme();
151
+ const vars = pepGetThemeVariables();
152
+
153
+ pepSetThemeVariables({
154
+ '--pep-color-user-primary': '#83b30c',
155
+ '--pep-color-user-secondary': '#6c757d',
156
+ });
157
+
158
+ const topBarHeight = pepGetTopBarHeight();
159
+ pepHideFooter();
160
+ pepShowFooter();
161
+ ```
162
+
163
+ Use these helpers when you want behavior identical to the Angular app (e.g.
164
+ PAPI/WAPI base URL resolution, theme persistence) but from React.
165
+
166
+ ### PepTranslateService helpers (i18n)
167
+
168
+ ```ts
169
+ import {
170
+ pepTranslateInstant,
171
+ pepTranslateGet,
172
+ pepTranslateUse,
173
+ pepTranslateGetDefaultLang,
174
+ pepTranslateGetCurrentLang,
175
+ } from '@pepperi-addons/ngx-lib-react';
176
+
177
+ // Synchronous lookup (for already-loaded keys)
178
+ const label = pepTranslateInstant('Buttons.Save');
179
+
180
+ // Ensure a specific language is active (returns a Promise that resolves when loaded)
181
+ await pepTranslateUse('en');
182
+
183
+ // Async lookup (waits for translations to load)
184
+ const texts = await pepTranslateGet<{ [key: string]: string }>([
185
+ 'Buttons.Save',
186
+ 'Buttons.Cancel',
187
+ ]);
188
+
189
+ const currentLang = pepTranslateGetCurrentLang();
190
+ const defaultLang = pepTranslateGetDefaultLang();
191
+ ```
192
+
193
+ These helpers are thin wrappers over `window.pepperi.services.translate` which is
194
+ initialized by the Elements bundle (`NgxLibElementsModule`). Make sure the
195
+ Elements scripts are loaded before calling them.
196
+
197
+ ### PepAddonService helpers (addons & CPI)
198
+
199
+ ```ts
200
+ import {
201
+ pepAddonGetApi,
202
+ pepAddonPostApi,
203
+ pepAddonGetCpi,
204
+ pepAddonPostCpi,
205
+ pepAddonGetServerBaseUrl,
206
+ pepAddonGetStaticFolder,
207
+ pepAddonSetStaticFolder,
208
+ } from '@pepperi-addons/ngx-lib-react';
209
+
210
+ // Classic addon API (sync or async)
211
+ const result = await pepAddonGetApi<any>(
212
+ '00000000-0000-0000-0000-000000000000',
213
+ 'api',
214
+ 'my_function'
215
+ );
216
+
217
+ // CPI call example
218
+ const cpiResult = await pepAddonGetCpi<any>(
219
+ '00000000-0000-0000-0000-000000000000',
220
+ '/my/relative/url'
221
+ );
222
+
223
+ // Static folder helpers
224
+ const baseUrl = pepAddonGetServerBaseUrl('00000000-0000-0000-0000-000000000000');
225
+ const staticFolder = pepAddonGetStaticFolder('00000000-0000-0000-0000-000000000000');
226
+ pepAddonSetStaticFolder('/my/addon/', '00000000-0000-0000-0000-000000000000');
227
+ ```
228
+
229
+ These map directly to `PepAddonService` and rely on `window.pepperi.services.addon`.
230
+
231
+ ### PepColorService helpers (color utilities)
232
+
233
+ ```ts
234
+ import {
235
+ pepFindClosestAccessibleColor,
236
+ pepLightOrDark,
237
+ } from '@pepperi-addons/ngx-lib-react';
238
+
239
+ const adjusted = pepFindClosestAccessibleColor('#ffffff', '#000000', 4.5);
240
+ const tone = pepLightOrDark('#83b30c'); // 'light' | 'dark'
241
+ ```
242
+
243
+ These wrap `window.pepperi.services.color` (PepColorService) to reuse Pepperi’s
244
+ accessibility-oriented color logic.
245
+
246
+ ### PepLoaderService helpers (global loader)
247
+
248
+ ```ts
249
+ import { pepLoaderShow, pepLoaderHide } from '@pepperi-addons/ngx-lib-react';
250
+
251
+ async function doSomething() {
252
+ try {
253
+ pepLoaderShow();
254
+ // ... async work ...
255
+ } finally {
256
+ pepLoaderHide();
257
+ }
258
+ }
259
+ ```
260
+
261
+ These call `window.pepperi.services.loader.show()` / `.hide()`, which in turn
262
+ drive the global Pepperi loader via `PepLoaderService`.
263
+
264
+ ### PepDialogService helpers (default dialogs)
265
+
266
+ ```ts
267
+ import {
268
+ pepOpenDefaultDialog,
269
+ pepOpenColorPickerDialog,
270
+ PepDialogActionsType,
271
+ PepDialogSizeType,
272
+ } from '@pepperi-addons/ngx-lib-react';
273
+
274
+ // Default dialog example
275
+ await pepOpenDefaultDialog<void>({
276
+ title: 'Confirm Action',
277
+ content: 'Opened from React via pepOpenDefaultDialog helper',
278
+ actionsType: 'cancel-continue' as PepDialogActionsType,
279
+ showClose: true,
280
+ showHeader: true,
281
+ showFooter: true,
282
+
283
+ // Optional dialog config forwarded to PepDialogService.getDialogConfig
284
+ size: 'small' as PepDialogSizeType, // 'inline' | 'small' | 'regular' | 'large' | 'full-screen'
285
+ disableClose: false,
286
+ hasBackdrop: true,
287
+ minWidth: '320px',
288
+ maxWidth: '600px',
289
+ maxHeight: '80vh',
290
+ panelClass: 'my-custom-dialog-class',
291
+ });
292
+
293
+ // Color picker dialog example
294
+ const colorResult = await pepOpenColorPickerDialog<any>({
295
+ value: '#ff0000',
296
+ type: 'regular',
297
+ showAAComplient: true,
298
+ checkAAComplient: true,
299
+ });
300
+ ```
301
+
302
+ `pepOpenDefaultDialog` and `pepOpenColorPickerDialog` are thin Promise-based
303
+ wrappers over `window.pepperi.services.dialog`. They rely on the same
304
+ `PepDialogService` implementation used by Angular apps, so all Pepperi dialog
305
+ styling and behavior (including size classes from `PepDialogSizeType`) apply.
306
+
307
+ ### React-only JSX dialog helper (openReactPepDialog)
308
+
309
+ In addition to the service-based dialogs, the React package exposes a
310
+ **React-only helper** for opening a Pepperi dialog shell with custom JSX
311
+ content.
312
+
313
+ ```ts
314
+ import { openReactPepDialog, PepDialogSizeType } from '@pepperi-addons/ngx-lib-react';
315
+
316
+ const result = await openReactPepDialog<boolean>({
317
+ title: 'React JSX Dialog',
318
+ size: 'small' as PepDialogSizeType, // optional: controls the size CSS class
319
+ renderContent: (close) => (
320
+ <>
321
+ {/* 1) First top-level wrapper = dialog body (mat-dialog-content) */}
322
+ <div pep-dialog-content>
323
+ <p>This dialog body is pure React JSX.</p>
324
+ <p>It still uses the Pepperi dialog shell.</p>
325
+ </div>
326
+
327
+ {/* 2) Second top-level wrapper = dialog actions (mat-dialog-actions) */}
328
+ <div
329
+ pep-dialog-actions
330
+ className="pep-spacing-element-negative"
331
+ style={{ display: 'flex', justifyContent: 'flex-end' }}
332
+ >
333
+ <button
334
+ className="pep-spacing-element mat-button pep-button md weak"
335
+ onClick={() => close(false)}
336
+ >
337
+ Cancel
338
+ </button>
339
+ <button
340
+ className="pep-spacing-element mat-button pep-button md strong"
341
+ onClick={() => close(true)}
342
+ >
343
+ OK
344
+ </button>
345
+ </div>
346
+ </>
347
+ ),
348
+ });
349
+ ```
350
+
351
+ Notes:
352
+
353
+ - `openReactPepDialog` is **pure React** – it does not call `PepDialogService`.
354
+ - It renders a `PepDialog` web component inside a Pepperi-styled overlay using
355
+ the same DOM structure and CSS classes as the Angular dialogs.
356
+ - The `size` option is optional; when provided, it adds the corresponding size
357
+ class (e.g. `small`, `regular`, `large`) to the dialog container.
358
+ - Starting from `@pepperi-addons/ngx-lib-react@0.5.7`, `PepDialog` uses
359
+ **React portals** to inject JSX into the internal Angular
360
+ `mat-dialog-content` / `mat-dialog-actions` containers.
361
+ - For correct placement:
362
+ - `renderContent` should return **exactly two logical top-level children**
363
+ (usually wrapped in a fragment `<>...</>`).
364
+ - The **first** child is treated as the **content wrapper** and rendered into
365
+ `mat-dialog-content`.
366
+ - The **second** child is treated as the **actions wrapper** and rendered into
367
+ `mat-dialog-actions`.
368
+ - Inside these wrappers you can use either plain HTML elements or Pepperi
369
+ React components (`PepSelect`, `PepButton`, etc.).
370
+
371
+ Example mirroring a permissions dialog (body with two selects + footer button):
372
+
373
+ ```tsx
374
+ import { openReactPepDialog, PepSelect, PepButton } from '@pepperi-addons/ngx-lib-react';
375
+
376
+ async function openPermissionsDialogDemo() {
377
+ await openReactPepDialog<void>({
378
+ title: 'Add Permission',
379
+ size: 'regular',
380
+ renderContent: () => (
381
+ <>
382
+ <div pep-dialog-content className="permissions-dialog-content">
383
+ <PepSelect
384
+ keyProp="addon"
385
+ label="Select an Addon"
386
+ options={addonOptions}
387
+ value={selectedAddonKey}
388
+ emptyOption={false}
389
+ onValueChange={setSelectedAddonKey}
390
+ />
391
+
392
+ <PepSelect
393
+ keyProp="editor"
394
+ label="Select an Editor"
395
+ options={editorOptions}
396
+ value={selectedEditorKey}
397
+ emptyOption={false}
398
+ disabled={!selectedAddonKey}
399
+ onValueChange={setSelectedEditorKey}
400
+ />
401
+ </div>
402
+
403
+ <div pep-dialog-actions className="permissions-dialog-actions">
404
+ <PepButton
405
+ value="Confirm"
406
+ styleType="strong"
407
+ disabled={!selectedAddonKey || !selectedEditorKey}
408
+ onButtonClick={handleConfirmClick}
409
+ />
410
+ </div>
411
+ </>
412
+ ),
413
+ });
414
+ }
415
+ ```
416
+
417
+ ## Support
418
+
419
+ For issues or questions about specific services, please refer to the main PEP-NgxLib documentation or contact the Pepperi development team.