@json-layout/core 0.10.0 → 0.12.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@json-layout/core",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Compilation and state management utilities for JSON Layout.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -59,7 +59,7 @@
59
59
  },
60
60
  "homepage": "https://github.com/json-layout/json-layout#readme",
61
61
  "dependencies": {
62
- "@json-layout/vocabulary": "^0.10.0",
62
+ "@json-layout/vocabulary": "^0.12.0",
63
63
  "@types/markdown-it": "^13.0.1",
64
64
  "ajv": "^8.12.0",
65
65
  "ajv-errors": "^3.0.0",
@@ -6,6 +6,7 @@ import addFormats from 'ajv-formats'
6
6
  import ajvErrors from 'ajv-errors'
7
7
  import ajvLocalizeModule from 'ajv-i18n'
8
8
  import MarkdownIt from 'markdown-it'
9
+ import { produce } from 'immer'
9
10
  import i18n from '../i18n/index.js'
10
11
  import { makeSkeletonTree } from './skeleton-tree.js'
11
12
  import { resolveRefs } from './utils/resolve-refs.js'
@@ -29,6 +30,17 @@ const ajvLocalize = /** @type {typeof ajvLocalizeModule.default} */ (ajvLocalize
29
30
 
30
31
  // const exprEvalParser = new ExprEvalParser()
31
32
 
33
+ // use Immer for efficient updating with immutability and no-op detection
34
+ /** @type {(draft: PartialCompileOptions, newOptions: PartialCompileOptions) => PartialCompileOptions} */
35
+ export const produceCompileOptions = produce((draft, newOptions) => {
36
+ for (const key of ['ajv', 'ajvOptions', 'code', 'markdown', 'markdownItOptions', 'locale', 'messages', 'optionsKeys']) {
37
+ // @ts-ignore
38
+ if (key in newOptions) draft[key] = newOptions[key]
39
+ // @ts-ignore
40
+ else delete draft[key]
41
+ }
42
+ })
43
+
32
44
  /**
33
45
  * @param {PartialCompileOptions} partialOptions
34
46
  * @returns {CompileOptions}
@@ -1,5 +1,5 @@
1
1
  // import Debug from 'debug'
2
- import { normalizeLayoutFragment, isSwitchStruct, isGetItemsExpression, isGetItemsFetch, isItemsLayout } from '@json-layout/vocabulary'
2
+ import { normalizeLayoutFragment, isSwitchStruct, isGetItemsExpression, isGetItemsFetch, isItemsLayout, getSchemaFragmentType } from '@json-layout/vocabulary'
3
3
  import { makeSkeletonTree } from './skeleton-tree.js'
4
4
 
5
5
  /**
@@ -27,8 +27,7 @@ export function makeSkeletonNode (
27
27
  parentPointer,
28
28
  required
29
29
  ) {
30
- // consolidate schema
31
- if (!schema.type && schema.properties) schema.type = 'object'
30
+ const { type, nullable } = getSchemaFragmentType(schema)
32
31
 
33
32
  // improve on ajv error messages based on ajv-errors (https://ajv.js.org/packages/ajv-errors.html)
34
33
  schema.errorMessage = schema.errorMessage ?? {}
@@ -49,8 +48,9 @@ export function makeSkeletonNode (
49
48
  let defaultData
50
49
  if ('default' in schema) defaultData = schema.default
51
50
  else if (required) {
52
- if (schema.type === 'object') defaultData = {}
53
- if (schema.type === 'array') defaultData = []
51
+ if (nullable) defaultData = null
52
+ else if (type === 'object') defaultData = {}
53
+ else if (type === 'array') defaultData = []
54
54
  }
55
55
 
56
56
  let pure = true
@@ -103,7 +103,7 @@ export function makeSkeletonNode (
103
103
 
104
104
  /** @type {import('./types.js').SkeletonNode} */
105
105
  const node = { key: key ?? '', pointer, parentPointer, pure, propertyKeys: [], roPropertyKeys: [] }
106
- if (schema.type === 'object') {
106
+ if (type === 'object') {
107
107
  if (schema.properties) {
108
108
  node.children = node.children ?? []
109
109
  for (const propertyKey of Object.keys(schema.properties)) {
@@ -166,7 +166,7 @@ export function makeSkeletonNode (
166
166
  const childrenTrees = []
167
167
  /** @type {string[]} */
168
168
  for (let i = 0; i < schema.oneOf.length; i++) {
169
- if (!schema.oneOf[i].type) schema.oneOf[i].type = schema.type
169
+ if (!schema.oneOf[i].type) schema.oneOf[i].type = type
170
170
  const title = schema.oneOf[i].title ?? `option ${i}`
171
171
  delete schema.oneOf[i].title
172
172
  childrenTrees.push(makeSkeletonTree(
@@ -195,7 +195,7 @@ export function makeSkeletonNode (
195
195
  }
196
196
  }
197
197
 
198
- if (schema.type === 'array' && schema.items) {
198
+ if (type === 'array' && schema.items) {
199
199
  if (Array.isArray(schema.items)) {
200
200
  node.children = schema.items.map((/** @type {any} */ itemSchema, /** @type {number} */ i) => {
201
201
  return makeSkeletonNode(
@@ -5,7 +5,7 @@ import { produce } from 'immer'
5
5
  import { evalExpression, producePatchedData } from './state-node.js'
6
6
  import { createStateTree } from './state-tree.js'
7
7
  import { Display } from './utils/display.js'
8
- import { isFileLayout, isGetItemsExpression, isGetItemsFetch, isItemsLayout } from '@json-layout/vocabulary'
8
+ import { isFileLayout, isGetItemsExpression, isGetItemsFetch, isItemsLayout, editableCompNames } from '@json-layout/vocabulary'
9
9
  import { shallowProduceArray } from './utils/immutable.js'
10
10
 
11
11
  export { Display } from './utils/display.js'
@@ -74,6 +74,7 @@ function fillOptions (partialOptions, compiledLayout) {
74
74
  removeAdditional: 'error',
75
75
  autofocus: false,
76
76
  readOnlyPropertiesMode: 'show',
77
+ debounceInputMs: 300,
77
78
  ...partialOptions,
78
79
  messages
79
80
  }
@@ -342,11 +343,12 @@ export class StatefulLayout {
342
343
  }
343
344
 
344
345
  /**
346
+ * @private
345
347
  * @param {StateNode} node
346
348
  * @param {unknown} data
347
349
  * @param {number} [activateKey]
348
350
  */
349
- input (node, data, activateKey) {
351
+ applyInput (node, data, activateKey) {
350
352
  logDataBinding('received input event from node', node, data)
351
353
 
352
354
  const transformedData = node.layout.transformData && this.evalNodeExpression(node, node.layout.transformData, data)
@@ -370,7 +372,10 @@ export class StatefulLayout {
370
372
  data = transformedData
371
373
  }
372
374
 
373
- if (node.options.validateOn === 'input' && !this.validationState.validatedChildren.includes(node.fullKey)) {
375
+ if (
376
+ (node.options.validateOn === 'input' || (node.options.validateOne === 'blur' && !editableCompNames.includes(node.layout.comp))) &&
377
+ !this.validationState.validatedChildren.includes(node.fullKey)
378
+ ) {
374
379
  this.validationState = { validatedChildren: this.validationState.validatedChildren.concat([node.fullKey]) }
375
380
  }
376
381
  if (activateKey !== undefined) {
@@ -385,17 +390,54 @@ export class StatefulLayout {
385
390
  const parentNode = this._lastCreateStateTreeContext.nodes.find(p => p.fullKey === node.parentFullKey)
386
391
  if (!parentNode) throw new Error(`parent with key "${node.parentFullKey}" not found`)
387
392
  const newParentValue = producePatchedData(parentNode.data ?? (typeof node.key === 'number' ? [] : {}), node, data)
388
- this.input(parentNode, newParentValue)
393
+ this.applyInput(parentNode, newParentValue)
389
394
 
390
395
  if (activateKey !== undefined) {
391
396
  this.handleAutofocus()
392
397
  }
393
398
  }
394
399
 
400
+ /**
401
+ * @private
402
+ * @type {null | [StateNode, unknown, number | undefined, ReturnType<typeof setTimeout>]}
403
+ */
404
+ debouncedInput = null
405
+
406
+ applyDebouncedInput () {
407
+ if (this.debouncedInput) {
408
+ clearTimeout(this.debouncedInput[3])
409
+ this.applyInput(this.debouncedInput[0], this.debouncedInput[1], this.debouncedInput[2])
410
+ this.debouncedInput = null
411
+ }
412
+ }
413
+
414
+ /**
415
+ * @param {StateNode} node
416
+ * @param {unknown} data
417
+ * @param {number} [activateKey]
418
+ */
419
+ input (node, data, activateKey) {
420
+ // debounced data from the same node is cancelled if a new input is received
421
+ // debounced data from another node is applied immediately
422
+ if (this.debouncedInput) {
423
+ if (this.debouncedInput[0] === node) clearTimeout(this.debouncedInput[3])
424
+ else this.applyDebouncedInput()
425
+ }
426
+
427
+ if (editableCompNames.includes(node.layout.comp) && node.options.debounceInputMs) {
428
+ this.debouncedInput = [node, data, activateKey, setTimeout(() => this.applyDebouncedInput(), node.options.debounceInputMs)]
429
+ } else {
430
+ this.applyInput(node, data, activateKey)
431
+ }
432
+ }
433
+
395
434
  /**
396
435
  * @param {StateNode} node
397
436
  */
398
437
  blur (node) {
438
+ // debounced data is applied immediately on blur
439
+ this.applyDebouncedInput()
440
+
399
441
  logDataBinding('received blur event from node', node)
400
442
  if (
401
443
  (node.options.validateOn === 'input' || node.options.validateOn === 'blur') &&
@@ -123,5 +123,10 @@ export const runtimeOptions = [
123
123
  hide: 'Hide the readOnly properties but keep them in the data.',
124
124
  show: 'Show the readOnly properties.'
125
125
  }
126
+ },
127
+ {
128
+ key: 'debounceInputMs',
129
+ description: 'The debounce time for the input event of editable fields.',
130
+ default: 300
126
131
  }
127
132
  ]
@@ -5,6 +5,8 @@
5
5
  */
6
6
  export function compile(_schema: object, partialOptions?: import("./types.js").PartialCompileOptions | undefined): CompiledLayout;
7
7
  export { resolveRefs } from "./utils/resolve-refs.js";
8
+ /** @type {(draft: PartialCompileOptions, newOptions: PartialCompileOptions) => PartialCompileOptions} */
9
+ export const produceCompileOptions: (draft: PartialCompileOptions, newOptions: PartialCompileOptions) => PartialCompileOptions;
8
10
  export type SkeletonTree = import('./types.js').SkeletonTree;
9
11
  export type SkeletonNode = import('./types.js').SkeletonNode;
10
12
  export type CompiledLayout = import('./types.js').CompiledLayout;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compile/index.js"],"names":[],"mappings":"AAsEA;;;;GAIG;AACH,iCAJW,MAAM,4EAEJ,cAAc,CA6E1B;;2BAtIY,OAAO,YAAY,EAAE,YAAY;2BACjC,OAAO,YAAY,EAAE,YAAY;6BACjC,OAAO,YAAY,EAAE,cAAc;6BACnC,OAAO,YAAY,EAAE,cAAc;oCACnC,OAAO,YAAY,EAAE,qBAAqB;iCAC1C,OAAO,YAAY,EAAE,kBAAkB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compile/index.js"],"names":[],"mappings":"AAkFA;;;;GAIG;AACH,iCAJW,MAAM,4EAEJ,cAAc,CA6E1B;;AAjID,yGAAyG;AACzG,4CADmB,qBAAqB,cAAc,qBAAqB,KAAK,qBAAqB,CAQnG;2BAxBW,OAAO,YAAY,EAAE,YAAY;2BACjC,OAAO,YAAY,EAAE,YAAY;6BACjC,OAAO,YAAY,EAAE,cAAc;6BACnC,OAAO,YAAY,EAAE,cAAc;oCACnC,OAAO,YAAY,EAAE,qBAAqB;iCAC1C,OAAO,YAAY,EAAE,kBAAkB"}
@@ -167,6 +167,19 @@ export class StatefulLayout {
167
167
  * @returns {any}
168
168
  */
169
169
  private evalNodeExpression;
170
+ /**
171
+ * @private
172
+ * @param {StateNode} node
173
+ * @param {unknown} data
174
+ * @param {number} [activateKey]
175
+ */
176
+ private applyInput;
177
+ /**
178
+ * @private
179
+ * @type {null | [StateNode, unknown, number | undefined, ReturnType<typeof setTimeout>]}
180
+ */
181
+ private debouncedInput;
182
+ applyDebouncedInput(): void;
170
183
  /**
171
184
  * @param {StateNode} node
172
185
  * @param {unknown} data
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.js"],"names":[],"mappings":";AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,mEAAmE;AACnE,+BADkB,SAAS,GAAG,SAAS,8CACoC;AAE3E,oGAAoG;AACpG,iCADkB,SAAS,GAAG,SAAS,yHACkC;AAmCzE;IAoHE;;;;;OAKG;IACH,4BALW,OAAO,aAAa,EAAE,cAAc,gBACpC,OAAO,aAAa,EAAE,YAAY,WAClC,QAAQ,qBAAqB,CAAC,SAC9B,OAAO,EAejB;IAtID;;;OAGG;IACH,iBAFU,OAAO,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAEhD;IAEN;;;;OAIG;IACH,iCAAe;IACf,mEAAqD;IAErD;;;OAGG;IAEH,mBAAU;IACV,gDAA2C;IAE3C;;;OAGG;IACH,uBAFU,OAAO,aAAa,EAAE,YAAY,CAEhC;IAEZ;;;OAGG;IAEH,iBAAQ;IACR,uBAAuC;IAEvC;;;OAGG;IAEH,yBAAgB;IAQhB;;;OAGG;IACH,+DAOC;IAlBD;;OAEG;IACH,4DAEC;IAeD;;;OAGG;IAEH,iBAAQ;IAKR;;OAEG;IACH,6DAGC;IAVD;;OAEG;IACH,0DAAuC;IASvC;;;OAGG;IACH,cAAK;IAEL,uBAIC;IALD,oBAAiC;IAOjC;;;OAGG;IAEH,oCAA2B;IAE3B;;;OAGG;IACH,yBAAgB;IAChB;;;OAGG;IACH,iCAAwB;IAExB;;OAEG;IACH,OAFU,OAAO,EAAE,CAET;IAoVV;;OAEG;IACH,aAFU,OAAO,MAAM,EAAE,MAAM,CAAC,CAErB;IAhUX;;;OAGG;IACH,uBAGC;IAED;;OAEG;IACH,4BAOC;IAED;;OAEG;IACH,oBAiBC;IAED;;;OAGG;IACH,wBAgCC;IAED,iBAEC;IAED,wBAGC;IAED;;OAEG;IACH,qBAEC;IAED;;OAEG;IACH,uBAEC;IAED;;OAEG;IACH,8BAEC;IAED;;;;;;OAMG;IACH,2BAKC;IAED;;;;;OAKG;IACH,mBA+CC;IAED;;;OAGG;IACH,uBAAqB;IAErB,4BAMC;IAED;;;;OAIG;IACH,YAJW,SAAS,QACT,OAAO,0CAgBjB;IAED;;OAEG;IACH,WAFW,SAAS,QAanB;IAED;;OAEG;IACH,0BAFW,SAAS,QASnB;IAED;;;;;OAKG;IACH,uBAwDC;IAED;;;;OAIG;IACH,eAJW,SAAS,MACT,MAAM,GACJ,QAAQ,OAAO,yBAAyB,EAAE,WAAW,CAAC,CAMlE;IAOD;;;OAGG;IACH,mBAHW,SAAS,OACT,MAAM,QAWhB;IAED;;OAEG;IACH,qBAFW,SAAS,QAKnB;IAED,wBASC;CACF;wBAjjBY,OAAO,YAAY,EAAE,SAAS;wBAC9B,OAAO,YAAY,EAAE,SAAS;oCAC9B,OAAO,YAAY,EAAE,qBAAqB;mCAC1C,OAAO,YAAY,EAAE,oBAAoB;qCACzC,OAAO,YAAY,EAAE,sBAAsB;4BAC3C,OAAO,YAAY,EAAE,aAAa;2BAClC,OAAO,YAAY,EAAE,YAAY;8BACjC,OAAO,YAAY,EAAE,eAAe;yBACpC,OAAO,YAAY,EAAE,UAAU;0BAC/B,OAAO,YAAY,EAAE,WAAW;yBAChC,OAAO,YAAY,EAAE,UAAU;+BAC/B,OAAO,YAAY,EAAE,gBAAgB;2BACrC,OAAO,YAAY,EAAE,YAAY;2BACjC,OAAO,YAAY,EAAE,YAAY;yBACjC,OAAO,YAAY,EAAE,UAAU;8BAC/B,OAAO,YAAY,EAAE,eAAe;6BACpC,OAAO,YAAY,EAAE,cAAc;iCACnC,OAAO,YAAY,EAAE,kBAAkB;6BACvC,OAAO,YAAY,EAAE,cAAc;kCACnC,OAAO,YAAY,EAAE,mBAAmB;uBACxC,OAAO,YAAY,EAAE,QAAQ;+BAC7B,OAAO,YAAY,EAAE,gBAAgB;0BACrC,OAAO,YAAY,EAAE,WAAW;8BAChC,OAAO,YAAY,EAAE,eAAe;uBACpC,OAAO,YAAY,EAAE,QAAQ;4BAC7B,OAAO,YAAY,EAAE,aAAa;2BAClC,OAAO,YAAY,EAAE,YAAY;sBACjC,OAAO,YAAY,EAAE,OAAO;wBAlCjB,oBAAoB"}
@@ -1 +1 @@
1
- {"version":3,"file":"doc-options.d.ts","sourceRoot":"","sources":["../../src/utils/doc-options.js"],"names":[],"mappings":"AAEA;;GAEG;AAEH,yBAAyB;AACzB,wCA8BC;AAED,yBAAyB;AACzB,wCAsFC;yBA3HY;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,MAAM,EAAE,GAAG,CAAC,CAAA;CAAC,EAAE"}
1
+ {"version":3,"file":"doc-options.d.ts","sourceRoot":"","sources":["../../src/utils/doc-options.js"],"names":[],"mappings":"AAEA;;GAEG;AAEH,yBAAyB;AACzB,wCA8BC;AAED,yBAAyB;AACzB,wCA2FC;yBAhIY;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,MAAM,EAAE,GAAG,CAAC,CAAA;CAAC,EAAE"}