@enonic/nextjs-adapter 3.0.0-RC4 → 3.0.0-RC5

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 (2) hide show
  1. package/README.md +516 -96
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -4,27 +4,33 @@
4
4
 
5
5
  ## Installation
6
6
 
7
- ---
8
-
9
7
  ```bash
10
8
  npm i --save @enonic/nextjs-adapter
11
9
  ```
12
10
 
13
11
  ## Usage
14
12
 
15
- ---
13
+ All functions and views are split into 4 categories by usage:
14
+
15
+ - `@enonic/nextjs-adapter` -- can be used both on server and client sides
16
+ - `@enonic/nextjs-adapter/server` -- can only be used on server side
17
+ - `@enonic/nextjs-adapter/client` -- can only be used on client side
18
+ - `@enonic/nextjs-adapter/views/...` -- views folder, every view has its own file with a default export
16
19
 
17
- Just import required functions and views in your project:
20
+ Here's the usage example in your project:
18
21
 
19
22
  ```tsx
20
- // all functions and interfaces are accessible at the library root
21
- import {fetchContent} from "@enonic/nextjs-adapter";
23
+ // server-side functions are accessible at /server
24
+ import {fetchContent} from "@enonic/nextjs-adapter/server";
22
25
 
23
26
  // views are placed in a folder called `views` and are default exports in files
24
27
  import MainView from "@enonic/nextjs-adapter/views/MainView"
25
28
 
26
29
  // ...
27
- const props = await fetchContent(path, context);
30
+ const props = await fetchContent(path, {
31
+ contentPath: '/content/path',
32
+ locale: 'en',
33
+ });
28
34
  // ...
29
35
 
30
36
  return <MainView {...props}/>
@@ -32,26 +38,26 @@ return <MainView {...props}/>
32
38
 
33
39
  ## API
34
40
 
35
- ---
41
+ ### <a id="server-side"></a>Server-side only functions
36
42
 
37
- ### Functions
43
+ They are available at `@enonic/nextjs-adapter/server`
38
44
 
39
- They are available at the library root at `@enonic/nextjs-adapter`
45
+ <br/>
40
46
 
41
47
  #### <a id="fetch-content"></a>`fetchContent(contentPath: string | string[], context: Context) => Promise<FetchContentResult>`
42
48
 
43
49
  Fetches the content/component by path with component queries optimization, page structure as well as runtime info calculation. This is the
44
50
  main method for querying content.
45
51
 
46
- | Argument | Description |
47
- |-----------|---------------------------------------|
48
- | `path` | Path to content |
49
- | `context` | Execution context provided by Next.js |
52
+ | Argument | Description |
53
+ |-----------|-------------------|
54
+ | `path` | Path to content |
55
+ | `context` | Execution context |
50
56
 
51
57
  Usage:
52
58
 
53
59
  ```tsx
54
- import {fetchContent} from '@enonic/nextjs-adapter';
60
+ import {fetchContent} from '@enonic/nextjs-adapter/server';
55
61
 
56
62
  const response = fetchContent('/path/to/content', context);
57
63
  ```
@@ -71,22 +77,29 @@ type FetchContentResult = {
71
77
  };
72
78
  ```
73
79
 
74
- ---
80
+ <br/>
75
81
 
76
- #### <a id="fetch-guillotine"></a>`fetchGuillotine(apiUrl: string, body: ContentApiBaseBody, headers?: {}) => Promise<GuillotineResult>`
82
+ #### <a id="fetch-guillotine"></a>`fetchGuillotine(apiUrl: string, mapping: LocaleMapping, options?: FetchOptions) => Promise<GuillotineResult>`
77
83
 
78
84
  Makes a custom request to Guillotine. Used by [fetchContent()](#fetch-content) method.
79
85
 
80
- | Argument | Description |
81
- |-----------|---------------------------------------------------------|
82
- | `apiUrl` | Guillotine API URL |
83
- | `body` | Body of the request |
84
- | `headers` | Object of custom headers with string values. _Optional_ |
86
+ | Argument | Description |
87
+ |-----------|---------------------------------------------------|
88
+ | `apiUrl` | Guillotine API URL |
89
+ | `mapping` | [Mapping](#locale-mapping-type) locale to project |
90
+ | `options` | Request and Next.js config options _(Optional)_ |
85
91
 
86
92
  Usage:
87
93
 
88
94
  ```tsx
89
- import {fetchGuillotine} from '@enonic/nextjs-adapter';
95
+ import {fetchGuillotine} from '@enonic/nextjs-adapter/server';
96
+ import {getLocaleMapping} from '@enonic/nextjs-adapter';
97
+
98
+ const apiUrl = 'http://domain:8000/graphql/api';
99
+
100
+ const mapping = getLocaleMapping({
101
+ contentPath: '/current/content/path',
102
+ });
90
103
 
91
104
  const body = {
92
105
  query: 'qraphql query as string',
@@ -99,7 +112,17 @@ const headers = {
99
112
  'custom-header': 'header-value',
100
113
  };
101
114
 
102
- const result = fetchGuillotine('http://domain:8000/graphql/api', body, headers);
115
+ const opts = {
116
+ body,
117
+ headers,
118
+ method: 'GET',
119
+ next: {
120
+ revalidate: 60,
121
+ tags: ['tag1', 'tag2'],
122
+ }
123
+ };
124
+
125
+ const result = fetchGuillotine(apiUrl, mapping, opts);
103
126
  ```
104
127
 
105
128
  Response type:
@@ -114,23 +137,29 @@ type GuillotineResult = {
114
137
  };
115
138
  ```
116
139
 
117
- ---
140
+ <br/>
118
141
 
119
- #### `fetchFromApi(apiUrl: string, body: ContentApiBaseBody, headers?: {}, method?: string) => Promise<any>`
142
+ #### `fetchFromApi(apiUrl: string, mapping: LocaleMapping, options?: FetchOptions) => Promise<GuillotineResponseJson>`
120
143
 
121
144
  Makes custom third-party service request. Used by the [fetchGuillotine()](#fetch-guillotine) method.
122
145
 
123
- | Argument | Description |
124
- |-----------|------------------------------------------------------------------------------------|
125
- | `apiUrl` | Service API URL |
126
- | `body` | Body of the request |
127
- | `headers` | Object of custom headers with string values. _Optional_ |
128
- | `method` | Method of the request: `HEAD`, `POST`, `GET`, etc. _Optional, defaults to `POST`._ |
146
+ | Argument | Description |
147
+ |-----------|---------------------------------------------------|
148
+ | `apiUrl` | Service API URL |
149
+ | `mapping` | [Mapping](#locale-mapping-type) locale to project |
150
+ | `options` | Request and Next.js config options _(Optional)_ |
129
151
 
130
152
  Usage:
131
153
 
132
154
  ```tsx
133
- import {fetchFromApi} from '@enonic/nextjs-adapter';
155
+ import {fetchFromApi} from '@enonic/nextjs-adapter/server';
156
+ import {getLocaleMapping} from '@enonic/nextjs-adapter';
157
+
158
+ const apiUrl = 'http://domain:8000/graphql/api';
159
+
160
+ const mapping = getLocaleMapping({
161
+ contentPath: '/current/content/path',
162
+ });
134
163
 
135
164
  const body = {
136
165
  query: 'qraphql query as string',
@@ -143,17 +172,144 @@ const headers = {
143
172
  'custom-header': 'header-value',
144
173
  }
145
174
 
146
- const result = fetchFromApi('http://domain:8000/graphql/api', body, headers, 'GET');
175
+ const opts = {
176
+ body,
177
+ headers,
178
+ method: 'POST',
179
+ next: {
180
+ revalidate: 60,
181
+ tags: ['tag1', 'tag2'],
182
+ }
183
+ };
184
+
185
+ const result = fetchFromApi(apiUrl, mapping, opts);
186
+ ```
187
+
188
+ <br/>
189
+
190
+ #### <a id="fetch-paths-for-all-locales"></a>`fetchContentPathsForAllLocales(path: string, query?: string, count?: number) => Promise<ContentPathItem[]>`
191
+
192
+ Loads all content paths for all locales. Generally used for static site generation.
193
+
194
+ | Argument | Description |
195
+ |----------|---------------------------------------------------|
196
+ | `apiUrl` | Service API URL |
197
+ | `query` | Request and Next.js config options _(Optional)_ * |
198
+ | `count` | Max result count _(Optional, defaults to 999)_ |
199
+
200
+ &ast; Default query gets up to `count` results, sorts them by `modifiedTime` and excludes following content types:
201
+
202
+ ```
203
+ "base:shortcut",
204
+ "portal:fragment",
205
+ "portal:template-folder",
206
+ "portal:page-template",
207
+ "media:*"
208
+ ```
209
+
210
+ Usage:
211
+
212
+ ```tsx
213
+ import {fetchContentPathsForAllLocales} from '@enonic/nextjs-adapter/server';
214
+
215
+ const contentPaths = fetchContentPathsForLocale('/', 'custom graphql query', 1001);
216
+ ```
217
+
218
+ <br/>
219
+
220
+ #### `fetchContentPathsForLocale(path: string, mapping: LocaleMapping, query?: string, count?: number) => Promise<ContentPathItem[]>`
221
+
222
+ Loads all content paths for the current locale. Generally used for static site generation.
223
+ Used by [fetchContentPathsForAllLocales()](#fetch-paths-for-all-locales)
224
+
225
+ | Argument | Description |
226
+ |-----------|-----------------------------------------------------------------------------------------------------|
227
+ | `apiUrl` | Service API URL |
228
+ | `mapping` | [Mapping](#locale-mapping-type) locale to project |
229
+ | `query` | Request and Next.js config options _(Optional, [default value here](#fetch-paths-for-all-locales))_ |
230
+ | `count` | Max result count _(Optional, defaults to 999)_ |
231
+
232
+ Usage:
233
+
234
+ ```tsx
235
+ import {fetchContentPathsForLocale} from '@enonic/nextjs-adapter/server';
236
+ import {getLocaleMapping} from '@enonic/nextjs-adapter';
237
+
238
+ const mapping = getLocaleMapping({
239
+ contentPath: '/current/content/path',
240
+ });
241
+
242
+ const contentPaths = fetchContentPathsForLocale('/', mapping, 'custom graphql query', 1001);
243
+ ```
244
+
245
+ <br/>
246
+
247
+ ### <a id="client-side"></a>Client-side only functions
248
+
249
+ They are available at `@enonic/nextjs-adapter/client`
250
+
251
+ <br/>
252
+
253
+ #### <a id="locale-context-provider"></a>`<LocaleContextProvider locale="en">`
254
+
255
+ Create a React.js context that allows child elements to access and modify current locale as well as localize static texts for current
256
+ locale. See [useLocaleContext()](#use-locale-context) method for example.
257
+
258
+ | Argument | Type | Description |
259
+ |----------|----------|------------------------------|
260
+ | `locale` | `String` | Set the initial locale value |
261
+
262
+ Usage:
263
+
264
+ ```tsx
265
+ import {LocaleContextProvider} from '@enonic/nextjs-adapter/client';
266
+
267
+ <LocaleContextProvider locale="en"> ...child elements... </LocaleContextProvider>
268
+ ```
269
+
270
+ <br/>
271
+
272
+ #### <a id="use-locale-context"></a>`useLocaleContext() => LocaleContextType`
273
+
274
+ Methods to access and modify current locale as well as localize static texts, where `LocaleContextType` is:
275
+
276
+ ```tsx
277
+ interface LocaleContextType {
278
+ dictionary: Dict
279
+ locale: string
280
+ localize: (key: string, ...args: any[]) => string
281
+ setLocale: (locale: string) => Promise<Dict>
282
+ }
283
+ ```
284
+
285
+ Usage:
286
+
287
+ ```tsx
288
+ 'use client';
289
+
290
+ import {useLocaleContext} from '@enonic/nextjs-adapter/client';
291
+
292
+ export default function ClientSideComponent() {
293
+ const {locale, localize} = useLocaleContext();
294
+ const localizedText = localize('text.key');
295
+ // ...
296
+ }
147
297
  ```
148
298
 
149
- ---
299
+ <br/>
300
+
301
+ ### <a id="multi-side"></a>Both client and server-side functions
302
+
303
+ They are available at `@enonic/nextjs-adapter`
150
304
 
151
- #### `getUrl(url: string, meta: MetaData) => string`
305
+ <br/>
152
306
 
153
- Converts an absolute URL to the relative one for current viewer (Next.js/Enonic XP).
307
+ #### <a id="get-url"></a>`getUrl(url: string, meta: MetaData) => string`
308
+
309
+ Converts a site-relative or absolute URL to relative one for current viewer (Next.js/Enonic XP). Also takes care of locale if needed.
154
310
 
155
311
  > **INFO:** For your URLs to work both in Enonic XP and Next.js you need to:
156
- > 1. Query absolute URLs from guillotine
312
+ > 1. Query site-relative or absolute URLs from guillotine
157
313
  > 2. Wrap them with `getUrl()` function in the views
158
314
 
159
315
  | Argument | Description |
@@ -166,10 +322,34 @@ Usage:
166
322
  ```tsx
167
323
  import {getUrl} from '@enonic/nextjs-adapter';
168
324
 
169
- const urlRelativeToViewer = getUrl('http://domain:8000/graphql/api', meta);
325
+ const urlRelativeToViewer = getUrl('/some/content/url', meta);
170
326
  ```
171
327
 
172
- ---
328
+ <br/>
329
+
330
+ #### <a id="get-asset"></a>`getAsset(url: string, meta: MetaData) => string`
331
+
332
+ Converts a local asset URL to relative one for current viewer (Next.js/Enonic XP). It doesn't append locales unlike [getUrl()]
333
+ (#get-url).
334
+
335
+ > **INFO:** For your URLs to work both in Enonic XP and Next.js you need to:
336
+ > 1. Use relative URL to local asset
337
+ > 2. Wrap them with `getAsset()` function in the views
338
+
339
+ | Argument | Description |
340
+ |----------|---------------------------------------------------------|
341
+ | `url` | asset URL you want to transform |
342
+ | `meta` | Runtime data returned by [fetchContent](#fetch-content) |
343
+
344
+ Usage:
345
+
346
+ ```tsx
347
+ import {getAsset} from '@enonic/nextjs-adapter';
348
+
349
+ const urlRelativeToViewer = getAsset('/some/asset/url', meta);
350
+ ```
351
+
352
+ <br/>
173
353
 
174
354
  #### <a id="rich-text-query"></a>`richTextQuery(fieldName: string) => string`
175
355
 
@@ -196,14 +376,40 @@ const query = `query($path:ID!){
196
376
  }`;
197
377
  ```
198
378
 
379
+ <br/>
380
+
381
+ #### `validateData(props: FetchContentResult) => void`
382
+
383
+ Validates data returned by [fetchContent()](#fetch-content) method. Throws an error or notFound() if data is invalid.
384
+
385
+ | Argument | Description |
386
+ |----------|-----------------------------|
387
+ | `props` | `FetchContentResult` object |
388
+
389
+ Usage:
390
+
391
+ ```tsx
392
+ import {fetchContent} from '@enonic/nextjs-adapter/server';
393
+ import {validateData} from '@enonic/nextjs-adapter';
394
+
395
+ const data = fetchContent({
396
+ contentPath: '/path/to/content',
397
+ locale: 'en',
398
+ });
399
+
400
+ validateData(data);
401
+ ```
402
+
403
+ <br/>
404
+
199
405
  ### `ComponentRegistry`
200
406
 
201
407
  Registry containing definitions of all components (i.e. pages, parts, layouts, macros, etc. ). It is used in the runtime by `nextjs-adapter`
202
408
  to make component queries and render components. It has several public methods:
203
409
 
204
- ---
410
+ <br/>
205
411
 
206
- #### `setCommonQuery(query: SelectedQueryMaybeVariablesFunc): void`
412
+ #### `static setCommonQuery(query: SelectedQueryMaybeVariablesFunc): void`
207
413
 
208
414
  Sets up a common query that is going to be executed along with component queries and passed to every component on the page.
209
415
 
@@ -228,9 +434,9 @@ const query = {
228
434
  ComponentRegistry.setCommonQuery(query);
229
435
  ```
230
436
 
231
- ---
437
+ <br/>
232
438
 
233
- #### `getCommonQuery(): SelectedQueryMaybeVariablesFunc`
439
+ #### `static getCommonQuery(): SelectedQueryMaybeVariablesFunc`
234
440
 
235
441
  Gets the common query definition.
236
442
 
@@ -255,9 +461,9 @@ import {ComponentRegistry} from '@enonic/nextjs-adapter';
255
461
  const query = ComponentRegistry.getCommonQuery();
256
462
  ```
257
463
 
258
- ---
464
+ <br/>
259
465
 
260
- #### `getByComponent(component: PageComponent): ComponentDefinition | undefined`
466
+ #### `static getByComponent(component: PageComponent): ComponentDefinition | undefined`
261
467
 
262
468
  Gets component definition from the ComponentRegistry.
263
469
 
@@ -285,19 +491,19 @@ interface ComponentDefinition {
285
491
  }
286
492
  ```
287
493
 
288
- ---
494
+ <br/>
289
495
 
290
- #### `addMacro(name: string, obj: ComponentDefinition): void`
496
+ #### `static addMacro(name: string, obj: ComponentDefinition): void`
291
497
 
292
- #### `addPart(name: string, obj: ComponentDefinition): void`
498
+ #### `static addPart(name: string, obj: ComponentDefinition): void`
293
499
 
294
- #### `addLayout(name: string, obj: ComponentDefinition): void`
500
+ #### `static addLayout(name: string, obj: ComponentDefinition): void`
295
501
 
296
- #### `addCPage(name: string, obj: ComponentDefinition): void`
502
+ #### `static addCPage(name: string, obj: ComponentDefinition): void`
297
503
 
298
- #### `addContentType(name: string, obj: ComponentDefinition): void`
504
+ #### `static addContentType(name: string, obj: ComponentDefinition): void`
299
505
 
300
- #### `addComponent(name: string, obj: ComponentDefinition): void`
506
+ #### `static addComponent(name: string, obj: ComponentDefinition): void`
301
507
 
302
508
  Saves the component definition in ComponentRegistry by name.
303
509
 
@@ -319,19 +525,19 @@ const definition = {}
319
525
  ComponentRegistry.addMacro('macro-name', definition);
320
526
  ```
321
527
 
322
- ---
528
+ <br/>
323
529
 
324
- #### `getMacro(name: string): ComponentDefinition | undefined`
530
+ #### `static getMacro(name: string): ComponentDefinition | undefined`
325
531
 
326
- #### `getPart(name: string): ComponentDefinition | undefined`
532
+ #### `static getPart(name: string): ComponentDefinition | undefined`
327
533
 
328
- #### `getLayout(name: string): ComponentDefinition | undefined`
534
+ #### `static getLayout(name: string): ComponentDefinition | undefined`
329
535
 
330
- #### `getPage(name: string): ComponentDefinition | undefined`
536
+ #### `static getPage(name: string): ComponentDefinition | undefined`
331
537
 
332
- #### `getContentType(name: string): ComponentDefinition | undefined`
538
+ #### `static getContentType(name: string): ComponentDefinition | undefined`
333
539
 
334
- #### `getComponent(name: string): ComponentDefinition | undefined`
540
+ #### `static getComponent(name: string): ComponentDefinition | undefined`
335
541
 
336
542
  Gets the component definition stored in ComponentRegistry by its name.
337
543
 
@@ -351,19 +557,19 @@ const definition = ComponentRegistry.getMacro('macro-name');
351
557
 
352
558
  Response type: [component definition](#comp-def)
353
559
 
354
- ---
560
+ <br/>
355
561
 
356
- #### `getMacros(): ComponentDefinition[]`
562
+ #### `static getMacros(): ComponentDefinition[]`
357
563
 
358
- #### `getParts(): ComponentDefinition[]`
564
+ #### `static getParts(): ComponentDefinition[]`
359
565
 
360
- #### `getLayouts(): ComponentDefinition[]`
566
+ #### `static getLayouts(): ComponentDefinition[]`
361
567
 
362
- #### `getPages(): ComponentDefinition[]`
568
+ #### `static getPages(): ComponentDefinition[]`
363
569
 
364
- #### `getContentTypes(): ComponentDefinition[]`
570
+ #### `static getContentTypes(): ComponentDefinition[]`
365
571
 
366
- #### `getComponents(): ComponentDefinition[]`
572
+ #### `static getComponents(): ComponentDefinition[]`
367
573
 
368
574
  Gets all component definitions stored in ComponentRegistry.
369
575
 
@@ -379,33 +585,37 @@ const macros = ComponentRegistry.getMacros();
379
585
 
380
586
  Response type: List of [component definitions](#comp-def)
381
587
 
588
+ <br/>
589
+
382
590
  ### `UrlProcessor`
383
591
 
384
592
  Helper singleton for processing URLs.
385
593
 
386
- ---
594
+ <br/>
387
595
 
388
- #### <a id="process"></a>`static process(url: string, meta: MetaData): string`
596
+ #### <a id="process"></a>`static process(url: string, meta: MetaData, serverSide = false, isResource = false): string`
389
597
 
390
598
  Processes the absolute URL to become relative for the current viewer, while keeping in mind Next.js assets and Enonic XP binary content
391
599
  links
392
600
 
393
- > **NOTE:** There is an alias to this function called `getUrl()` available at `@enonic/nextjs-adapter`
601
+ > **NOTE:** There are convenience aliases to this function called [getUrl()](#get-url) and [getAsset()](#get-asset)
394
602
 
395
- | Argument | Description |
396
- |----------|---------------------------------------------------------|
397
- | `url` | Absolute URL |
398
- | `meta` | Runtime data returned by [fetchContent](#fetch-content) |
603
+ | Argument | Description |
604
+ |--------------|------------------------------------------------------------------------------|
605
+ | `url` | Absolute URL |
606
+ | `meta` | Runtime data returned by [fetchContent](#fetch-content) |
607
+ | `serverSide` | Whether URL is going to be used on the server side _(Skips adding basePath)_ |
608
+ | `isResource` | Whether URL is a resource _(Skips adding locale)_ |
399
609
 
400
610
  Usage:
401
611
 
402
612
  ```tsx
403
613
  import {UrlProcessor} from '@enonic/nextjs-adapter';
404
614
 
405
- const url = UrlProcessor.process('http://www.some.site.com/url/to/content', meta);
615
+ const url = UrlProcessor.process('http://www.some.site.com/url/to/content', meta, true, false);
406
616
  ```
407
617
 
408
- ---
618
+ <br/>
409
619
 
410
620
  #### `static processSrcSet(srcset: string, meta: MetaData): string`
411
621
 
@@ -424,11 +634,12 @@ import {UrlProcessor} from '@enonic/nextjs-adapter';
424
634
  const url = UrlProcessor.processSrcSet('<srcset value>', meta);
425
635
  ```
426
636
 
427
- ---
637
+ <br/>
428
638
 
429
639
  #### `static setSiteKey(key: string): void`
430
640
 
431
- Sets the site key value that is needed for correct URL processing. It is automatically done by `nextjs-adapter` so you don't have to do it.
641
+ Sets the site key value that is needed for correct absolute URL processing. It is automatically done by `nextjs-adapter` so you don't
642
+ have to do it.
432
643
 
433
644
  > **WARNING:** Overriding this value may result in wrong URL processing !
434
645
 
@@ -444,7 +655,7 @@ import {UrlProcessor} from '@enonic/nextjs-adapter';
444
655
  UrlProcessor.setSiteKey('<site key>');
445
656
  ```
446
657
 
447
- ---
658
+ <br/>
448
659
 
449
660
  #### `static isMediaLink(ref: string, linkData: LinkData[]): boolean`
450
661
 
@@ -465,7 +676,7 @@ import {UrlProcessor} from '@enonic/nextjs-adapter';
465
676
  UrlProcessor.isMediaLink('<link ref>', linkData);
466
677
  ```
467
678
 
468
- ---
679
+ <br/>
469
680
 
470
681
  #### `static isContentImage(ref: string, imageData: ImageData[]): boolean`
471
682
 
@@ -486,30 +697,234 @@ import {UrlProcessor} from '@enonic/nextjs-adapter';
486
697
  UrlProcessor.isContentImage('<image ref>', imageData);
487
698
  ```
488
699
 
700
+ <br/>
701
+
702
+ ### Enonic XP locale mapping functions
703
+
704
+ In order to create association between locale and Enonic XP project, `ENONIC_MAPPINGS` environment variable should be set.
705
+ Functions for reading those mappings are available at `@enonic/nextjs-adapter`.
706
+
707
+ <br/>
708
+
709
+ #### `getLocaleMapping(context: Context): LocaleMapping`
710
+
711
+ | Argument | Description |
712
+ |-----------|------------------|
713
+ | `context` | `Context` object |
714
+
715
+ Usage:
716
+
717
+ ```tsx
718
+ import {getLocaleMapping} from '@enonic/nextjs-adapter';
719
+
720
+ const mapping = getLocaleMapping({
721
+ contentPath: '/current/content/path',
722
+ locale: 'en',
723
+ });
724
+ ```
725
+
726
+ <a id="locale-mapping-type"></a>Response type:
727
+
728
+ ```tsx
729
+ export interface LocaleMapping {
730
+ default: boolean
731
+ project: string
732
+ site: string
733
+ locale: string
734
+ }
735
+ ```
736
+
737
+ <br/>
738
+
739
+ #### `getLocaleMappingByProjectId(projectId?: string, useDefault = true): LocaleMapping`
740
+
741
+ | Argument | Description |
742
+ |--------------|------------------------------------------------------------|
743
+ | `projectId` | Enonic project ID _(Optional)_ |
744
+ | `useDefault` | Use default locale as fallback _(Optional, default: true)_ |
745
+
746
+ Usage:
747
+
748
+ ```tsx
749
+ import {getLocaleMappingByProjectId} from '@enonic/nextjs-adapter';
750
+
751
+ const mapping = getLocaleMappingByProjectId('project-id', true);
752
+ ```
753
+
754
+ [Response type](#locale-mapping-type)
755
+
756
+ <br/>
757
+
758
+ #### `getLocaleMappingByLocale(locale?: string, useDefault = true): LocaleMapping`
759
+
760
+ | Argument | Description |
761
+ |--------------|------------------------------------------------------------|
762
+ | `locale` | locale ID _(Optional)_ |
763
+ | `useDefault` | Use default locale as fallback _(Optional, default: true)_ |
764
+
765
+ Usage:
766
+
767
+ ```tsx
768
+ import {getLocaleMappingByLocale} from '@enonic/nextjs-adapter';
769
+
770
+ const mapping = getLocaleMappingByLocale('en', true);
771
+ ```
772
+
773
+ [Response type](#locale-mapping-type)
774
+
775
+ <br/>
776
+
777
+ #### `getRequestLocaleInfo(context: Context): LocaleMapping`
778
+
779
+ Attempts to get the locale info from the request. Along with that it also returns the default locale and all configured locales.
780
+
781
+ | Argument | Description |
782
+ |-----------|------------------|
783
+ | `context` | `Context` object |
784
+
785
+ Usage:
786
+
787
+ ```tsx
788
+ import {getRequestLocaleInfo} from '@enonic/nextjs-adapter';
789
+
790
+ const mapping = getRequestLocaleInfo({
791
+ contentPath: '/current/content/path',
792
+ locale: 'en',
793
+ });
794
+ ```
795
+
796
+ Response type:
797
+
798
+ ```tsx
799
+ interface LocaleInfo {
800
+ locale: string,
801
+ locales: string[],
802
+ defaultLocale: string
803
+ }
804
+ ```
805
+
806
+ <br/>
807
+
808
+ ### `I18n` localization functions
809
+
810
+ These functions can be used both on server and client sides, but it is recommended to
811
+ use [native React.js context](#locale-context-provider) classes for client-side localization.
812
+
813
+ <br/>
814
+
815
+ #### `static I18n.setLocale(locale: string): Promise<Dict>`
816
+
817
+ Sets the current locale and returns the dictionary for it.
818
+
819
+ | Argument | Description |
820
+ |----------|----------------------|
821
+ | `locale` | Locale id, i.e. `en` |
822
+
823
+ Usage:
824
+
825
+ ```tsx
826
+ import {I18n} from '@enonic/nextjs-adapter';
827
+
828
+ const dict = await I18n.setLocale('en');
829
+ ```
830
+
831
+ <a id="dict-type"></a>Response type:
832
+
833
+ ```tsx
834
+ interface Dict {
835
+ [key: string]: string
836
+ }
837
+ ```
838
+
839
+ <br/>
840
+
841
+ #### `static I18n.localize(key: string, ...args: any[]): string`
842
+
843
+ Localizes the static text by key and replaces placeholders with provided arguments.
844
+
845
+ | Argument | Description |
846
+ |-----------|--------------------|
847
+ | `key` | text key |
848
+ | `...args` | template arguments |
849
+
850
+ Usage:
851
+
852
+ ```tsx
853
+ import {I18n} from '@enonic/nextjs-adapter';
854
+
855
+ const localizedText = I18n.localize('text.key', 'value1', 'value2');
856
+ ```
857
+
858
+ <br/>
859
+
860
+ #### `static I18n.getLocale(): string`
861
+
862
+ Returns the current locale.
863
+
864
+ Usage:
865
+
866
+ ```tsx
867
+ import {I18n} from '@enonic/nextjs-adapter';
868
+
869
+ const locale = I18n.getLocale();
870
+ ```
871
+
872
+ <br/>
873
+
874
+ #### `static I18n.getDictionary(): Dict`
875
+
876
+ Returns dictionary for the current locale.
877
+
878
+ Usage:
879
+
880
+ ```tsx
881
+ import {I18n} from '@enonic/nextjs-adapter';
882
+
883
+ const dict = I18n.getDictionary();
884
+ ```
885
+
886
+ [Response type](#dict-type)
887
+
888
+ <br/>
889
+
489
890
  ### Utility functions
490
891
 
491
- There is also a number of utility variables and functions available at `@enonic/nextjs-adapter`.
892
+ There is also a number of utility constants and functions available at `@enonic/nextjs-adapter`.
492
893
 
493
- ---
894
+ <br/>
494
895
 
495
896
  ```tsx
496
- IS_DEV_MODE; // True if current mode == development
897
+ import {CATCH_ALL} from './constants';
898
+
899
+ IS_DEV_MODE; // True if current mode == development
900
+
901
+ APP_NAME; // Name of the app defined in .env files
902
+
903
+ APP_NAME_UNDERSCORED; // APP_NAME with underscores instead of dots
904
+
905
+ APP_NAME_DASHED; // APP_NAME with dashes instead of dots
906
+
907
+ CATCH_ALL; // Catch all component name
908
+
909
+ PORTAL_COMPONENT_ATTRIBUTE; // Portal component attribute name
497
910
 
498
- APP_NAME; // Name of the app defined in .env files
911
+ PORTAL_REGION_ATTRIBUTE; // Portal region attribute name
499
912
 
500
- APP_NAME_UNDERSCORED; // APP_NAME with underscores instead of dots
913
+ JSESSIONID_HEADER; // JSESSIONID header name
501
914
 
502
- APP_NAME_DASHED; // APP_NAME with dashes instead of dots
915
+ PROJECT_ID_HEADER; // Project ID header name
503
916
 
504
- SITE_KEY; // Site key defined in .env files
917
+ RENDER_MODE_HEADER; // Render mode header name
505
918
 
506
- enum XP_REQUEST_TYPE {
919
+ XP_BASE_URL_HEADER; // XP base URL header name
920
+
921
+ enum XP_REQUEST_TYPE { // Enum for XP request types
507
922
  COMPONENT = 'component',
508
923
  TYPE = 'type',
509
924
  PAGE = 'page',
510
925
  }
511
926
 
512
- enum RENDER_MODE {
927
+ enum RENDER_MODE { // Enum for render modes
513
928
  INLINE = 'inline',
514
929
  EDIT = 'edit',
515
930
  PREVIEW = 'preview',
@@ -518,7 +933,7 @@ enum RENDER_MODE {
518
933
  NEXT = 'next',
519
934
  }
520
935
 
521
- enum XP_COMPONENT_TYPE {
936
+ enum XP_COMPONENT_TYPE { // Enum for XP component types
522
937
  PART = 'part',
523
938
  LAYOUT = 'layout',
524
939
  TEXT = 'text',
@@ -531,13 +946,16 @@ const sanitizeGraphqlName = (text: string) => string;
531
946
 
532
947
  // Returns common part of 2 strings
533
948
  const commonChars = (s1?: string, s2?: string) => string;
949
+
950
+ // Returns full content api URL with current project and branch appended
951
+ const getContentApiUrl = (context: Context) => string;
534
952
  ```
535
953
 
536
954
  ### Views
537
955
 
538
956
  They are located in `@enonic/nextjs-adapter/views` folder. Each view is a default export in the corresponding file.
539
957
 
540
- ---
958
+ <br/>
541
959
 
542
960
  #### `<MainView common="common" data="data" page="page" meta="meta">`
543
961
 
@@ -567,7 +985,7 @@ export async function getServerSideProps(context: Context) {
567
985
  export default MainView;
568
986
  ```
569
987
 
570
- ---
988
+ <br/>
571
989
 
572
990
  #### `<StaticContent condition="true" tag="div">`
573
991
 
@@ -586,7 +1004,7 @@ import StaticContent from '@enonic/nextjs-adapter/views/StaticContent';
586
1004
  <StaticContent condition={true} tag="div"> ...child elements... </StaticContent>
587
1005
  ```
588
1006
 
589
- ---
1007
+ <br/>
590
1008
 
591
1009
  #### <a id="rich-text-view"></a>`<RichTextView className="css-class" tag="section" data={data} meta={meta}, renderMacroInEditMode="true", customReplacer={customReplacerFn}>`
592
1010
 
@@ -612,7 +1030,7 @@ import RichTextView from '@enonic/nextjs-adapter/views/RichTextView';
612
1030
  <RichTextView data={richTextData} meta={meta} tag="section" className="rich-text-view" renderMacroInEditMode="false"></RichTextView>
613
1031
  ```
614
1032
 
615
- ---
1033
+ <br/>
616
1034
 
617
1035
  #### `<Regions page={page} meta={meta} name="main" common={common}>`
618
1036
 
@@ -636,19 +1054,21 @@ import StaticContent from '@enonic/nextjs-adapter/views/StaticContent';
636
1054
 
637
1055
  ## Known problems
638
1056
 
639
- ---
640
1057
 
641
1058
  In some cases, when using in NextJS application, a build errors related to the JSX may appear, that state the following:
1059
+
642
1060
  ```
643
1061
  You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
644
1062
  ```
1063
+
645
1064
  To prevent these errors, it is necessary to transpile the library using something
646
1065
  like [`next-transpile-modules`](https://www.npmjs.com/package/next-transpile-modules).
647
1066
  Install it as dev dependency and call it explicitly from you NextJS config:
648
1067
 
649
1068
  `next.config.js`
1069
+
650
1070
  ```js
651
1071
  const withTM = require('next-transpile-modules')(['@enonic/nextjs-adapter']);
652
1072
 
653
1073
  module.exports = withTM({});
654
- ```
1074
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enonic/nextjs-adapter",
3
- "version": "3.0.0-RC4",
3
+ "version": "3.0.0-RC5",
4
4
  "license": "Apache-2.0",
5
5
  "main": "index.js",
6
6
  "author": "Pavel Milkevich <pmi@enonic.com>",
@@ -53,7 +53,7 @@
53
53
  "@formatjs/intl-localematcher": "^0.5.4",
54
54
  "html-react-parser": "^5.1.10",
55
55
  "negotiator": "^0.6.3",
56
- "next": "^14.2.1",
56
+ "next": "^14.2.2",
57
57
  "react": "18.2.0",
58
58
  "react-dom": "18.2.0",
59
59
  "unescape": "^1.0.1"
@@ -66,10 +66,10 @@
66
66
  "@testing-library/react": "^15.0.2",
67
67
  "@types/negotiator": "^0.6.3",
68
68
  "@types/node": "^20.12.7",
69
- "@types/react": "^18.2.78",
69
+ "@types/react": "^18.2.79",
70
70
  "@types/react-dom": "^18.2.25",
71
- "@typescript-eslint/eslint-plugin": "^7.6.0",
72
- "@typescript-eslint/parser": "^7.6.0",
71
+ "@typescript-eslint/eslint-plugin": "^7.7.0",
72
+ "@typescript-eslint/parser": "^7.7.0",
73
73
  "concurrently": "^8.2.2",
74
74
  "cpy-cli": "^5.0.0",
75
75
  "del-cli": "^5.1.0",