@humandialog/forms.svelte 0.5.20 → 0.5.22

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 (32) hide show
  1. package/components/Fab.svelte +0 -1
  2. package/components/combo/combo.svelte +42 -13
  3. package/components/combo/combo.svelte.d.ts +1 -0
  4. package/components/contextmenu.svelte +0 -1
  5. package/components/document/rich.edit.svelte +0 -1
  6. package/components/kanban/Kanban.d.ts +2 -0
  7. package/components/kanban/Kanban.js +24 -0
  8. package/components/kanban/internal/kanban.card.svelte +42 -26
  9. package/components/kanban/internal/kanban.column.svelte +46 -10
  10. package/components/kanban/internal/kanban.column.svelte.d.ts +2 -0
  11. package/components/kanban/internal/kanban.inserter.svelte +44 -6
  12. package/components/kanban/internal/kanban.props.svelte +2 -0
  13. package/components/kanban/kanban.combo.svelte +2 -0
  14. package/components/kanban/kanban.combo.svelte.d.ts +1 -0
  15. package/components/kanban/kanban.svelte +11 -4
  16. package/components/kanban/kanban.title.svelte +2 -0
  17. package/components/kanban/kanban.title.svelte.d.ts +1 -0
  18. package/components/list/List.d.ts +1 -0
  19. package/components/list/List.js +1 -0
  20. package/components/list/internal/list.element.props.svelte +1 -0
  21. package/components/list/internal/list.element.svelte +1 -0
  22. package/components/list/internal/list.inserter.svelte +55 -17
  23. package/components/list/list.combo.svelte +2 -0
  24. package/components/list/list.combo.svelte.d.ts +1 -0
  25. package/components/list/list.svelte +7 -4
  26. package/components/sidebar/sidebar.item.svelte +76 -22
  27. package/components/sidebar/sidebar.item.svelte.d.ts +3 -0
  28. package/components/sidebar/sidebar.list.svelte +23 -3
  29. package/components/sidebar/sidebar.list.svelte.d.ts +3 -0
  30. package/components/table/table.svelte +0 -1
  31. package/package.json +1 -1
  32. package/utils.js +21 -7
@@ -81,7 +81,6 @@ function getSelectionPos() {
81
81
  rect = range.getBoundingClientRect();
82
82
  let result = window.innerHeight - rect.top;
83
83
  result = Math.floor(result);
84
- console.log("selection box", result);
85
84
  return result;
86
85
  } else
87
86
  return 0;
@@ -26,6 +26,7 @@ export let inContext = "sel";
26
26
  export let cached = false;
27
27
  export let filtered = false;
28
28
  export let pushChangesImmediately = true;
29
+ export let hasNone = isAssociation;
29
30
  let is_compact = getContext("rIs-table-component") || compact;
30
31
  if (!definition) {
31
32
  definition = new rCombo_definition();
@@ -265,14 +266,18 @@ async function on_choose(itm) {
265
266
  if (onSelect) {
266
267
  if (itm == new_item_option)
267
268
  await onNewItemCreated(itm.Key, itm.Name);
268
- else
269
- await onSelect(item, itm.Key, itm.Name);
269
+ else {
270
+ if (itm)
271
+ await onSelect(item, itm.Key, itm.Name);
272
+ else
273
+ await onSelect(item, null, null);
274
+ }
270
275
  tick_request_internal = tick_request_internal + 1;
271
276
  } else {
272
277
  if (isAssociation) {
273
278
  if (choiceCallback) {
274
279
  let body = {
275
- choice: itm.Key
280
+ choice: itm ? itm.Key : null
276
281
  };
277
282
  let path;
278
283
  if (item.$ref)
@@ -297,15 +302,19 @@ async function on_choose(itm) {
297
302
  let result = await reef.post(
298
303
  path,
299
304
  {
300
- [a]: itm.Key
305
+ [a]: itm ? itm.Key : null
301
306
  }
302
307
  );
303
308
  if (result) {
304
- let name = definition.element_name ?? "$display";
305
- item[a] = {
306
- $ref: itm.Key,
307
- [name]: itm.Name
308
- };
309
+ if (itm) {
310
+ let name = definition.element_name ?? "$display";
311
+ item[a] = {
312
+ $ref: itm.Key,
313
+ [name]: itm.Name
314
+ };
315
+ } else {
316
+ item[a] = null;
317
+ }
309
318
  tick_request_internal = tick_request_internal + 1;
310
319
  }
311
320
  }
@@ -319,14 +328,14 @@ async function on_choose(itm) {
319
328
  let fields = calc_path_fields_param();
320
329
  if (fields)
321
330
  path += fields;
322
- let value = itm.Key ?? itm.Name;
331
+ let value = itm ? itm.Key ?? itm.Name : null;
323
332
  let result = await reef.post(path, { choice: value });
324
333
  if (result) {
325
334
  item[a] = result;
326
335
  tick_request_internal = tick_request_internal + 1;
327
336
  }
328
337
  } else {
329
- item[a] = itm.Key ?? itm.Name;
338
+ item[a] = itm ? itm.Key ?? itm.Name : null;
330
339
  tick_request_internal = tick_request_internal + 1;
331
340
  if (item && a && typename) {
332
341
  informModification(item, a, typename);
@@ -336,8 +345,12 @@ async function on_choose(itm) {
336
345
  }
337
346
  }
338
347
  }
339
- if (!!changed)
340
- changed(itm.Key, itm.Name);
348
+ if (!!changed) {
349
+ if (itm)
350
+ changed(itm.Key, itm.Name);
351
+ else
352
+ changed(null, null);
353
+ }
341
354
  }
342
355
  function on_keydown(e) {
343
356
  switch (e.key) {
@@ -588,6 +601,22 @@ function on_focus_out(e) {
588
601
  <ul class="py-1">
589
602
 
590
603
  {#if definition.source && definition.source.length}
604
+ {#if hasNone}
605
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
606
+ <li class="rounded p-2 flex flex-row items-center {font_size}"
607
+ class:bg-stone-100={highlighted_option == null}
608
+ class:dark:bg-stone-700={highlighted_option == null}
609
+ class:dark:hover:bg-stone-700={highlighted_option == null}
610
+ on:mousemove={() => on_mouse_move(null)}
611
+ on:click|preventDefault|stopPropagation={async () => await on_choose(null)}
612
+ tabindex="-1">
613
+
614
+ <div class="ml-2">
615
+ &lt;none&gt;
616
+ </div>
617
+ </li>
618
+ {/if}
619
+
591
620
  {@const _filtered_source = filtered_source ? filtered_source : definition.source}
592
621
  {#if _filtered_source.length > 0}
593
622
  {#each _filtered_source as item (item.Key)}
@@ -22,6 +22,7 @@ declare const __propDef: {
22
22
  cached?: boolean | undefined;
23
23
  filtered?: boolean | undefined;
24
24
  pushChangesImmediately?: boolean | undefined;
25
+ hasNone?: boolean | undefined;
25
26
  show?: ((event: any, hide_callback: any) => void) | undefined;
26
27
  hide?: (() => void) | undefined;
27
28
  };
@@ -28,7 +28,6 @@ afterUpdate(() => {
28
28
  const sel = window.getSelection();
29
29
  if (sel && sel.rangeCount > 0 && sel.focusNode && sel.focusNode.nodeType == sel.focusNode.TEXT_NODE) {
30
30
  container_rect.height -= 300;
31
- console.log("shirnked: ", container_rect);
32
31
  }
33
32
  }
34
33
  let xShifted = false;
@@ -963,7 +963,6 @@ function on_focus() {
963
963
  }
964
964
  function on_blur() {
965
965
  let active_range = Selection_helper.get_selection(editable_div);
966
- console.log("rich.edit: on_blur", active_range?.begin?.absolute_index);
967
966
  storedSelection = null;
968
967
  if (onBlur) {
969
968
  onBlur();
@@ -18,6 +18,7 @@ export declare class rKanban_definition {
18
18
  titleReadOnly: boolean;
19
19
  titleHref: string | undefined;
20
20
  titleHrefFunc: Function | undefined;
21
+ titleHasAttachment: Function | undefined;
21
22
  summaryAttrib: string;
22
23
  summaryOnChange: Function | undefined;
23
24
  summaryReadOnly: boolean;
@@ -39,6 +40,7 @@ export declare class rKanban_definition {
39
40
  getCardOperations: Function | undefined;
40
41
  private items;
41
42
  getItems(): object[];
43
+ visibleColumnsNo(): number;
42
44
  clear(): void;
43
45
  }
44
46
  export declare const KanbanColumnTop = -1;
@@ -17,6 +17,7 @@ export class rKanban_definition {
17
17
  titleReadOnly = false;
18
18
  titleHref = undefined;
19
19
  titleHrefFunc = undefined;
20
+ titleHasAttachment = undefined;
20
21
  summaryAttrib = '';
21
22
  summaryOnChange = undefined;
22
23
  summaryReadOnly = false;
@@ -50,6 +51,29 @@ export class rKanban_definition {
50
51
  }
51
52
  return this.items;
52
53
  }
54
+ visibleColumnsNo() {
55
+ // has <Other> column
56
+ if (this.columns.find((c) => c.state < 0)) {
57
+ const allItems = this.getItems();
58
+ const isExplicitState = (e) => {
59
+ const elementState = e[this.stateAttrib];
60
+ const colsNo = this.columns.length;
61
+ for (let i = 0; i < colsNo; i++) {
62
+ const def = this.columns[i];
63
+ if ((def.state >= 0) && (def.state == elementState))
64
+ return true;
65
+ }
66
+ return false;
67
+ };
68
+ const unknownStateItems = allItems.filter(e => !isExplicitState(e));
69
+ if (unknownStateItems && (unknownStateItems.length > 0))
70
+ return this.columns.length;
71
+ else
72
+ return this.columns.length - 1;
73
+ }
74
+ else
75
+ return this.columns.length;
76
+ }
53
77
  clear() {
54
78
  this.columns = [];
55
79
  this.titleAttrib = '';
@@ -12,8 +12,7 @@ import {
12
12
  pushChanges,
13
13
  startEditing
14
14
  } from "../../..";
15
- import { FaArrowsAlt, FaTrash, FaPlus, FaExternalLinkAlt } from "svelte-icons/fa";
16
- import MoveOperations from "./kanban.move.menu.svelte";
15
+ import { FaRegFileAlt } from "svelte-icons/fa";
17
16
  import Properties from "./kanban.props.svelte";
18
17
  import { KanbanCardTop, KanbanCardMiddle, KanbanCardBottom } from "../Kanban";
19
18
  export let item;
@@ -148,6 +147,28 @@ function getHRef() {
148
147
  else
149
148
  return "";
150
149
  }
150
+ function performOpen(e) {
151
+ e.stopPropagation();
152
+ if (isLinkLike)
153
+ followDefinedHRef();
154
+ else
155
+ definition.onOpen(item);
156
+ }
157
+ function conditionalClick(node, { condition, callback }) {
158
+ if (condition) {
159
+ node.addEventListener("click", callback);
160
+ return {
161
+ destroy() {
162
+ node.removeEventListener("click", callback);
163
+ }
164
+ };
165
+ }
166
+ }
167
+ function showAttachementIcon() {
168
+ if (!definition.titleHasAttachment)
169
+ return false;
170
+ return definition.titleHasAttachment(item);
171
+ }
151
172
  </script>
152
173
 
153
174
  <!-- svelte-ignore a11y-click-events-have-key-events -->
@@ -183,43 +204,38 @@ function getHRef() {
183
204
 
184
205
 
185
206
  {#if isCardActive}
186
- {#if isLinkLike}
207
+ {@const hasOpen = !!definition.onOpen}
208
+ {@const canOpen = isLinkLike || hasOpen}
209
+ {@const openableClass = canOpen ? "sm:hover:cursor-pointer underline" : ""}
210
+ {@const showIcon = showAttachementIcon()}
187
211
  <h3 class=" text-lg font-semibold min-h-[1.75rem]
188
212
  sm:text-sm sm:font-semibold sm:min-h-[1.25rem]
189
213
  whitespace-nowrap overflow-clip truncate w-full sm:flex-none
190
- relative
191
- sm:hover:cursor-pointer underline"
192
- on:click|stopPropagation={followDefinedHRef}
214
+ relative {openableClass}"
193
215
  use:editable={{
194
216
  action: (text) => onTitleChanged(text),
195
217
  active: false,
196
218
  readonly: definition.titleReadOnly,
197
- onFinish: (d) => {titleElement.blur()}}}
219
+ onFinish: (d) => {titleElement.blur()},
220
+ onSoftEnter: async (text) => { onTitleChanged(text); await editProperty('Summary') }
221
+ }}
222
+ use:conditionalClick={{
223
+ condition: canOpen,
224
+ callback: performOpen}}
198
225
  bind:this={titleElement}>
199
226
  {item[definition.titleAttrib]}
200
- </h3>
201
- {:else}
202
- <h3 class=" text-lg font-semibold min-h-[1.75rem]
203
- sm:text-sm sm:font-semibold sm:min-h-[1.25rem]
204
- whitespace-nowrap overflow-clip truncate w-full sm:flex-none
205
- relative"
206
- use:editable={{
207
- action: (text) => onTitleChanged(text),
208
- active: true,
209
- readonly: definition.titleReadOnly,
210
- onFinish: (d) => {titleElement.blur()}}}
211
- bind:this={titleElement}>
212
- {item[definition.titleAttrib]}
213
227
 
214
- {#if definition.onOpen}
215
- <button class="absolute top-1 right-0 w-5 h-5 sm:w-3 sm:h-3"
216
- on:click={(e) => definition.onOpen(item)}>
217
- <FaExternalLinkAlt/>
218
- </button>
228
+ {#if showIcon}
229
+ <span id="attachement" class="absolute top-1 right-0 w-5 h-5 sm:w-3 sm:h-3">
230
+ <FaRegFileAlt/>
231
+ </span>
219
232
  {/if}
220
233
  </h3>
221
- {/if}
234
+
235
+ <!--Tooltip type='light' triggeredBy="#attachement">Has attachement</Tooltip-->
222
236
 
237
+
238
+
223
239
  {:else}
224
240
  <h3 class=" text-lg font-semibold min-h-[1.75rem]
225
241
  sm:text-sm sm:font-semibold sm:min-h-[1.25rem]
@@ -9,6 +9,8 @@ export let currentColumnIdx;
9
9
  export let onInsert;
10
10
  let column_element;
11
11
  export function getHeight() {
12
+ if (!column_element)
13
+ return 0;
12
14
  return column_element.getBoundingClientRect().height;
13
15
  }
14
16
  let titleElement;
@@ -20,6 +22,8 @@ export const SET_RIGHT = 1;
20
22
  export const CLEAR_LEFT = 2;
21
23
  export const CLEAR_RIGHT = 3;
22
24
  export function setBorder(what_to_do) {
25
+ if (!column_element)
26
+ return;
23
27
  switch (what_to_do) {
24
28
  case SET_LEFT:
25
29
  column_element.classList.add("border-l");
@@ -52,8 +56,31 @@ $:
52
56
  force_rerender($data_tick_store, $contextItemsStore);
53
57
  export function reload() {
54
58
  let allItems = definition.getItems();
55
- if (definition.stateAttrib)
56
- column_items = allItems.filter((e) => e[definition.stateAttrib] == columnDef.state);
59
+ if (definition.stateAttrib) {
60
+ if (columnDef.state < 0) {
61
+ const isExplicitState = (e) => {
62
+ const elementState = e[definition.stateAttrib];
63
+ const colsNo = definition.columns.length;
64
+ for (let i = 0; i < colsNo; i++) {
65
+ const def = definition.columns[i];
66
+ if (def.state >= 0 && def.state == elementState)
67
+ return true;
68
+ }
69
+ return false;
70
+ };
71
+ column_items = allItems.filter((e) => !isExplicitState(e));
72
+ } else
73
+ column_items = allItems.filter((e) => e[definition.stateAttrib] == columnDef.state);
74
+ }
75
+ }
76
+ export function isVisible() {
77
+ if (columnDef.state < 0) {
78
+ if (column_items && column_items.length > 0)
79
+ return true;
80
+ else
81
+ return false;
82
+ } else
83
+ return true;
57
84
  }
58
85
  function setup_data(...args) {
59
86
  reload();
@@ -111,6 +138,8 @@ export async function add(after = KanbanColumnTop) {
111
138
  if (!inserter)
112
139
  return;
113
140
  inserter.run(async (detail) => {
141
+ if (detail.softEnter)
142
+ return;
114
143
  showInserterAfterId = None;
115
144
  if (detail.cancel)
116
145
  activateAfterDomUpdate = lastActivatedElement;
@@ -175,11 +204,14 @@ function onResizeWindow() {
175
204
  styleWidth = getWidthStyle();
176
205
  }
177
206
  function getWidthStyle() {
178
- const assumed_space = 800;
179
- const default_column_width = Math.floor(assumed_space / definition.columns.length);
180
- const column_width = columnDef.width ? columnDef.width : default_column_width;
207
+ const container = document.getElementById("__hd_svelte_main_content_container");
208
+ const containerRect = container?.getBoundingClientRect();
209
+ const assumed_space = containerRect.width;
210
+ const columns_no = definition.visibleColumnsNo();
211
+ const default_column_width = Math.floor(assumed_space / columns_no);
212
+ const column_width = Math.min(columnDef.width ? columnDef.width : default_column_width, 640);
181
213
  if (window.innerWidth >= 640)
182
- return `width: ${column_width}px; min-width: 180px; max-width: ${column_width}px;`;
214
+ return `width: ${column_width}px; min-width: 200px; max-width: ${column_width}px;`;
183
215
  else
184
216
  return "width: 92%;";
185
217
  }
@@ -187,6 +219,8 @@ function getWidthStyle() {
187
219
 
188
220
  <!-- svelte-ignore a11y-click-events-have-key-events -->
189
221
 
222
+ {#if (columnDef.state >=0) || ((column_items && column_items.length > 0))}
223
+
190
224
  <section class=" snap-center
191
225
  sm:snap-align-none
192
226
  flex-none sm:flex-1
@@ -194,6 +228,8 @@ function getWidthStyle() {
194
228
  min-h-[calc(100vh-5rem)]
195
229
  rounded-md border border-transparent
196
230
  {selected_class} {focused_class}"
231
+
232
+
197
233
  style={styleWidth}
198
234
  use:selectable={columnDef}
199
235
  on:click={activate}>
@@ -221,7 +257,7 @@ function getWidthStyle() {
221
257
  </header>
222
258
  <ul class="w-full border-stone-700 pb-20" bind:this={column_element}>
223
259
  {#if showInserterAfterId === KanbanColumnTop}
224
- <Inserter onInsert={async (text) => {await onInsert(currentColumnIdx, text, KanbanColumnTop)}}
260
+ <Inserter onInsert={async (title, summary) => {await onInsert(currentColumnIdx, title, summary, KanbanColumnTop)}}
225
261
  bind:this={inserter} />
226
262
  {/if}
227
263
 
@@ -243,17 +279,17 @@ function getWidthStyle() {
243
279
  </Card>
244
280
 
245
281
  {#if showInserterAfterId == element.Id}
246
- <Inserter onInsert={async (text) => {await onInsert(currentColumnIdx, text, showInserterAfterId)}}
282
+ <Inserter onInsert={async (title, summary) => {await onInsert(currentColumnIdx, title, summary, showInserterAfterId)}}
247
283
  bind:this={inserter} />
248
284
  {/if}
249
285
  {/each}
250
286
  {/if}
251
287
 
252
288
  {#if showInserterAfterId === KanbanColumnBottom}
253
- <Inserter onInsert={async (text) => {await onInsert(currentColumnIdx, text, KanbanColumnBottom)}}
289
+ <Inserter onInsert={async (title, summary) => {await onInsert(currentColumnIdx, title, summary, KanbanColumnBottom)}}
254
290
  bind:this={inserter} />
255
291
  {/if}
256
292
 
257
293
  </ul>
258
294
  </section>
259
-
295
+ {/if}
@@ -11,6 +11,7 @@ declare const __propDef: {
11
11
  CLEAR_RIGHT?: 3 | undefined;
12
12
  setBorder?: ((what_to_do: number) => void) | undefined;
13
13
  reload?: (() => void) | undefined;
14
+ isVisible?: (() => boolean) | undefined;
14
15
  findCardByItem?: ((item: object) => any) | undefined;
15
16
  activateByItemId?: ((id: number) => void) | undefined;
16
17
  add?: ((after?: object | number) => Promise<void>) | undefined;
@@ -43,6 +44,7 @@ export default class Kanban extends SvelteComponentTyped<KanbanProps, KanbanEven
43
44
  get CLEAR_RIGHT(): 3;
44
45
  get setBorder(): (what_to_do: number) => void;
45
46
  get reload(): () => void;
47
+ get isVisible(): () => boolean;
46
48
  get findCardByItem(): (item: object) => any;
47
49
  get activateByItemId(): (id: number) => void;
48
50
  get add(): (after?: number | object) => Promise<void>;
@@ -1,12 +1,29 @@
1
- <script>import {
1
+ <script>import { tick } from "svelte";
2
+ import {
2
3
  startEditing,
3
4
  editable
4
5
  } from "../../..";
5
6
  export let onInsert;
7
+ let onClose;
6
8
  export function run(onclose) {
7
- startEditing(insertion_paragraph, onclose);
9
+ onClose = onclose;
10
+ startEditing(titleElement, onclose);
11
+ }
12
+ let titleElement;
13
+ let title = "";
14
+ let summary = "";
15
+ let editSummary = false;
16
+ let summaryElement;
17
+ async function softEnter(t) {
18
+ title = t;
19
+ editSummary = true;
20
+ await tick();
21
+ startEditing(summaryElement, onClose);
22
+ }
23
+ async function onSummaryChanged(text) {
24
+ summary = text;
25
+ await onInsert(title, summary);
8
26
  }
9
- let insertion_paragraph;
10
27
  </script>
11
28
 
12
29
  <!-- svelte-ignore a11y-click-events-have-key-events -->
@@ -17,8 +34,29 @@ let insertion_paragraph;
17
34
  <h3 class=" text-lg font-semibold min-h-[1.75rem]
18
35
  sm:text-sm sm:font-semibold sm:min-h-[1.25rem]
19
36
  whitespace-nowrap overflow-clip w-full sm:flex-none "
20
- use:editable={onInsert}
21
- bind:this={insertion_paragraph}>
22
-
37
+ use:editable={{
38
+ action: (text) => onInsert(text, ''),
39
+ active: false,
40
+ onSoftEnter: softEnter
41
+ }}
42
+ bind:this={titleElement}>
23
43
  </h3>
44
+
45
+ {#if editSummary}
46
+ <p class=" sm:text-xs sm:min-h-[1rem]
47
+ text-base min-h-[1.5rem]
48
+ text-stone-400
49
+ max-h-[75px] sm:max-h-[64px]
50
+ overflow-hidden"
51
+ use:editable={{
52
+ action: (text) => onSummaryChanged(text),
53
+ active: false,
54
+ onFinish: (d) => {editSummary = false}}}
55
+ bind:this={summaryElement}>
56
+ {summary}
57
+ </p>
58
+ {/if}
59
+
60
+
61
+
24
62
  </li>
@@ -107,9 +107,11 @@ async function editTags(field, propIdx) {
107
107
  a={prop.a}
108
108
  onSelect={prop.onSelect}
109
109
  isAssociation={prop.association}
110
+ hasNone={prop.hasNone}
110
111
  icon={false}
111
112
  definition={prop.combo_definition}
112
113
  s="xs"
114
+ changed={(k,n) => { /*fake assignment for component rer-ender*/ item[prop.a] = item[prop.a]; }}
113
115
  bind:this={propElements[idx]}/>
114
116
  {:else if prop.type == rList_property_type.Static}
115
117
  <p
@@ -6,6 +6,7 @@ export let name = "";
6
6
  export let a = "";
7
7
  export let onSelect = void 0;
8
8
  export let association = false;
9
+ export let hasNone = association;
9
10
  export let top = false;
10
11
  export let middle = true;
11
12
  export let bottom = false;
@@ -23,6 +24,7 @@ if (!a && name) {
23
24
  }
24
25
  combo_property.onSelect = onSelect;
25
26
  combo_property.association = association;
27
+ combo_property.hasNone = hasNone;
26
28
  if (top)
27
29
  combo_property.position = KanbanCardTop;
28
30
  else if (bottom)
@@ -5,6 +5,7 @@ declare const __propDef: {
5
5
  a?: string | undefined;
6
6
  onSelect?: undefined;
7
7
  association?: boolean | undefined;
8
+ hasNone?: boolean | undefined;
8
9
  top?: boolean | undefined;
9
10
  middle?: boolean | undefined;
10
11
  bottom?: boolean | undefined;
@@ -125,7 +125,12 @@ export async function reload(data, selectElement = KEEP_SELECTION) {
125
125
  }
126
126
  }
127
127
  export function getColumnIdx(item) {
128
- return definition.columns.findIndex((c2) => c2.state == item[definition.stateAttrib]);
128
+ let idx = definition.columns.findIndex((c2) => c2.state == item[definition.stateAttrib]);
129
+ if (idx >= 0)
130
+ return idx;
131
+ else {
132
+ return definition.columns.findIndex((c2) => c2.state < 0);
133
+ }
129
134
  }
130
135
  export function edit(item, field) {
131
136
  const columnIdx = getColumnIdx(item);
@@ -299,7 +304,7 @@ export function replace(item, toColumnIdx, afterElement) {
299
304
  return;
300
305
  }
301
306
  }
302
- async function onInsert(columnIdx, title2, afterId) {
307
+ async function onInsert(columnIdx, title2, summary, afterId) {
303
308
  const columnState = definition.columns[columnIdx].state;
304
309
  const oa = definition.orderAttrib;
305
310
  const sa = definition.stateAttrib;
@@ -308,6 +313,7 @@ async function onInsert(columnIdx, title2, afterId) {
308
313
  const columnBottom = allItems.findLast((e) => e[sa] == columnState);
309
314
  let newElement = {
310
315
  [definition.titleAttrib]: title2,
316
+ [definition.summaryAttrib]: summary,
311
317
  [sa]: columnState
312
318
  };
313
319
  if (afterId == KanbanColumnTop) {
@@ -427,9 +433,10 @@ export function add(item, columnIdx = -1) {
427
433
  <!--hr class="hidden sm:block w-full"-->
428
434
  {/if}
429
435
 
430
- <section class="h-full mt-5 flex flex-row no-wrap sm:justify-center
436
+ <section id="__hd_svelte_kanban_columns_container"
437
+ class="h-full mt-5 flex flex-row no-wrap
431
438
  overflow-x-auto snap-x snap-mandatory sm:snap-none
432
- {user_class}">
439
+ {user_class}"> <!--sm:justify-center -->
433
440
  {#each definition.columns as column, idx (column.id)}
434
441
  <Column currentColumnIdx={idx}
435
442
  {onInsert}
@@ -4,11 +4,13 @@ export let onChange = void 0;
4
4
  export let readOnly = false;
5
5
  export let href = void 0;
6
6
  export let hrefFunc = void 0;
7
+ export let hasAttachment = void 0;
7
8
  let definition = getContext("rKanban-definition");
8
9
  definition.titleAttrib = a;
9
10
  definition.titleOnChange = onChange;
10
11
  definition.titleReadOnly = readOnly;
11
12
  definition.titleHref = href;
12
13
  definition.titleHrefFunc = hrefFunc;
14
+ definition.titleHasAttachment = hasAttachment;
13
15
  </script>
14
16
 
@@ -6,6 +6,7 @@ declare const __propDef: {
6
6
  readOnly?: boolean | undefined;
7
7
  href?: string | undefined;
8
8
  hrefFunc?: Function | undefined;
9
+ hasAttachment?: Function | undefined;
9
10
  };
10
11
  events: {
11
12
  [evt: string]: CustomEvent<any>;
@@ -19,6 +19,7 @@ export declare class rList_property_combo extends rList_property {
19
19
  constructor();
20
20
  association: boolean;
21
21
  combo_definition: rCombo_definition;
22
+ hasNone: boolean;
22
23
  }
23
24
  export declare class rList_property_tags extends rList_property {
24
25
  constructor();
@@ -25,6 +25,7 @@ export class rList_property_combo extends rList_property {
25
25
  }
26
26
  association = false;
27
27
  combo_definition;
28
+ hasNone = false;
28
29
  }
29
30
  export class rList_property_tags extends rList_property {
30
31
  constructor() {
@@ -90,6 +90,7 @@ async function edit_date(field, prop_idx) {
90
90
  a={prop.a}
91
91
  onSelect={prop.onSelect}
92
92
  isAssociation={prop.association}
93
+ hasNone={prop.hasNone}
93
94
  icon={false}
94
95
  bind:this={props[prop_index]}
95
96
  definition={prop.combo_definition}
@@ -250,6 +250,7 @@ export function scrollToView() {
250
250
  action: (text) => {change_name(text)},
251
251
  active: false,
252
252
  readonly: definition.title_readonly,
253
+ onSoftEnter: (text) => {change_name(text); editProperty('Summary')}
253
254
  }}
254
255
  >
255
256
  {element_title}
@@ -1,27 +1,65 @@
1
- <script>import { editable, startEditing } from "../../../utils";
1
+ <script>import { tick } from "svelte";
2
+ import { editable, startEditing } from "../../../utils";
2
3
  import Icon from "../../icon.svelte";
3
4
  import { FaPlus } from "svelte-icons/fa";
4
5
  export let onInsert;
5
6
  export let icon = false;
7
+ let onClose;
6
8
  export function run(onclose) {
7
- startEditing(insertion_paragraph, onclose);
9
+ onClose = onclose;
10
+ startEditing(titleElement, onclose);
11
+ }
12
+ let titleElement;
13
+ let summaryElement;
14
+ let title = "";
15
+ let summary = "";
16
+ let editSummary = false;
17
+ async function softEnter(text) {
18
+ title = text;
19
+ editSummary = true;
20
+ await tick();
21
+ startEditing(summaryElement, onClose);
22
+ }
23
+ async function onSummaryChanged(text) {
24
+ summary = text;
25
+ await onInsert(title, summary);
8
26
  }
9
- let insertion_paragraph;
10
27
  </script>
11
28
 
12
- <section class="mt-3 flex flex-row my-0 w-full text-lg sm:text-sm text-stone-700 dark:text-stone-400 cursor-default rounded-md border border-transparent bg-stone-200 dark:bg-stone-700">
13
- {#if icon}
14
- <!--Icon size={3}
15
- component={FaPlus}
16
- class="mt-1.5 ml-2 "/-->
17
- <div class="h-5 w-5 sm:h-4 sm:w-4 mt-2 sm:mt-1.5 ml-2"></div>
18
- {/if}
29
+ <section class="mt-3 my-0 w-full text-lg sm:text-sm text-stone-700 dark:text-stone-400 cursor-default rounded-md border border-transparent bg-stone-200 dark:bg-stone-700">
30
+ <div class="flex flex-row">
31
+ {#if icon}
32
+ <!--Icon size={3}
33
+ component={FaPlus}
34
+ class="mt-1.5 ml-2 "/-->
35
+ <div class="h-5 w-5 sm:h-4 sm:w-4 mt-2 sm:mt-1.5 ml-2"></div>
36
+ {/if}
19
37
 
20
- <p class=" ml-3 py-1
21
- text-lg font-semibold min-h-[1.75rem]
22
- sm:text-sm sm:font-semibold sm:min-h-[1.25rem]
23
- whitespace-nowrap overflow-clip flex-none w-1/2 sm:w-1/3" tabindex="0"
24
- bind:this={insertion_paragraph}
25
- use:editable={onInsert} >
26
- </p>
38
+ <p class=" ml-3 py-1
39
+ text-lg font-semibold min-h-[1.75rem]
40
+ sm:text-sm sm:font-semibold sm:min-h-[1.25rem]
41
+ whitespace-nowrap overflow-clip flex-none w-1/2 sm:w-1/3" tabindex="0"
42
+ bind:this={titleElement}
43
+ use:editable={{
44
+ action: (text) => onInsert(text, ''),
45
+ active: false,
46
+ onSoftEnter: softEnter
47
+ }} >
48
+ </p>
49
+ </div>
50
+
51
+ {#if editSummary}
52
+ <p bind:this={summaryElement}
53
+ class=" ml-10 sm:ml-9
54
+ sm:text-xs sm:min-h-[1rem]
55
+ text-base min-h-[1.5rem]
56
+ text-stone-400"
57
+ use:editable={{
58
+ action: onSummaryChanged,
59
+ active: false,
60
+ onFinish: (d) => {editSummary=false}
61
+ }}>
62
+ {summary}
63
+ </p>
64
+ {/if}
27
65
  </section>
@@ -5,6 +5,7 @@ export let name;
5
5
  export let a = "";
6
6
  export let onSelect = void 0;
7
7
  export let association = false;
8
+ export let hasNone = association;
8
9
  let definition = getContext("rList-definition");
9
10
  let combo_property = new rList_property_combo();
10
11
  combo_property.name = name;
@@ -13,6 +14,7 @@ if (!combo_property.a)
13
14
  combo_property.a = combo_property.name;
14
15
  combo_property.onSelect = onSelect;
15
16
  combo_property.association = association;
17
+ combo_property.hasNone = hasNone;
16
18
  definition.properties.push(combo_property);
17
19
  setContext("rCombo-definition", combo_property.combo_definition);
18
20
  </script>
@@ -5,6 +5,7 @@ declare const __propDef: {
5
5
  a?: string | undefined;
6
6
  onSelect?: undefined;
7
7
  association?: boolean | undefined;
8
+ hasNone?: boolean | undefined;
8
9
  };
9
10
  events: {
10
11
  [evt: string]: CustomEvent<any>;
@@ -175,6 +175,8 @@ export async function addRowAfter(after = null) {
175
175
  if (!inserter)
176
176
  return;
177
177
  inserter.run(async (detail) => {
178
+ if (detail.softEnter)
179
+ return;
178
180
  show_insertion_row_after_element = null;
179
181
  if (detail.cancel)
180
182
  activate_after_dom_update = last_activated_element;
@@ -233,9 +235,10 @@ function reorderElements(items2, from = null) {
233
235
  }
234
236
  pushChanges();
235
237
  }
236
- async function insert(title2, after) {
238
+ async function insert(title2, summary, after) {
237
239
  let newElement = {
238
- [definition.title]: title2
240
+ [definition.title]: title2,
241
+ [definition.summary]: summary
239
242
  };
240
243
  if (after && orderAttrib) {
241
244
  const leftElement = after;
@@ -298,7 +301,7 @@ async function insert(title2, after) {
298
301
  </List_element>
299
302
 
300
303
  {#if show_insertion_row_after_element == element}
301
- <Inserter onInsert={async (text) => {await insert(text, show_insertion_row_after_element)}}
304
+ <Inserter onInsert={async (title, summary) => {await insert(title, summary, show_insertion_row_after_element)}}
302
305
  icon={definition.inserter_icon}
303
306
  bind:this={inserter} />
304
307
  {/if}
@@ -306,7 +309,7 @@ async function insert(title2, after) {
306
309
  {/if}
307
310
 
308
311
  {#if show_insertion_row_after_element == END_OF_LIST}
309
- <Inserter onInsert={async (text) => {await insert(text, null)}}
312
+ <Inserter onInsert={async (title, summary) => {await insert(text, summary, null)}}
310
313
  icon={definition.inserter_icon}
311
314
  bind:this={inserter} />
312
315
  {/if}
@@ -8,6 +8,7 @@ import {
8
8
  editable as _editable,
9
9
  handleSelect,
10
10
  activateItem,
11
+ startEditing,
11
12
  getActive
12
13
  } from "../../utils";
13
14
  import { showMenu } from "../menu";
@@ -18,11 +19,48 @@ export let selectable = void 0;
18
19
  export let editable = void 0;
19
20
  export let operations = void 0;
20
21
  export let item = void 0;
22
+ export let summary = void 0;
21
23
  let isOnPage = getContext("rIs-page-component");
24
+ let summaryElement = null;
25
+ let summaryPlaceholder = false;
26
+ let summaryEditable = void 0;
22
27
  $:
23
28
  context_data = $contextItemsStore;
24
29
  $:
25
30
  isRowActive = calculateIsRowActive($contextItemsStore);
31
+ $:
32
+ summaryText = calculateSummary(summary);
33
+ function calculateSummary(...args) {
34
+ if (!summary) {
35
+ summaryEditable = void 0;
36
+ return "";
37
+ }
38
+ if (summary instanceof Object) {
39
+ summaryEditable = summary.editable;
40
+ if (summary.content)
41
+ return summary.content;
42
+ else
43
+ return "";
44
+ } else {
45
+ summaryEditable = void 0;
46
+ return summary;
47
+ }
48
+ }
49
+ export async function editSummary() {
50
+ if (!summaryEditable)
51
+ return;
52
+ if (!!summaryElement)
53
+ startEditing(summaryElement, (d) => {
54
+ summaryPlaceholder = false;
55
+ });
56
+ else {
57
+ summaryPlaceholder = true;
58
+ await tick();
59
+ startEditing(summaryElement, (d) => {
60
+ summaryPlaceholder = false;
61
+ });
62
+ }
63
+ }
26
64
  let user_class = $$props.class ?? "";
27
65
  let root;
28
66
  function calculateIsRowActive(...args) {
@@ -130,34 +168,50 @@ function activateRow(e) {
130
168
  class=" border border-transparent rounded-lg
131
169
  text-lg sm:text-base font-normal
132
170
  text-stone-900 sm:hover:bg-stone-100
133
- dark:text-white sm:dark:hover:bg-stone-700 {user_class}
134
- flex flex-row justify-between"
171
+ dark:text-white sm:dark:hover:bg-stone-700 {user_class}"
135
172
  class:bg-stone-200={isRowActive}
136
173
  class:dark:bg-stone-700={isRowActive}
137
174
  class:selected={selected(selectable, context_data)}>
138
- <a href={href}
139
- on:click={on_link_clicked}
140
- class="flex-1 ml-2 my-3 sm:my-2 inline-flex items-center group">
141
- {#if icon}
142
- <Icon size={5} component={icon}/>
143
- {/if}
144
- <span class="ml-3 group-hover:underline"
145
- use:editable_if_needed={editable}>
146
- <slot/>
147
- </span>
148
- </a>
175
+ <div class="flex flex-row justify-between">
176
+ <a href={href}
177
+ on:click={on_link_clicked}
178
+ class="flex-1 ml-2 mt-3 sm:mt-2 inline-flex items-center group"
179
+ class:mb-3={!summary}
180
+ class:sm:mb-2={!summary}
181
+ >
182
+ {#if icon}
183
+ <Icon size={5} component={icon}/>
184
+ {/if}
185
+ <span class="ml-3 group-hover:underline"
186
+ use:editable_if_needed={editable}>
187
+ <slot/>
188
+ </span>
189
+ </a>
149
190
 
150
- {#if !isOnPage}
151
- <section class="flex-0 w-20 sm:w-12 h-10 flex-0 flex flex-row"
152
- use:selectable_if_needed={selectable}>
153
- {#if can_show_context_menu(selectable, context_data)}
154
- <button class="w-6 sm:w-4 h-6 sm:h-4 mt-3 mr-3 sm:mr-2 ml-auto" on:click={on_show_menu}>
155
- <FaBars/>
156
- </button>
191
+ {#if !isOnPage}
192
+ <section class="flex-0 w-20 sm:w-12 h-10 flex-0 flex flex-row"
193
+ use:selectable_if_needed={selectable}>
194
+ {#if can_show_context_menu(selectable, context_data)}
195
+ <button class="w-6 sm:w-4 h-6 sm:h-4 mt-3 mr-3 sm:mr-2 ml-auto" on:click={on_show_menu}>
196
+ <FaBars/>
197
+ </button>
198
+ {/if}
199
+ </section>
157
200
  {/if}
158
- </section>
201
+ </div>
202
+
203
+ {#if summary}
204
+ <p class="text-xs ml-10 mb-2 mr-2
205
+ text-stone-900 dark:text-stone-400
206
+ cursor-default"
207
+ use:selectable_if_needed={selectable}
208
+ use:editable_if_needed={summaryEditable}
209
+ bind:this={summaryElement}>
210
+ {summaryText}
211
+ </p>
159
212
  {/if}
160
- </div>
213
+
214
+ </div>
161
215
  </li>
162
216
 
163
217
 
@@ -9,6 +9,8 @@ declare const __propDef: {
9
9
  editable?: any | undefined;
10
10
  operations?: any | undefined;
11
11
  item?: object | undefined;
12
+ summary?: string | object | undefined;
13
+ editSummary?: (() => Promise<void>) | undefined;
12
14
  };
13
15
  events: {
14
16
  click: MouseEvent;
@@ -25,5 +27,6 @@ export type SidebarProps = typeof __propDef.props;
25
27
  export type SidebarEvents = typeof __propDef.events;
26
28
  export type SidebarSlots = typeof __propDef.slots;
27
29
  export default class Sidebar extends SvelteComponentTyped<SidebarProps, SidebarEvents, SidebarSlots> {
30
+ get editSummary(): () => Promise<void>;
28
31
  }
29
32
  export {};
@@ -1,7 +1,7 @@
1
1
  <script>import Icon from "../icon.svelte";
2
2
  import Edit from "../edit.field.svelte";
3
3
  import { FaPlus } from "svelte-icons/fa";
4
- import { getPrev, getNext, swapElements, getLast } from "../../utils";
4
+ import { getPrev, getNext, swapElements, getLast, getFirst, remove, insertAt } from "../../utils";
5
5
  import { informModification, pushChanges } from "../../updates";
6
6
  import { tick } from "svelte";
7
7
  export let objects;
@@ -28,6 +28,26 @@ export function moveUp(element) {
28
28
  pushChanges();
29
29
  }
30
30
  }
31
+ export function moveTop(element) {
32
+ if (!orderAttrib)
33
+ return;
34
+ let current = getFirst(objects);
35
+ if (current == element)
36
+ return;
37
+ const firstOrder = current[orderAttrib];
38
+ while (current != element) {
39
+ const next = getNext(objects, current);
40
+ const nextOrder = next[orderAttrib];
41
+ current[orderAttrib] = nextOrder;
42
+ informModification(current, orderAttrib);
43
+ current = next;
44
+ }
45
+ element[orderAttrib] = firstOrder;
46
+ informModification(element, orderAttrib);
47
+ objects = remove(objects, element);
48
+ objects = insertAt(objects, 0, element);
49
+ pushChanges();
50
+ }
31
51
  export function moveDown(element) {
32
52
  if (!orderAttrib)
33
53
  return;
@@ -73,9 +93,9 @@ function onBlurInserter() {
73
93
  }
74
94
  </script>
75
95
 
76
- {#each objects as item (item.Id)}
96
+ {#each objects as item, idx (item.Id)}
77
97
  {#key item} <!-- Forces to fully rerender when item changed to fire use: callbacks again -->
78
- <slot {item}/>
98
+ <slot {item} {idx}/>
79
99
  {/key}
80
100
  {/each }
81
101
 
@@ -9,6 +9,7 @@ declare const __propDef: {
9
9
  MIN_ORDER?: 0 | undefined;
10
10
  reload?: ((_objects: object[]) => void) | undefined;
11
11
  moveUp?: ((element: object) => void) | undefined;
12
+ moveTop?: ((element: object) => void) | undefined;
12
13
  moveDown?: ((element: object) => void) | undefined;
13
14
  add?: ((onAddHandler: Function) => Promise<void>) | undefined;
14
15
  };
@@ -18,6 +19,7 @@ declare const __propDef: {
18
19
  slots: {
19
20
  default: {
20
21
  item: object;
22
+ idx: any;
21
23
  };
22
24
  };
23
25
  };
@@ -29,6 +31,7 @@ export default class Sidebar extends SvelteComponentTyped<SidebarProps, SidebarE
29
31
  get MIN_ORDER(): 0;
30
32
  get reload(): (_objects: object[]) => void;
31
33
  get moveUp(): (element: object) => void;
34
+ get moveTop(): (element: object) => void;
32
35
  get moveDown(): (element: object) => void;
33
36
  get add(): (onAddHandler: Function) => Promise<void>;
34
37
  }
@@ -75,7 +75,6 @@ function override_items_from_slot(...args) {
75
75
  last_tick_internal = definition.items_ticket;
76
76
  if (definition.items)
77
77
  items = definition.items;
78
- console.log("override_items_from_slot", definition.items, definition.items_ticket);
79
78
  }
80
79
  return 0;
81
80
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humandialog/forms.svelte",
3
- "version": "0.5.20",
3
+ "version": "0.5.22",
4
4
  "description": "Basic Svelte UI components for Object Reef applications",
5
5
  "devDependencies": {
6
6
  "@playwright/test": "^1.28.1",
package/utils.js CHANGED
@@ -105,13 +105,15 @@ export function editable(node, params)
105
105
  let active = false;
106
106
  let onRemove = undefined;
107
107
  let onFinish = undefined;
108
+ let onSoftEnter = undefined;
108
109
  if(params instanceof Object)
109
110
  {
110
111
  action = params.action ?? params;
111
112
  active = params.active ?? false;
112
113
  onRemove = params.remove ?? undefined
113
114
  onFinish = params.onFinish ?? undefined
114
-
115
+ onSoftEnter = params.onSoftEnter ?? undefined;
116
+
115
117
  if(params.readonly)
116
118
  return;
117
119
  }
@@ -131,7 +133,7 @@ export function editable(node, params)
131
133
  if(observer)
132
134
  observer.disconnect();
133
135
 
134
- await finish_editing(cancel, false);
136
+ await finish_editing({cancel: cancel});
135
137
  }
136
138
 
137
139
  const key_listener = async (e) =>
@@ -146,7 +148,7 @@ export function editable(node, params)
146
148
  e.stopPropagation();
147
149
  e.preventDefault();
148
150
 
149
- await finish_editing(true, false);
151
+ await finish_editing({ cancel: true });
150
152
  }
151
153
  break;
152
154
 
@@ -154,7 +156,10 @@ export function editable(node, params)
154
156
  e.stopPropagation();
155
157
  e.preventDefault();
156
158
 
157
- await finish_editing(false, true);
159
+ if(e.shiftKey && onSoftEnter)
160
+ await finish_editing({ softEnter: true});
161
+ else
162
+ await finish_editing({ incremental: true});
158
163
  break;
159
164
 
160
165
  case 'Backspace':
@@ -162,15 +167,19 @@ export function editable(node, params)
162
167
  {
163
168
  e.stopPropagation();
164
169
  e.preventDefault();
165
- //await finish_editing(false, false);
166
170
  onRemove();
167
171
  }
168
172
  break;
169
173
  }
170
174
  }
171
175
 
172
- const finish_editing = async (cancel, incremental) =>
176
+ //const finish_editing = async (softEnter, cancel, incremental) =>
177
+ const finish_editing = async (params) =>
173
178
  {
179
+ const softEnter = params.softEnter ?? false;
180
+ const cancel = params.cancel ?? false;
181
+ const incremental = params.incremental ?? false;
182
+
174
183
  if(!active)
175
184
  {
176
185
  node.removeEventListener("blur", blur_listener);
@@ -186,6 +195,10 @@ export function editable(node, params)
186
195
  {
187
196
  node.innerHTML = org_text;
188
197
  }
198
+ else if(softEnter)
199
+ {
200
+ onSoftEnter(node.textContent)
201
+ }
189
202
  else if(action)
190
203
  {
191
204
  if(active)
@@ -202,7 +215,8 @@ export function editable(node, params)
202
215
  detail:
203
216
  {
204
217
  cancel: cancel,
205
- incremental: incremental
218
+ incremental: incremental,
219
+ softEnter: softEnter
206
220
  }
207
221
  });
208
222