@appsemble/lang-sdk 0.37.1 → 0.37.3

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/iterApp.js CHANGED
@@ -97,34 +97,43 @@ export function iterPage(page, callbacks, prefix = []) {
97
97
  if ('actions' in page) {
98
98
  result = Object.entries(page.actions ?? {}).some(([key, action]) => iterAction(action, callbacks, [...prefix, 'actions', key]));
99
99
  }
100
- return (result ||
101
- (page.type === 'flow'
102
- ? page.steps.some((step, index) => iterBlockList(step.blocks, callbacks, [...prefix, 'steps', index, 'blocks']))
103
- : page.tabs
104
- ? page.tabs.some((tab, index) => iterBlockList(tab.blocks, callbacks, [...prefix, 'tabs', index, 'blocks']))
105
- : iterBlockList(page.definition?.foreach.blocks ?? [], callbacks, [
106
- ...prefix,
107
- 'tabs',
108
- 0,
109
- 'blocks',
110
- ])));
100
+ if (result) {
101
+ return true;
102
+ }
103
+ if (page.type === 'flow') {
104
+ const { steps = [] } = page;
105
+ return steps.some((step, index) => iterBlockList(step.blocks ?? [], callbacks, [...prefix, 'steps', index, 'blocks']));
106
+ }
107
+ return page.tabs
108
+ ? page.tabs.some((tab, index) => iterBlockList(tab.blocks, callbacks, [...prefix, 'tabs', index, 'blocks']))
109
+ : iterBlockList(page.definition?.foreach.blocks ?? [], callbacks, [
110
+ ...prefix,
111
+ 'tabs',
112
+ 0,
113
+ 'blocks',
114
+ ]);
111
115
  }
112
116
  if (page.type === 'loop') {
113
117
  let result = false;
114
118
  if ('actions' in page) {
115
119
  result = Object.entries(page.actions ?? {}).some(([key, action]) => iterAction(action, callbacks, [...prefix, 'actions', key]));
116
120
  }
117
- return (result ||
118
- ['steps.first', 'steps', 'steps.last'].some((suffix) => iterBlockList(page.foreach.blocks, callbacks, [...prefix, suffix, 'blocks'])));
121
+ if (result) {
122
+ return true;
123
+ }
124
+ const { foreach } = page;
125
+ return ['steps.first', 'steps', 'steps.last'].some((suffix) => iterBlockList(foreach?.blocks ?? [], callbacks, [...prefix, suffix, 'blocks']));
119
126
  }
120
127
  if (page.type === 'container') {
121
128
  let result = false;
122
- for (const containerPage of page.pages) {
129
+ const { pages = [] } = page;
130
+ for (const containerPage of pages) {
123
131
  result = iterPage(containerPage, callbacks, prefix);
124
132
  }
125
133
  return result;
126
134
  }
127
- return iterBlockList(page.blocks, callbacks, [...prefix, 'blocks']);
135
+ const { blocks = [] } = page;
136
+ return iterBlockList(blocks, callbacks, [...prefix, 'blocks']);
128
137
  }
129
138
  /**
130
139
  * Iterate over an app definition and call each callback if relevant.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appsemble/lang-sdk",
3
- "version": "0.37.1",
3
+ "version": "0.37.3",
4
4
  "description": "Language SDK for Appsemble",
5
5
  "keywords": [
6
6
  "app",
@@ -49,11 +49,13 @@ If set to \`navigation\`, it will only be visible if \`login\` is also visible i
49
49
  `,
50
50
  },
51
51
  navigation: {
52
- enum: ['bottom', 'left-menu', 'hidden'],
52
+ enum: ['bottom', 'left-menu', 'hidden', 'top'],
53
53
  default: 'left-menu',
54
54
  description: `The navigation type to use.
55
55
 
56
56
  If this is omitted, a collapsable side navigation menu will be rendered on the left.
57
+ Top navigation is rendered in the title bar. When the title bar is hidden, top navigation is
58
+ rendered as side navigation.
57
59
  `,
58
60
  },
59
61
  logo: {
@@ -94,6 +96,14 @@ If this is omitted, a collapsable side navigation menu will be rendered on the l
94
96
  type: 'boolean',
95
97
  default: false,
96
98
  },
99
+ stackedHeader: {
100
+ description: `Whether to render the app logo on its own centered row above the navigation.
101
+
102
+ Only applies when \`navigation\` is set to \`top\`.
103
+ `,
104
+ type: 'boolean',
105
+ default: false,
106
+ },
97
107
  hideGroupDropdown: {
98
108
  description: `Whether to hide the group dropdown.
99
109
 
@@ -35,14 +35,15 @@ have two pages with the same name. The name of the page is displayed at the *app
35
35
  default: false,
36
36
  },
37
37
  navigation: {
38
- enum: ['bottom', 'left-menu', 'hidden', 'dropdown', 'profileDropdown'],
38
+ enum: ['bottom', 'left-menu', 'hidden', 'dropdown', 'profileDropdown', 'top'],
39
39
  description: `The type of navigation displayed on the page.
40
40
 
41
41
  This overrides the navigation property of the app itself. Defaults to \`left-menu\` if navigation or
42
42
  App navigation are not set.
43
43
 
44
- Set to \`bottom\` to use a navigation pane at the bottom of the screen instead of the default side
45
- menu. Set to \`hidden\` to display no navigational menus at all.
44
+ Set to \`bottom\` to use a navigation pane at the bottom of the screen. Set to \`top\` to render
45
+ navigation in the title bar. When the title bar is hidden, top navigation is rendered as side
46
+ navigation. Set to \`hidden\` to display no navigational menus at all.
46
47
  `,
47
48
  },
48
49
  icon: {
package/types/core.d.ts CHANGED
@@ -88,7 +88,9 @@ export interface AppDefinition {
88
88
  /**
89
89
  * The navigation type to use.
90
90
  *
91
- * If this is omitted, a collapsible side navigation menu will be rendered on the left.
91
+ * If this is omitted, a collapsible side navigation menu is rendered on the left.
92
+ * Top navigation is rendered in the title bar. When the title bar is hidden,
93
+ * top navigation is rendered as side navigation.
92
94
  *
93
95
  * @default 'left-menu'
94
96
  */
@@ -110,6 +112,12 @@ export interface AppDefinition {
110
112
  * Whether to hide the title bar from all pages in the app.
111
113
  */
112
114
  hideTitleBar?: boolean;
115
+ /**
116
+ * Whether to render the app logo on its own centered row above the top navigation.
117
+ *
118
+ * Only applies when `navigation` is set to `top`.
119
+ */
120
+ stackedHeader?: boolean;
113
121
  /**
114
122
  * Whether to hide the group dropdown.
115
123
  *
@@ -203,7 +211,8 @@ export interface BasePageDefinition {
203
211
  /**
204
212
  * The navigation type to use for the page.
205
213
  * Setting this will override the default navigation for the app.
206
- * if this is set to `navbar`, navigation link is rendered in the profile dropdown.
214
+ * Top navigation is rendered in the title bar. When the title bar is hidden,
215
+ * top navigation is rendered as side navigation.
207
216
  */
208
217
  navigation?: Navigation | 'profileDropdown';
209
218
  /**
package/types/layout.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export type Navigation = 'bottom' | 'hidden' | 'left-menu';
1
+ export type Navigation = 'bottom' | 'hidden' | 'left-menu' | 'top';
2
2
  export type LayoutPosition = 'hidden' | 'navbar' | 'navigation';
package/validation.js CHANGED
@@ -55,7 +55,10 @@ function validateJSONSchema(schema, prefix, report) {
55
55
  if (schema.type !== 'object') {
56
56
  return;
57
57
  }
58
- if (!('properties' in schema)) {
58
+ // An object that only defines `additionalProperties` (an open map, e.g. a
59
+ // dictionary of confidence scores) is a valid schema and does not need
60
+ // `properties`. Only require `properties` when there is no `additionalProperties`.
61
+ if (!('properties' in schema) && !schema.additionalProperties) {
59
62
  report(schema, 'is missing properties', prefix);
60
63
  return;
61
64
  }
@@ -69,6 +72,11 @@ function validateJSONSchema(schema, prefix, report) {
69
72
  for (const [key, propertySchema] of Object.entries(schema.properties ?? {})) {
70
73
  validateJSONSchema(propertySchema, [...prefix, 'properties', key], report);
71
74
  }
75
+ // Recurse into the `additionalProperties` sub schema so open maps are validated
76
+ // as thoroughly as `properties`. A boolean `additionalProperties` has no sub schema.
77
+ if (typeof schema.additionalProperties === 'object') {
78
+ validateJSONSchema(schema.additionalProperties, [...prefix, 'additionalProperties'], report);
79
+ }
72
80
  }
73
81
  /**
74
82
  * Validates the pages in the app definition to ensure there are no duplicate page names.