@valbuild/next 0.13.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/.babelrc.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "presets": [
3
+ [
4
+ "@babel/preset-react",
5
+ {
6
+ "runtime": "automatic"
7
+ }
8
+ ]
9
+ ]
10
+ }
package/CHANGELOG.md ADDED
File without changes
package/README.md ADDED
@@ -0,0 +1,503 @@
1
+ <p align="center">
2
+ <h1 align="center">Val</h1>
3
+ <p align="center">
4
+ ✨ <a href="https://app.val.build">https://app.val.build</a> ✨
5
+ <br/>
6
+ hard-coded content - super-charged
7
+ </p>
8
+ </p>
9
+
10
+ # 🐉 HERE BE DRAGONS 🐉
11
+
12
+ Val is PRE-ALPHA - MOST features are broken and in state of flux.
13
+
14
+ This is released only for **INTERNAL** **TESTING** PURPOSES.
15
+
16
+ ## Table of contents
17
+
18
+ - [Table of contents](#table-of-contents)
19
+ - [Introduction](#introduction)
20
+ - [Installation](#installation)
21
+ - [Getting started](#getting-started)
22
+ - [Concepts](#concepts)
23
+ - [String](#string)
24
+ - [Number](#number)
25
+ - [Boolean](#boolean)
26
+ - [Optional](#optional)
27
+ - [Array](#array)
28
+ - [Object](#object)
29
+ - [Rich text](#richtext)
30
+ - [Image](#image)
31
+ - [Internalization](#internalization)
32
+ - [Union](#union)
33
+ - [One-of references](#one-of-references)
34
+ - [Remote](#remote)
35
+ - [Selector](#selector)
36
+
37
+ ## Introduction
38
+
39
+ Val treats your content as code, but it remains fully editable.
40
+
41
+ Val is built on top of TypeScript and Git, letting you use types, branches, version control (even rollbacks!) seamlessly.
42
+
43
+ - Val is **TypeSafe**: being TypeScript-first means you see errors as you type. In addition you can **refactor**, find references and auto-complete content - just as if it was hard-coded. Safety means no more "add-only" content models, where your content model continues to expand because you hesitate to remove anything.
44
+
45
+ - Version **control**: content is tied to commits, which means you can use branches and reverts just as you would normally do.
46
+
47
+ - Val is **isomorphic**: if your content scales beyond your code base, Val lets you easily make it remote. Just add `.remote()` to your schema and Val will host your content - your components stays the same. Remote content are handled using immutable references, so remote content are tied to Git commits - rollbacks, branches works as before.
48
+
49
+ - Contextual editing: Val is built from the ground up to support contextual editing. Editors can see Val content in the context of the app, and make edits directly there.
50
+
51
+ - Full CMS: even hard-coded content has its drawbacks: i18n, images, rich text - Val supports all of these.
52
+
53
+ - No signup required: **your** content is yours. Local development requires no sign ups and is free. When you are ready and editors needs access, you can sign up and without any changes to your code base. Head over to [https://app.val.build](https://app.val.build) to get started 🚀.
54
+
55
+ ## Installation
56
+
57
+ - Make sure you have TypeScript 4.9+, Next 12+ (other meta frameworks will come), React 18+ (other frontend frameworks will come)
58
+ - Install the packages:
59
+
60
+ ```sh
61
+ npm install @valbuild/next
62
+ ```
63
+
64
+ - Create your val.config.ts file. NOTE: this file should be in the same directory as `tsconfig.json`:
65
+
66
+ ```ts
67
+ // ./val.config.ts
68
+
69
+ import { initVal } from "@valbuild/next";
70
+
71
+ const { s, val } = initVal();
72
+
73
+ export { s, val };
74
+ ```
75
+
76
+ - Enable contextual editing: setup Val endpoints
77
+
78
+ ```ts
79
+ // ./src/pages/api/val/[...val].ts
80
+
81
+ import { valEditHandler } from "../../../../val.config";
82
+ import { NextApiHandler } from "next";
83
+
84
+ const handler: NextApiHandler = valEditHandler;
85
+
86
+ export default handler;
87
+
88
+ export const config = {
89
+ api: {
90
+ bodyParser: false,
91
+ externalResolver: true,
92
+ },
93
+ };
94
+ ```
95
+
96
+ - Enable contextual editing: Use the Val provider in the \_app file:
97
+
98
+ ```tsx
99
+ // ./src/pages/_app.tsx
100
+
101
+ import { ValProvider } from "@valbuild/react";
102
+ import type { AppProps } from "next/app";
103
+
104
+ function MyApp({ Component, pageProps }: AppProps) {
105
+ return (
106
+ <ValProvider host="/api/val">
107
+ <Component {...pageProps} />
108
+ </ValProvider>
109
+ );
110
+ }
111
+
112
+ export default MyApp;
113
+ ```
114
+
115
+ ## Getting started
116
+
117
+ ### Create your first Val content file
118
+
119
+ Content defined in Val is always defined `.val.{ts|js}` files.
120
+
121
+ They must export a default `val.content` where the first argument equals the path of the file relative to the `val.config.{js|ts}` file.
122
+
123
+ ```ts
124
+ // ./src/content/example/blogs.val.ts
125
+
126
+ import { s, val } from "../../../val.config";
127
+
128
+ export default val.content(
129
+ "/src/content/example/blogs", // <- NOTE: this must be the same path as the file
130
+ s.array(s.object({ title: s.string(), text: s.string() })),
131
+ [
132
+ {
133
+ title: "Title 1",
134
+ text: "Text 1",
135
+ },
136
+ {
137
+ title: "Title 2",
138
+ text: "Text 2",
139
+ },
140
+ ]
141
+ );
142
+ ```
143
+
144
+ ### Use your content
145
+
146
+ ```tsx
147
+ // ./src/pages/example/index.tsx
148
+
149
+ import { NextPage } from "next";
150
+ import { useVal } from "@valbuild/react";
151
+ import blogsVal from "@/content/example/blogs.val";
152
+
153
+ const Blog: NextPage = () => {
154
+ const blog = useVal(blogsVal[0]);
155
+ return (
156
+ <main>
157
+ <article>
158
+ <section>
159
+ <h1>{blog.title}</h1>
160
+ <p>{blog.text}</p>
161
+ </section>
162
+ </article>
163
+ </main>
164
+ );
165
+ };
166
+
167
+ export default Blog;
168
+ ```
169
+
170
+ ## Concepts
171
+
172
+ `.val.{ts|js}` files **MUST** have a default export which is a ValModule. A ValModule is a special type of [Selector](#selectors). Selectors makes it possible to select a subset of content from a ValModule or a another Selector.
173
+
174
+ Selectors can be turned to Val types using `useVal` or `fetchVal`.
175
+
176
+ ### .val files
177
+
178
+ `.val.{ts|js}` files are the files in which you store your content.
179
+
180
+ They are evaluated when the content is run, therefore they have a specific set of requirements. They must have a default export that is `val.content`, they must have a `export const schema` with the Schema and they CANNOT import anything other than `val.config` and `@valbuild/core`.
181
+
182
+ Example:
183
+
184
+ ```ts
185
+ import { s, val } from "../val.config";
186
+
187
+ export const schema = t.string();
188
+
189
+ export default val.content(
190
+ "/file/path/relative/to/val/config",
191
+ schema,
192
+ "My string content"
193
+ );
194
+ ```
195
+
196
+ NOTE: IN THE FUTURE, they will be validated by the eslint-plugin.
197
+
198
+ ## String
199
+
200
+ ```ts
201
+ import { s } from "./val.config";
202
+
203
+ s.string(); // <- Schema<string>
204
+ ```
205
+
206
+ ### String selectors
207
+
208
+ See [Selectors](#selector) for more info.
209
+
210
+ ### String `.eq`
211
+
212
+ ```ts
213
+ useVal(stringVal.eq("")); // <- Val<boolean>
214
+ ```
215
+
216
+ ## Number
217
+
218
+ ```ts
219
+ import { s } from "./val.config";
220
+
221
+ s.number(); // <- Schema<number>
222
+ ```
223
+
224
+ ### Number selectors
225
+
226
+ See [Selectors](#selector) for more info.
227
+
228
+ ### Number `.eq`
229
+
230
+ ```ts
231
+ useVal(numberVal.eq(2)); // <- Val<boolean>
232
+ ```
233
+
234
+ ## Boolean
235
+
236
+ ```ts
237
+ import { s } from "./val.config";
238
+
239
+ s.boolean(); // <- Schema<boolean>
240
+ ```
241
+
242
+ ### Boolean selectors
243
+
244
+ See [Selectors](#selector) for more info.
245
+
246
+ ### Boolean `.eq`
247
+
248
+ ```ts
249
+ useVal(booleanVal.eq(true)); // <- Val<boolean>
250
+ ```
251
+
252
+ ## Optional
253
+
254
+ All schema types can be optional. An optional schema creates a union of the type and `null`.
255
+
256
+ ```ts
257
+ import { s } from "./val.config";
258
+
259
+ s.string().optional(); // <- Schema<string | null>
260
+ ```
261
+
262
+ ### Selectors
263
+
264
+ ### Accessing the underlying type: `.andThen`
265
+
266
+ To use and optional val, you can use the [.andThen](#andthen) selector.
267
+
268
+ ## Array
269
+
270
+ ```ts
271
+ s.array(t.string());
272
+ ```
273
+
274
+ ### Selecting arrays
275
+
276
+ ### `.filter`
277
+
278
+ TODO: text
279
+
280
+ ```ts
281
+ useVal(myArray.filter((item) => item.title.eq("Title 1")));
282
+ ```
283
+
284
+ ### `.map`
285
+
286
+ TODO:
287
+
288
+ ```ts
289
+ useVal(myArray.map((item) => ({ test: item.title })));
290
+ ```
291
+
292
+ ## Object
293
+
294
+ ```ts
295
+ s.object({
296
+ myProperty: s.string(),
297
+ });
298
+ ```
299
+
300
+ ### Selecting objects
301
+
302
+ You can select Selector objects almost as if they were normal objects. The exception is that you cannot use the spread (`...`) operator.
303
+
304
+ Example:
305
+
306
+ ```ts
307
+ useVal({ foo: myObjectVal.hello });
308
+ ```
309
+
310
+ ## RichText
311
+
312
+ ### RichText Schema
313
+
314
+ ```ts
315
+ import { s } from "./val.config";
316
+
317
+ s.richtext();
318
+ ```
319
+
320
+ ### Initializing RichText content
321
+
322
+ To initialize some text content using a RichText schema, you can use follow the example below:
323
+
324
+ ```ts
325
+ import { s, val } from "./val.config";
326
+
327
+ // TODO: need some other way of doing this:
328
+ export default val.content("/example/richtext.ts", s.richtext(), {
329
+ children: [
330
+ {
331
+ type: "paragraph",
332
+ version: 1,
333
+ indent: 0,
334
+ direction: "ltr",
335
+ format: "",
336
+ children: [
337
+ {
338
+ type: "text",
339
+ version: 1,
340
+ mode: "normal",
341
+ format: 0,
342
+ detail: 0,
343
+ style: "",
344
+ text: "TODO: update me",
345
+ },
346
+ ],
347
+ },
348
+ ],
349
+ direction: "ltr",
350
+ format: "",
351
+ indent: 0,
352
+ type: "root",
353
+ version: 1,
354
+ });
355
+ ```
356
+
357
+ ### Render RichText
358
+
359
+ You can use the `ValRichText` component to render content.
360
+
361
+ ```tsx
362
+ "use client";
363
+ import { useVal, ValRichText } from "@valbuild/react";
364
+ import richtextVal from "./richtext";
365
+
366
+ export default function Page() {
367
+ const richtext = useVal(richtextVal);
368
+ return <ValRichText>{richtext}</ValRichText>;
369
+ }
370
+ ```
371
+
372
+ ## Image
373
+
374
+ ### Schema
375
+
376
+ ```ts
377
+ s.image();
378
+ ```
379
+
380
+ ### Initializing image content
381
+
382
+ Local images must be stored under the `.public` folder.
383
+
384
+ ```ts
385
+ import { s, val } from "../val.config";
386
+
387
+ export const schema = s.image();
388
+
389
+ export default val.content("/image", schema, val.file("/public/myfile.jpg"));
390
+ ```
391
+
392
+ NOTE: This will not validate, since images requires `width`, `height` and a `sha256` checksum. You can fix this validation in the UI by opening the image and clicking the Fix button.
393
+
394
+ ### Using images in components
395
+
396
+ Images are transformed to object that have a `url` property which can be used to render them.
397
+
398
+ Example:
399
+
400
+ ```tsx
401
+ // in a Functional Component
402
+ const image = useVal(imageVal);
403
+
404
+ return <img src={image.url} />;
405
+ ```
406
+
407
+ ## Internalization
408
+
409
+ **NOTE**: WORKS ONLY ON THE TYPE LEVEL
410
+
411
+ To enable i18n, you must update your Val with the locales you want to enforce.
412
+
413
+ Example:
414
+
415
+ ```ts
416
+ // ./val.config.ts
417
+
418
+ import { initVal } from "@valbuild/core";
419
+
420
+ const { s, val } = initVal({
421
+ locales: {
422
+ required: ["en_US", "fr_FR"],
423
+ fallback: "en_US",
424
+ },
425
+ });
426
+
427
+ export { s, val };
428
+ ```
429
+
430
+ ## Union
431
+
432
+ **NOTE**: WORKS ONLY ON THE TYPE LEVEL
433
+
434
+ TODO: fill in.
435
+
436
+ ```ts
437
+ s.union(
438
+ "type",
439
+ s.object({ type: s.literal("type1"), bar: s.string() }),
440
+ s.object({ type: s.literal("type2"), foo: s.number() })
441
+ );
442
+ ```
443
+
444
+ ### Selecting unions
445
+
446
+ ### `.fold`
447
+
448
+ TODO: description
449
+
450
+ ```ts
451
+ useVal(myUnionVal.fold("type")({
452
+
453
+ })
454
+ ```
455
+
456
+ ## One of references
457
+
458
+ **NOTE**: Currently not possible to change from UI
459
+
460
+ ```ts
461
+
462
+ ```
463
+
464
+ # Remote
465
+
466
+ **NOTE**: WORKS ONLY ON THE TYPE LEVEL
467
+
468
+ All schemas can be converted into `.remote`.
469
+
470
+ TODO: add description.
471
+
472
+ Example:
473
+
474
+ ```ts
475
+ export const schema = s.object({ stuff: s.string() });
476
+
477
+ export default val.content("/remote/example", schema, val.remote("REFERENCE"));
478
+ ```
479
+
480
+ ## Selector
481
+
482
+ To select parts of a your content you should use Selectors.
483
+ If you make the content `.remote`
484
+
485
+ ### `.andThen`
486
+
487
+ All selectors can use `andThen` method which is similar to the `&&` operator. You can use this to only do operations on optionals that are defined. NOTE: only TRUTHY arguments are passed in to `andThen` (i.e. the empty string, `''` is NOT truthy).
488
+
489
+ Given the example schema:
490
+
491
+ ```ts
492
+ // ./maybeArray.val.ts
493
+ //...
494
+
495
+ export const schema = t.array(t.string()).optional();
496
+
497
+ //...
498
+ ```
499
+
500
+ ```ts
501
+ import maybeArrayVal from "./maybeArray.val";
502
+ useVal(maybeArrayVal.andThen((array) => array.filter((v) => v.eq("foo"))));
503
+ ```
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ import { RichText } from "@valbuild/core";
3
+ export declare function ValRichText({ children }: {
4
+ children: RichText;
5
+ }): JSX.Element;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { SelectorSource, SelectorOf, GenericSelector } from "@valbuild/core";
2
+ import { StegaOfSource } from "./stegaEncode";
3
+ export declare function fetchVal<T extends SelectorSource>(selector: T, locale?: string): SelectorOf<T> extends GenericSelector<infer S> ? Promise<StegaOfSource<S>> : never;
@@ -0,0 +1,3 @@
1
+ import { GenericSelector, SelectorOf, SelectorSource } from "@valbuild/core";
2
+ import { StegaOfSource } from "../stegaEncode";
3
+ export declare function useVal<T extends SelectorSource>(selector: T, locale?: string): SelectorOf<T> extends GenericSelector<infer S> ? StegaOfSource<S> : never;
@@ -0,0 +1,7 @@
1
+ import "./autoTagJSX";
2
+ export { ValProvider } from "@valbuild/react";
3
+ export { useVal } from "./hooks/useVal";
4
+ export { type ValEncodedString } from "./stegaEncode";
5
+ export * from "@valbuild/core";
6
+ export { fetchVal } from "./fetchVal";
7
+ export { ValRichText } from "./ValRichText";
@@ -0,0 +1,24 @@
1
+ import { Json, Val, RichTextSource, RichText } from "@valbuild/core";
2
+ import { FileSource, RemoteSource, Source, SourceObject } from "@valbuild/core";
3
+ import { JsonPrimitive } from "@valbuild/core/src/Json";
4
+ import { SourceArray } from "@valbuild/core/src/source";
5
+ import { I18nSource } from "@valbuild/core/src/source/i18n";
6
+ declare const brand: unique symbol;
7
+ /**
8
+ * ValEncodedString is a string that is encoded using steganography.
9
+ *
10
+ * This means that there is a hidden / non-visible object embedded in the string.
11
+ * This object includes a path, which is used to automatically tag
12
+ * where the content comes from for contextual editing.
13
+ *
14
+ */
15
+ export type ValEncodedString = string & {
16
+ [brand]: "ValEncodedString";
17
+ };
18
+ export type StegaOfSource<T extends Source> = Json extends T ? Json : T extends I18nSource<readonly string[], infer U> ? StegaOfSource<U> : T extends RemoteSource<infer U> ? StegaOfSource<U> : T extends RichTextSource ? RichText : T extends FileSource ? {
19
+ url: ValEncodedString;
20
+ } : T extends SourceObject ? {
21
+ [key in keyof T]: StegaOfSource<T[key]>;
22
+ } : T extends SourceArray ? StegaOfSource<T[number]>[] : T extends string ? ValEncodedString : T extends JsonPrimitive ? T : never;
23
+ export declare function stegaEncodeVal<T extends Json>(val: Val<T>): T;
24
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./declarations/src/index";
2
+ //# sourceMappingURL=valbuild-next.cjs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valbuild-next.cjs.d.ts","sourceRoot":"","sources":["./declarations/src/index.d.ts"],"names":[],"mappings":"AAAA"}