@kubex/zinc 1.1.28 → 1.1.29

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 (46) hide show
  1. package/custom-elements-manifest.config.js +2 -2
  2. package/dist/custom-elements.json +1483 -17
  3. package/dist/vscode.html-custom-data.json +40 -1
  4. package/dist/web-types.json +124 -3
  5. package/dist/zn.d.ts +670 -14
  6. package/dist/zn.min.js +1305 -925
  7. package/docs/pages/components/flow-builder-troubleshooter-demo.njk +106 -78
  8. package/docs/pages/components/flow-builder.md +422 -66
  9. package/docs/pages/components/page-builder.md +167 -0
  10. package/package.json +1 -1
  11. package/src/components/datepicker/datepicker.scss +0 -10
  12. package/src/components/flow-builder/flow-builder.component.ts +377 -16
  13. package/src/components/flow-builder/flow-builder.scss +398 -250
  14. package/src/components/flow-builder/flow-builder.test.ts +241 -4
  15. package/src/components/flow-builder/flow-layout.ts +42 -17
  16. package/src/components/flow-builder/flow.types.ts +168 -43
  17. package/src/components/flow-builder/modules/flow-branch-conditions/flow-branch-conditions.component.ts +300 -0
  18. package/src/components/flow-builder/modules/flow-branch-conditions/flow-branch-conditions.scss +222 -0
  19. package/src/components/flow-builder/modules/flow-branch-conditions/flow-branch-conditions.test.ts +125 -0
  20. package/src/components/flow-builder/modules/flow-branch-conditions/index.ts +12 -0
  21. package/src/components/flow-builder/modules/flow-canvas/flow-canvas.component.ts +184 -26
  22. package/src/components/flow-builder/modules/flow-canvas/flow-canvas.scss +170 -120
  23. package/src/components/flow-builder/modules/flow-node/flow-node.scss +42 -42
  24. package/src/components/flow-builder/modules/flow-step/flow-step.component.ts +2 -1
  25. package/src/components/flow-builder/modules/flow-step/flow-step.scss +25 -17
  26. package/src/components/icon-picker/icon-picker.component.ts +20 -37
  27. package/src/components/icon-picker/icon-picker.scss +5 -45
  28. package/src/components/page-builder/index.ts +14 -0
  29. package/src/components/page-builder/modules/page-palette-item/index.ts +12 -0
  30. package/src/components/page-builder/modules/page-palette-item/page-palette-item.component.ts +71 -0
  31. package/src/components/page-builder/modules/page-palette-item/page-palette-item.scss +70 -0
  32. package/src/components/page-builder/modules/page-palette-item/page-palette-item.test.ts +20 -0
  33. package/src/components/page-builder/modules/page-section-card/index.ts +12 -0
  34. package/src/components/page-builder/modules/page-section-card/page-section-card.component.ts +93 -0
  35. package/src/components/page-builder/modules/page-section-card/page-section-card.scss +92 -0
  36. package/src/components/page-builder/modules/page-section-card/page-section-card.test.ts +50 -0
  37. package/src/components/page-builder/page-builder.component.ts +1053 -0
  38. package/src/components/page-builder/page-builder.scss +494 -0
  39. package/src/components/page-builder/page-builder.test.ts +464 -0
  40. package/src/components/page-builder/page-registry.ts +48 -0
  41. package/src/components/page-builder/page.types.ts +75 -0
  42. package/src/events/events.ts +2 -0
  43. package/src/events/zn-page-change.ts +9 -0
  44. package/src/events/zn-page-selection-change.ts +7 -0
  45. package/src/zinc.ts +4 -0
  46. package/web-test-runner.config.js +6 -1
@@ -92,36 +92,90 @@ permalink: /components/flow-builder-troubleshooter-demo/index.html
92
92
  const QUESTION_COLOR = 'rgb(43, 192, 145)';
93
93
  const ANSWER_COLOR = 'rgb(59, 130, 246)';
94
94
 
95
- // Shared branch editor body: the conditions/filters required to take this path.
96
- // The builder supplies the "Branch name" input; this adds the condition fields,
97
- // persisted on the output port's `data`.
98
- const renderBranchConfig = (node, port, update) =>
99
- {
100
- const wrap = document.createElement('div');
101
- wrap.style.cssText = 'display:flex;flex-direction:column;gap:10px';
102
-
103
- const filter = document.createElement('zn-input');
104
- filter.setAttribute('label', 'Filter');
105
- filter.setAttribute('placeholder', 'e.g. platform = macOS');
106
- filter.value = port.data?.filter ?? '';
107
- filter.addEventListener('change', () =>
108
- update({data: {...port.data, filter: filter.value}}));
109
-
110
- const condition = document.createElement('zn-input');
111
- condition.setAttribute('label', 'Condition');
112
- condition.setAttribute('placeholder', 'e.g. answer contains "reinstalled"');
113
- condition.value = port.data?.condition ?? '';
114
- condition.addEventListener('change', () =>
115
- update({data: {...port.data, condition: condition.value}}));
116
-
117
- wrap.append(filter, condition);
118
- return wrap;
119
- };
120
-
121
- // Node config: label + body text, plus a branch manager — every question or
122
- // answer can have as many outputs as it likes. Inputs commit on every keystroke
123
- // so the canvas (node card, branch pills) updates live; the builder keeps this
124
- // DOM in place across those re-renders, so read node.outputs at event time.
95
+ // Shared branch filters: clicking a branch pill opens the built-in conditions
96
+ // editor (searchable picker, AND groups joined by OR), saved onto the output
97
+ // port's `data.conditions`. Operators without labels (eq, neq, gte…) get
98
+ // their well-known default labels.
99
+ const branchFilters = [
100
+ {
101
+ id: 'platform',
102
+ label: 'Platform',
103
+ description: 'The operating system the user reported',
104
+ fields: [
105
+ {
106
+ id: 'os',
107
+ operators: [{value: 'is'}, {value: 'is-not'}],
108
+ options: [
109
+ {value: 'macos', label: 'macOS'},
110
+ {value: 'windows', label: 'Windows'},
111
+ {value: 'linux', label: 'Linux'},
112
+ {value: 'ios', label: 'iOS'},
113
+ {value: 'android', label: 'Android'}
114
+ ]
115
+ }
116
+ ]
117
+ },
118
+ {
119
+ id: 'answer-text',
120
+ label: 'Answer text',
121
+ description: 'What the user typed in their reply',
122
+ fields: [
123
+ {
124
+ id: 'text',
125
+ type: 'text',
126
+ placeholder: 'e.g. reinstalled',
127
+ operators: [{value: 'contains'}, {value: 'not-contains'}]
128
+ }
129
+ ]
130
+ },
131
+ {
132
+ id: 'attempts',
133
+ label: 'Troubleshooting attempts',
134
+ description: 'How many times this flow ran for the contact',
135
+ fields: [
136
+ {
137
+ id: 'count',
138
+ type: 'number',
139
+ suffix: 'time(s)',
140
+ value: 2,
141
+ operators: [{value: 'gte'}, {value: 'lte'}, {value: 'eq'}]
142
+ }
143
+ ]
144
+ },
145
+ {
146
+ id: 'app-version',
147
+ label: 'App version',
148
+ fields: [
149
+ {
150
+ id: 'version',
151
+ type: 'text',
152
+ placeholder: 'e.g. 4.2.0',
153
+ operators: [{value: 'gte'}, {value: 'lte'}, {value: 'eq'}]
154
+ }
155
+ ]
156
+ },
157
+ {
158
+ id: 'plan',
159
+ label: 'Subscription plan',
160
+ fields: [
161
+ {
162
+ id: 'name',
163
+ operators: [{value: 'is'}, {value: 'is-not'}],
164
+ options: [
165
+ {value: 'trial', label: 'Trial'},
166
+ {value: 'personal', label: 'Personal'},
167
+ {value: 'family', label: 'Family'},
168
+ {value: 'business', label: 'Business'}
169
+ ]
170
+ }
171
+ ]
172
+ }
173
+ ];
174
+
175
+ // Node config: label + body text. Branches are managed entirely on the
176
+ // canvas — click a node's output port to draw one, rename/configure it via
177
+ // its pill, delete it via the pill's ✕. Inputs commit on every keystroke so
178
+ // the canvas (node card, branch pills) updates live.
125
179
  const live = (input, fn) =>
126
180
  ['input', 'zn-input'].forEach(ev => input.addEventListener(ev, fn));
127
181
 
@@ -144,50 +198,7 @@ permalink: /components/flow-builder-troubleshooter-demo/index.html
144
198
  body.value = node.data.subtitle ?? '';
145
199
  live(body, () => update({subtitle: body.value}));
146
200
 
147
- const heading = document.createElement('p');
148
- heading.textContent = 'Branches';
149
- heading.style.cssText = 'margin:4px 0 0;font-weight:600;font-size:0.8125rem';
150
-
151
- wrap.append(label, body, heading);
152
-
153
- const branches = node.outputs ?? [{id: 'out'}];
154
- const setBranches = (next) =>
155
- {
156
- node.outputs = next;
157
- update({});
158
- };
159
- const currentBranches = () => node.outputs ?? branches;
160
-
161
- branches.forEach((branch, i) =>
162
- {
163
- const row = document.createElement('div');
164
- row.style.cssText = 'display:flex;gap:6px;align-items:center';
165
-
166
- const input = document.createElement('zn-input');
167
- input.setAttribute('size', 'small');
168
- input.value = branch.label ?? branch.id;
169
- input.style.flex = '1';
170
- live(input, () =>
171
- setBranches(currentBranches().map((b, j) => (j === i ? {...b, label: input.value} : b))));
172
-
173
- const remove = document.createElement('zn-button');
174
- remove.setAttribute('icon', 'x@lu');
175
- remove.setAttribute('icon-button', 'small');
176
- remove.setAttribute('plain', '');
177
- remove.addEventListener('click', () => setBranches(currentBranches().filter((_, j) => j !== i)));
178
-
179
- row.append(input, remove);
180
- wrap.appendChild(row);
181
- });
182
-
183
- const add = document.createElement('zn-button');
184
- add.setAttribute('size', 'small');
185
- add.setAttribute('icon', 'plus@lu');
186
- add.textContent = 'Add branch';
187
- add.addEventListener('click', () =>
188
- setBranches([...currentBranches(), {id: 'branch-' + Date.now().toString(36), label: 'New branch'}]));
189
- wrap.appendChild(add);
190
-
201
+ wrap.append(label, body);
191
202
  return wrap;
192
203
  };
193
204
 
@@ -200,7 +211,7 @@ permalink: /components/flow-builder-troubleshooter-demo/index.html
200
211
  color: QUESTION_COLOR,
201
212
  description: 'Ask the user a question',
202
213
  renderConfig: renderConfig('Question'),
203
- renderBranchConfig,
214
+ branchFilters,
204
215
  };
205
216
 
206
217
  const answerType = {
@@ -212,7 +223,7 @@ permalink: /components/flow-builder-troubleshooter-demo/index.html
212
223
  color: ANSWER_COLOR,
213
224
  description: 'A user answer to branch on',
214
225
  renderConfig: renderConfig('Answer'),
215
- renderBranchConfig,
226
+ branchFilters,
216
227
  };
217
228
 
218
229
  // The tiered Q&A flow from the design: one question fanning out to three
@@ -229,7 +240,22 @@ permalink: /components/flow-builder-troubleshooter-demo/index.html
229
240
  },
230
241
  {
231
242
  id: 't1a1', type: 'ts-answer', x: 220, y: 340, label: 'Tier 1 - Answer 1',
232
- outputs: [{id: 'out', label: 'Branch C'}], data: {subtitle: 'I did XYZ...'}
243
+ // Branch C ships with saved conditions click its pill to see them.
244
+ outputs: [{
245
+ id: 'out', label: 'Branch C',
246
+ data: {
247
+ conditions: [
248
+ [
249
+ {filter: 'platform', values: {os: {operator: 'is', value: 'macos'}}},
250
+ {filter: 'attempts', values: {count: {operator: 'gte', value: 2}}}
251
+ ],
252
+ [
253
+ {filter: 'answer-text', values: {text: {operator: 'contains', value: 'reinstalled'}}}
254
+ ]
255
+ ]
256
+ }
257
+ }],
258
+ data: {subtitle: 'I did XYZ...'}
233
259
  },
234
260
  {
235
261
  id: 't1a2', type: 'ts-answer', x: 620, y: 340, label: 'Tier 1 - Answer 2',
@@ -274,8 +300,10 @@ permalink: /components/flow-builder-troubleshooter-demo/index.html
274
300
 
275
301
  const pristine = el.value;
276
302
  document.getElementById('ts-reset').addEventListener('click', () => (el.value = pristine));
303
+ // The builder serialises straight to its FlowState (positions included) —
304
+ // `JSON.stringify(el)` is the ready-made POST body for persisting.
277
305
  document.getElementById('ts-apply').addEventListener('click', () =>
278
- console.log('Apply changes', el.getState()));
306
+ console.log('Apply changes — POST body:', JSON.stringify(el)));
279
307
  document.getElementById('ts-close').addEventListener('click', () => history.back());
280
308
  });
281
309
  </script>