@humandialog/forms.svelte 1.8.0 → 1.8.2

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.
@@ -11,11 +11,13 @@ import {
11
11
  informModification,
12
12
  pushChanges,
13
13
  startEditing,
14
- Ricon
14
+ Ricon,
15
+ focusEditable
15
16
  } from "../../..";
16
17
  import { FaRegFileAlt } from "svelte-icons/fa";
17
18
  import Properties from "./kanban.props.svelte";
18
19
  import { KanbanCardTop, KanbanCardMiddle, KanbanCardBottom } from "../Kanban";
20
+ import Editable from "../../r.editable.svelte";
19
21
  export let item;
20
22
  let definition = getContext("rKanban-definition");
21
23
  $:
@@ -97,28 +99,15 @@ function setSelectionAtEnd(element) {
97
99
  let topProps;
98
100
  let middleProps;
99
101
  let bottomProps;
100
- let titleElement;
101
- let summaryElement;
102
102
  let summaryPlaceholder = false;
103
103
  export async function editProperty(field) {
104
104
  if (field == "Title") {
105
- if (isLinkLike) {
106
- startEditing(titleElement);
107
- } else {
108
- titleElement.focus();
109
- await tick();
110
- setSelectionAtEnd(titleElement);
111
- }
105
+ focusEditable("#__or_kanban_ctrl_Title");
112
106
  } else if (field == "Summary") {
113
- if (!!summaryElement) {
114
- summaryElement.focus();
115
- await tick();
116
- setSelectionAtEnd(summaryElement);
117
- } else {
107
+ if (!focusEditable("#__or_kanban_ctrl_Summary")) {
118
108
  summaryPlaceholder = true;
119
109
  await tick();
120
- if (!!summaryElement)
121
- summaryElement.focus();
110
+ focusEditable("#__or_kanban_ctrl_Summary");
122
111
  }
123
112
  } else {
124
113
  const property = definition.properties.find((p) => p.name == field);
@@ -209,23 +198,22 @@ function showAttachementIcon() {
209
198
  {@const showIcon = showAttachementIcon()}
210
199
  <!-- whitespace-nowrap overflow-clip -->
211
200
  <h4 class = "font-semibold relative"
212
- use:editable={{
213
- action: (text) => onTitleChanged(text),
214
- active: false,
215
- readonly: definition.titleReadOnly,
216
- onFinish: (d) => {titleElement.blur()},
217
- onSoftEnter: async (text) => { onTitleChanged(text); await editProperty('Summary') }
218
- }}
219
201
  use:conditionalClick={{
220
202
  condition: hasOpen,
221
- callback: performOpen}}
222
- bind:this={titleElement}>
203
+ callback: performOpen}}>
223
204
  {#if isLinkLike}
224
205
  <a class= "font-semibold" href={getHRef()} use:link>
225
- {item[definition.titleAttrib]}
206
+ <Editable self={item}
207
+ a={definition.titleAttrib}
208
+ readonly={definition.titleReadOnly}
209
+ focusOnClick={false}
210
+ id="__or_kanban_ctrl_Title"/>
226
211
  </a>
227
212
  {:else}
228
- {item[definition.titleAttrib]}
213
+ <Editable self={item}
214
+ a={definition.titleAttrib}
215
+ readonly={definition.titleReadOnly}
216
+ id="__or_kanban_ctrl_Title"/>
229
217
  {/if}
230
218
 
231
219
 
@@ -258,13 +246,9 @@ function showAttachementIcon() {
258
246
  {#if item[definition.summaryAttrib] || summaryPlaceholder}
259
247
  {#key item[definition.summaryAttrib]}
260
248
  {#if isCardActive}
261
- <figcaption use:editable={{
262
- action: (text) => onSummaryChanged(text),
263
- active: true,
264
- readonly: definition.summaryReadOnly,
265
- onFinish: (d) => {summaryPlaceholder = false}}}
266
- bind:this={summaryElement}>
267
- {item[definition.summaryAttrib]}
249
+ <figcaption><Editable self={item}
250
+ a={definition.summaryAttrib}
251
+ id="__or_kanban_ctrl_Summary"/>
268
252
  </figcaption>
269
253
  {:else}
270
254
  <figcaption>
@@ -432,7 +432,7 @@ export function add(item, columnIdx = -1) {
432
432
  {#key renderToken}
433
433
  <slot/> <!-- Launch definition settings -->
434
434
 
435
- <figure class="px-4">
435
+ <figure class="px-0 sm:px-4">
436
436
  <h1><Editable self={self} a={title}/></h1>
437
437
  <figcaption><Editable self={self} a={summary}/></figcaption>
438
438
  </figure>
@@ -8,7 +8,8 @@ import {
8
8
  editable,
9
9
  startEditing,
10
10
  addActiveItem,
11
- removeActiveItem
11
+ removeActiveItem,
12
+ focusEditable
12
13
  } from "../../../utils";
13
14
  import { showGridMenu, showMenu } from "../../menu";
14
15
  import { pushChanges, informModification } from "../../../updates";
@@ -16,12 +17,10 @@ import { isDeviceSmallerThan } from "../../../utils";
16
17
  import Circle from "../../ricons/circle.svelte";
17
18
  import CircleCheck from "../../ricons/circle-check.svelte";
18
19
  import Ricon from "../../r.icon.svelte";
19
- import Spinner from "../../delayed.spinner.svelte";
20
20
  import { rList_definition, rList_property_type } from "../List";
21
21
  import { push, link } from "svelte-spa-router";
22
- import { FaExternalLinkAlt, FaRegCircle, FaRegCheckCircle } from "svelte-icons/fa/";
23
- import Tags from "../../tags.svelte";
24
22
  import { ext } from "../../../i18n";
23
+ import Editable from "../../r.editable.svelte";
25
24
  export let item;
26
25
  export let element_title = "";
27
26
  export let list_properties = void 0;
@@ -188,28 +187,11 @@ export function editProperty(field) {
188
187
  }
189
188
  }
190
189
  async function force_editing(field) {
191
- let element_id = `__or_list_ctrl_${getItemKey(item)}_${field}`;
192
- let element_node = document.getElementById(element_id);
193
- if (!element_node) {
190
+ let element_id = `#__or_list_ctrl_${getItemKey(item)}_${field}`;
191
+ if (!focusEditable(element_id)) {
194
192
  placeholder = field;
195
193
  await tick();
196
- element_node = document.getElementById(element_id);
197
- if (!element_node)
198
- return;
199
- }
200
- if (!element_node.classList.contains("editable")) {
201
- return;
202
- }
203
- if (field == "Title") {
204
- if (is_link_like) {
205
- startEditing(element_node, () => {
206
- placeholder = "";
207
- });
208
- } else {
209
- element_node.focus();
210
- }
211
- } else {
212
- element_node.focus();
194
+ focusEditable(element_id);
213
195
  }
214
196
  }
215
197
  function setSelectionAtEnd(element) {
@@ -416,36 +398,30 @@ async function onDownloadFile(e) {
416
398
  href={element_href}
417
399
  on:click={onDownloadFile}>
418
400
 
419
- <h4 class="-indent-8"
420
- id="__or_list_ctrl_{getItemKey(item)}_Title"
421
- use:editable={{
422
- action: (text) => {change_property(element_title, text)},
423
- active: false,
424
- readonly: title_readonly,
425
- onSoftEnter: (text) => {change_name(text); editProperty('Summary')}
426
- }}>
401
+ <h4 class="-indent-8">
427
402
  <div class="inline-block w-4 h-4 ml-0 mr-4 align-baseline
428
403
  text-stone-700 dark:text-stone-400 ">
429
404
  <Ricon icon={isDownloading ? 'loader-circle' : element_icon} />
430
- </div>{translated_element_title}
405
+ </div><Editable self={item}
406
+ a={element_title}
407
+ id="__or_list_ctrl_{getItemKey(item)}_Title"
408
+ readonly={title_readonly}
409
+ focusOnClick={false}/>
431
410
  </h4>
432
411
  </a>
433
412
  {:else if element_href}
434
413
  <a class="sm:hover:cursor-pointer"
435
414
  href={element_href} use:link>
436
415
 
437
- <h4 class="-indent-8 "
438
- id="__or_list_ctrl_{getItemKey(item)}_Title"
439
- use:editable={{
440
- action: (text) => {change_property(element_title, text)},
441
- active: false,
442
- readonly: title_readonly,
443
- onSoftEnter: (text) => {change_name(text); editProperty('Summary')}
444
- }}>
416
+ <h4 class="-indent-8 ">
445
417
  <div class="inline-block w-4 h-4 ml-0 mr-4 align-baseline
446
418
  text-stone-700 dark:text-stone-400 ">
447
419
  <Ricon icon={element_icon} />
448
- </div>{translated_element_title}
420
+ </div><Editable self={item}
421
+ a={element_title}
422
+ id="__or_list_ctrl_{getItemKey(item)}_Title"
423
+ readonly={title_readonly}
424
+ focusOnClick={false}/>
449
425
  </h4>
450
426
  </a>
451
427
  {:else if element_open_handler}
@@ -453,33 +429,26 @@ async function onDownloadFile(e) {
453
429
  href="/#"
454
430
  on:click|preventDefault={() => element_open_handler(item)}>
455
431
 
456
- <h4 class="-indent-8"
457
- id="__or_list_ctrl_{getItemKey(item)}_Title"
458
- use:editable={{
459
- action: (text) => {change_property(element_title, text)},
460
- active: false,
461
- readonly: title_readonly,
462
- onSoftEnter: (text) => {change_name(text); editProperty('Summary')}
463
- }}>
432
+ <h4 class="-indent-8">
464
433
  <div class="inline-block w-4 h-4 ml-0 mr-4 align-baseline
465
434
  text-stone-700 dark:text-stone-400 ">
466
435
  <Ricon icon={element_icon} />
467
- </div>{translated_element_title}
436
+ </div><Editable self={item}
437
+ a={element_title}
438
+ id="__or_list_ctrl_{getItemKey(item)}_Title"
439
+ readonly={title_readonly}
440
+ focusOnClick={false}/>
468
441
  </h4>
469
442
  </a>
470
443
  {:else}
471
- <h4 class="-indent-8 "
472
- id="__or_list_ctrl_{getItemKey(item)}_Title"
473
- use:editable={{
474
- action: (text) => {change_property(element_title, text)},
475
- active: false,
476
- readonly: title_readonly,
477
- onSoftEnter: (text) => {change_name(text); editProperty('Summary')}
478
- }}>
444
+ <h4 class="-indent-8">
479
445
  <div class="inline-block w-4 h-4 ml-0 mr-4 align-baseline
480
446
  text-stone-700 dark:text-stone-400 ">
481
447
  <Ricon icon={element_icon} />
482
- </div>{translated_element_title}
448
+ </div><Editable self={item}
449
+ a={element_title}
450
+ id="__or_list_ctrl_{getItemKey(item)}_Title"
451
+ readonly={title_readonly}/>
483
452
  </h4>
484
453
  {/if}
485
454
 
@@ -493,25 +462,14 @@ async function onDownloadFile(e) {
493
462
  </figcaption>
494
463
  -------------------------------->
495
464
 
496
- {#if summary && (item[summary])}
497
- <figcaption id="__or_list_ctrl_{getItemKey(item)}_Summary" use:editable={{
498
- action: (text) => {change_property(summary, text)},
499
- readonly: summary_readonly,
500
- onFinish: (d) => {placeholder='';},
501
- active: true
502
- }}>{item[summary]}
503
- </figcaption>
504
-
505
- {:else if placeholder=='Summary'}
506
- <figcaption id="__or_list_ctrl_{getItemKey(item)}_Summary"
507
- use:editable={{
508
- action: (text) => {change_property(summary, text)},
509
- readonly: summary_readonly,
510
- onFinish: (d) => {placeholder='';},
511
- active: true
512
- }}>&nbsp;
465
+ {#if (summary && (item[summary])) || (placeholder=='Summary')}
466
+ <figcaption><Editable self={item}
467
+ a={summary}
468
+ id="__or_list_ctrl_{getItemKey(item)}_Summary"
469
+ readonly={summary_readonly} />
513
470
  </figcaption>
514
471
  {/if}
472
+
515
473
  </figure>
516
474
  </div>
517
475
 
@@ -59,39 +59,3 @@ async function onSummaryChanged(text) {
59
59
  {/if}
60
60
  </figure>
61
61
 
62
-
63
- <!--section class=" my-1 w-full text-base text-stone-700 dark:text-stone-400 cursor-default rounded-md border border-transparent bg-stone-200 dark:bg-stone-700">
64
- <div class="flex flex-row">
65
- {#if icon}
66
-
67
- <div class="h-5 w-5 sm:h-4 sm:w-4 mt-2 sm:mt-1.5 ml-2"></div>
68
- {/if}
69
-
70
- <p class=" ml-3 py-1
71
- text-base font-semibold min-h-[1.75rem]
72
- sm:min-h-[1.25rem]
73
- whitespace-nowrap overflow-clip flex-none w-1/2 sm:w-1/3" tabindex="0"
74
- bind:this={titleElement}
75
- use:editable={{
76
- action: (text) => onInsert(text, ''),
77
- active: false,
78
- onSoftEnter: softEnter
79
- }} >
80
- </p>
81
- </div>
82
-
83
- {#if editSummary}
84
- <p bind:this={summaryElement}
85
- class=" ml-10 sm:ml-9
86
- sm:min-h-[1rem]
87
- text-sm min-h-[1.5rem]
88
- text-stone-400"
89
- use:editable={{
90
- action: onSummaryChanged,
91
- active: false,
92
- onFinish: (d) => {editSummary=false}
93
- }}>
94
- {summary}
95
- </p>
96
- {/if}
97
- </section-->
@@ -411,10 +411,7 @@ function read_from_def(propName) {
411
411
  {selectionKey}
412
412
  bind:this={rows[i]}
413
413
  >
414
-
415
- <span slot="left" let:element>
416
- <slot name="left" {element}/>
417
- </span>
414
+
418
415
  </ListElement>
419
416
 
420
417
  {#if show_insertion_row_after_element == element}
@@ -43,9 +43,6 @@ declare const __propDef: {
43
43
  };
44
44
  slots: {
45
45
  default: {};
46
- left: {
47
- element: any;
48
- };
49
46
  };
50
47
  };
51
48
  export type ListProps = typeof __propDef.props;
@@ -2,6 +2,7 @@
2
2
  import {editable, makeEditableIdFromFieldName} from '../utils'
3
3
  import {setjItemProperty} from '../updates.js'
4
4
  import { afterUpdate } from 'svelte';
5
+ import {ext} from '../i18n'
5
6
 
6
7
  export let self
7
8
  export let a
@@ -63,9 +64,7 @@
63
64
  }}
64
65
  on:focus={focus}
65
66
  on:blur={blur}
66
- >
67
- {self[a]}
68
- </span>
67
+ >{ext(self[a])}</span>
69
68
 
70
69
  <!--style>
71
70
  span:empty:focus::before {
package/desk.svelte CHANGED
@@ -79,29 +79,19 @@
79
79
 
80
80
  $: { visible_sidebar = $main_sidebar_visible_store
81
81
  const navMode = navGetMode()
82
- if(navMode == NAV_MODE_SIDEBAR)
82
+ if(visible_sidebar == "*")
83
83
  {
84
- if(visible_sidebar == "*")
85
- {
86
- main_side_panel_visibility = "hidden"
87
- lg_content_area_horizontal_dim = ""
88
- lg_content_area_horizontal_tools_dim = `sm:left-[50px] sm:w-[calc(100vw-60px)]`
89
- }
90
- else
91
- {
92
- main_side_panel_visibility = "fixed lg:block"
93
- lg_content_area_horizontal_dim = `lg:left-[360px] lg:w-[calc(100vw-360px)]`
94
- lg_content_area_horizontal_tools_dim = `sm:left-[50px] sm:w-[calc(100vw-60px)] lg:left-[368px] lg:w-[calc(100vw-376px)]`
95
- }
84
+ main_side_panel_visibility = "hidden"
85
+ lg_content_area_horizontal_dim = ""
86
+ lg_content_area_horizontal_tools_dim = `sm:left-[50px] sm:w-[calc(100vw-60px)]`
96
87
  }
97
88
  else
98
89
  {
99
- main_side_panel_visibility = "hidden"
100
- lg_content_area_horizontal_dim = ""
90
+ main_side_panel_visibility = "fixed block"
91
+ lg_content_area_horizontal_dim = `lg:left-[360px] lg:w-[calc(100vw-360px)]`
92
+ lg_content_area_horizontal_tools_dim = `sm:left-[50px] sm:w-[calc(100vw-60px)] lg:left-[368px] lg:w-[calc(100vw-376px)]`
93
+ }
101
94
  }
102
-
103
- //console.log('main_side_panel_visibility', main_side_panel_visibility)
104
- }
105
95
 
106
96
  let tools_visibility = "hidden"
107
97
  let tools_visible = false
@@ -399,15 +389,25 @@
399
389
 
400
390
 
401
391
  <!--#######################################################-->
402
- <!--## VERTICAL TOOLBAR ##################-->
392
+ <!--## VERTICAL DESKTOP MAIN TOOLBAR ##################-->
403
393
  <!--#######################################################-->
404
- <div class="hidden sm:block fixed left-0 top-[50px] sm:top-0 w-[40px] h-screen z-20 inset-0 overflow-hidden">
394
+ <div class="hidden sm:block
395
+ fixed left-0 top-0 w-[40px] h-screen z-20
396
+ inset-0 overflow-hidden">
397
+
405
398
  <div class="sticky top-0 flex h-full w-12 sm:w-10 bg-stone-800 dark:bg-stone-950 flex-col items-center text-stone-100 shadow">
406
399
  <VerticalToolbar appConfig={layout} mobile={false}/>
407
400
  </div>
408
401
  </div>
402
+ <!--#######################################################-->
403
+ <!--## VERTICAL MOBILE MAIN TOOLBAR ##################-->
404
+ <!--#######################################################-->
405
+
406
+ <header class=" mobile-main-toolbar block sm:hidden
407
+ fixed w-screen bottom-0 h-[50px] z-20
408
+ shadow shadow-stone-900/5 dark:shadow-none
409
+ overflow-auto" >
409
410
 
410
- <header class="block sm:hidden fixed w-screen bottom-0 h-[50px] sm:h-[40px] z-20 shadow shadow-stone-900/5 dark:shadow-none overflow-auto" >
411
411
  <div class=" flex flex-row justify-between h-full
412
412
  text-stone-500 bg-stone-200/70 hover:bg-stone-200
413
413
  dark:text-orange-200 dark:bg-stone-700/70 dark:hover:bg-stone-700
@@ -426,15 +426,16 @@
426
426
  {@const sidebar_small_width = $sidebar_left_pos==0 ? "w-full" : "w-[calc(100vw-50px)]"}
427
427
 
428
428
  <div class="main-side-bar {main_side_panel_visibility}
429
- left-0 top-0 sm:left-[40px]
430
- top-0
429
+
430
+ left-0 bottom-[50px]
431
+ sm:left-[40px] sm:top-0
431
432
  w-full sm:w-[320px]
432
- h-[calc(100vh-50px)] sm:h-full {lg_main_sidebar_height}
433
+ h-[calc(100svh-50px)] sm:h-full
433
434
 
434
- z-20 overflow-x-hidden
435
+ z-30 overflow-x-hidden
435
436
 
436
437
  bg-stone-50 dark:bg-stone-900
437
- sm:border-r border-stone-300 dark:border-stone-300/50
438
+ border-t sm:border-t-0 sm:border-r border-stone-300 dark:border-stone-300/50
438
439
  sm:shadow-lg sm:shadow-stone-500
439
440
  sm:dark:shadow-black">
440
441
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humandialog/forms.svelte",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
4
4
  "description": "Basic Svelte UI components for Object Reef applications",
5
5
  "devDependencies": {
6
6
  "@playwright/test": "^1.28.1",
package/updates.js CHANGED
@@ -203,7 +203,7 @@ update_request_ticket.subscribe(async (v) => {
203
203
  {
204
204
  modified_items_map.clear();
205
205
  unsavedModificationsTicket.set( get(unsavedModificationsTicket) + 1 )
206
-
206
+
207
207
  afterPushCallbacks.forEach( cb => cb())
208
208
  afterPushCallbacks = []
209
209
  }
package/utils.js CHANGED
@@ -366,8 +366,8 @@ export function editable(node, params)
366
366
 
367
367
  let observer = null;
368
368
  let has_changed = false;
369
+ let org_text = '';
369
370
 
370
- const org_text = node.textContent;
371
371
  const blur_listener = async (e) =>
372
372
  {
373
373
  if(currentEditable == node)
@@ -403,13 +403,9 @@ export function editable(node, params)
403
403
  {
404
404
  case 'Esc':
405
405
  case 'Escape':
406
- if(!active)
407
- {
408
- e.stopPropagation();
409
- e.preventDefault();
410
-
411
- await finish_editing({ cancel: true });
412
- }
406
+ e.stopPropagation();
407
+ e.preventDefault();
408
+ await finish_editing({ cancel: true });
413
409
  break;
414
410
 
415
411
  case 'Enter':
@@ -447,16 +443,17 @@ export function editable(node, params)
447
443
  const cancel = params.cancel ?? false;
448
444
  const incremental = params.incremental ?? false;
449
445
 
446
+ node.removeEventListener("blur", blur_listener);
447
+ node.removeEventListener("keydown", key_listener);
448
+ node.removeEventListener("save", save_listener);
449
+
450
450
  if(!active)
451
- {
452
- node.removeEventListener("blur", blur_listener);
453
- node.removeEventListener("keydown", key_listener);
454
- node.removeEventListener("save", save_listener);
455
451
  node.contentEditable = "false"
452
+ else
453
+ node.blur()
456
454
 
457
- let sel = window.getSelection();
458
- sel.removeAllRanges();
459
- }
455
+ let sel = window.getSelection();
456
+ sel.removeAllRanges();
460
457
 
461
458
  if(cancel)
462
459
  {
@@ -468,17 +465,11 @@ export function editable(node, params)
468
465
  }
469
466
  else if(action)
470
467
  {
471
- if(active)
468
+ if(has_changed)
472
469
  {
473
- if(has_changed)
474
- {
475
- has_changed = false;
476
- await action(node.textContent)
477
- }
478
-
479
- }
480
- else
470
+ has_changed = false;
481
471
  await action(node.textContent)
472
+ }
482
473
  }
483
474
 
484
475
  const finish_event = new CustomEvent("finish", {
@@ -505,12 +496,6 @@ export function editable(node, params)
505
496
  const edit_listener = async (e) =>
506
497
  {
507
498
  node.contentEditable = "true"
508
- node.addEventListener("blur", blur_listener);
509
- node.addEventListener("keydown", key_listener);
510
-
511
- currentEditable = node;
512
- node.addEventListener("save", save_listener)
513
-
514
499
  node.focus();
515
500
 
516
501
  /*await tick();
@@ -543,6 +528,8 @@ export function editable(node, params)
543
528
  onSingleChange(node.textContent)
544
529
  });
545
530
 
531
+ org_text = node.textContent;
532
+
546
533
  observer.observe( node, {
547
534
  childList: true,
548
535
  attributes: true,
@@ -553,28 +540,26 @@ export function editable(node, params)
553
540
  node.classList.add("editable")
554
541
  node.classList.add("focus:outline-none")
555
542
 
543
+ node.addEventListener('focus', focus_listener);
544
+ node.addEventListener("edit", edit_listener);
545
+
546
+ if(onFinish)
547
+ node.addEventListener("finish", (e) => { onFinish(e.detail) })
548
+
556
549
  if(active)
557
- {
558
550
  node.contentEditable = "true"
559
- node.addEventListener('focus', focus_listener);
560
-
561
- if(onFinish)
562
- {
563
- node.addEventListener("finish", (e) => { onFinish(e.detail) })
564
- }
565
- }
566
- else
567
- {
568
- node.addEventListener("edit", edit_listener);
551
+
552
+ return {
553
+ destroy() {
569
554
 
570
- return {
571
- destroy() {
555
+ node.removeEventListener("edit", edit_listener)
556
+ node.removeEventListener('focus', focus_listener);
557
+ if(onFinish)
558
+ node.removeEventListener("finish", (e) => { onFinish(e.detail) })
572
559
 
573
- node.removeEventListener("edit", edit_listener)
574
- node.classList.remove("editable")
575
- node.contentEditable = "false"
576
- }};
577
- }
560
+ node.classList.remove("editable")
561
+
562
+ }};
578
563
  }
579
564
 
580
565
  export function startEditing(element, finish_callback)