@humandialog/forms.svelte 1.4.4 → 1.4.5

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.
@@ -238,18 +238,19 @@ function operationVisible(operation) {
238
238
  {@const position = calculatePosition(operation)}
239
239
  {#if position}
240
240
  <button
241
- class="text-white bg-blue-700/70 hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300
241
+ class="text-stone-700 bg-stone-300/70 hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300
242
242
  font-medium rounded-full text-sm text-center shadow-md
243
- w-[35px] h-[35px]
243
+ w-[30px] h-[30px]
244
244
  fixed m-0
245
- dark:bg-blue-600/50 dark:hover:bg-blue-700 dark:focus:ring-blue-800
245
+ dark:text-stone-400
246
+ dark:bg-stone-700/50 dark:hover:bg-blue-700 dark:focus:ring-blue-800
246
247
  flex items-center justify-center
247
248
  disable-dbl-tap-zoom
248
249
  cursor-pointer z-40"
249
250
  style={position}
250
251
  on:click|stopPropagation={(e) => {on_click(e, operation)}}
251
252
  on:mousedown={mousedown} >
252
- <div class="w-5 h-5"><svelte:component this={operation.icon}/></div>
253
+ <div class="w-5 h-5"><svelte:component this={operation.icon}/></div>
253
254
  </button>
254
255
  {/if}
255
256
  {/if}
@@ -375,7 +376,8 @@ function operationVisible(operation) {
375
376
  on:mousedown={mousedown}>
376
377
  {#if operation.caption}
377
378
  <div>
378
- <span class="block whitespace-nowrap text-sm mt-3 font-semibold text-white mr-3 select-none bg-stone-700 group-hover:bg-stone-800 px-1 shadow-lg rounded">{operation.caption}</span>
379
+ <span class="block whitespace-nowrap text-sm mt-3 font-semibold text-white mr-3
380
+ select-none bg-stone-700 group-hover:bg-stone-800 px-1 shadow-lg rounded">{operation.caption}</span>
379
381
  </div>
380
382
  {/if}
381
383
  <button class=" bg-transparent
@@ -71,12 +71,12 @@ function calculatePosition(x2, y2, around, visible2, fresh) {
71
71
  }
72
72
  let yShifted = false;
73
73
  if (myRect.bottom > screenRect.bottom) {
74
- y2 = screenRect.bottom - myRect.height - m;
74
+ y2 = screenRect.bottom - myRect.height;
75
75
  if (around) {
76
76
  if (xShifted)
77
77
  x2 -= around.width;
78
78
  else
79
- y2 -= around.height - m;
79
+ y2 -= around.height;
80
80
  }
81
81
  yShifted = true;
82
82
  }
@@ -85,7 +85,7 @@ function calculatePosition(x2, y2, around, visible2, fresh) {
85
85
  if (myRect.top < screenRect.top)
86
86
  y2 = screenRect.top;
87
87
  }
88
- result = `left:${x2}px; top:${y2}px; display: block`;
88
+ result = `left:${x2}px; top:${y2}px; display: block; min-width: 15rem`;
89
89
  }
90
90
  return result;
91
91
  }
@@ -144,7 +144,7 @@ export function hide() {
144
144
  visible = false;
145
145
  css_position = calculatePosition(x, y, around_rect, false, false);
146
146
  window.removeEventListener("click", on_before_window_click, true);
147
- menu_root.removeEventListener("click", on_before_container_click, true);
147
+ menu_root?.removeEventListener("click", on_before_container_click, true);
148
148
  }
149
149
  export function getRenderedRect() {
150
150
  if (menu_root)
@@ -188,24 +188,12 @@ function on_keydown(e, operation, index) {
188
188
  }
189
189
  }
190
190
  function navigate_up() {
191
- let index = focused_index;
192
- while (index > 0 && menu_items.length > 0) {
193
- let prev_item = menu_items[--index];
194
- if (prev_item) {
195
- focus_menu_item(index);
196
- break;
197
- }
198
- }
191
+ let index = get_this_or_prev_valid_index(focused_index - 1);
192
+ focus_menu_item(index);
199
193
  }
200
194
  function navigate_down() {
201
- let index = focused_index;
202
- while (index + 1 < menu_items.length) {
203
- let next_item = menu_items[++index];
204
- if (next_item) {
205
- focus_menu_item(index);
206
- break;
207
- }
208
- }
195
+ let index = get_this_or_next_valid_index(focused_index + 1);
196
+ focus_menu_item(index);
209
197
  }
210
198
  function on_change_focus(e) {
211
199
  if (!isDeviceSmallerThan("sm")) {
@@ -251,11 +239,41 @@ function execute_action(e, operation, index) {
251
239
  }
252
240
  }
253
241
  }
242
+ function get_this_or_next_valid_index(index) {
243
+ if (!operations)
244
+ return 0;
245
+ if (operations.length == 0)
246
+ return 0;
247
+ if (index >= operations.length)
248
+ return operations.length - 1;
249
+ if (index < 0)
250
+ return 0;
251
+ const op = operations[index];
252
+ if (op.separator || op.disabled)
253
+ return get_this_or_next_valid_index(index + 1);
254
+ else
255
+ return index;
256
+ }
257
+ function get_this_or_prev_valid_index(index) {
258
+ if (!operations)
259
+ return 0;
260
+ if (operations.length == 0)
261
+ return 0;
262
+ if (index >= operations.length)
263
+ return operations.length - 1;
264
+ if (index < 0)
265
+ return 0;
266
+ const op = operations[index];
267
+ if (op.separator || op.disabled)
268
+ return get_this_or_prev_valid_index(index - 1);
269
+ else
270
+ return index;
271
+ }
254
272
  function focus_menu_item(index) {
255
273
  const operation = operations[index];
256
274
  if (operation.disabled)
257
275
  return;
258
- focused_index = index;
276
+ focused_index = get_this_or_next_valid_index(index);
259
277
  let element = menu_items[focused_index];
260
278
  element.focus();
261
279
  if (submenus && submenus.length) {
@@ -310,7 +328,7 @@ function calculateBackground(is_highlighted, active) {
310
328
  class=" bg-white dark:bg-stone-800
311
329
  text-stone-800 dark:text-stone-400 rounded-lg border
312
330
  border-stone-200 dark:border-stone-700 shadow-md
313
- z-30 fixed min-w-[{min_width_px}px] w-max overflow-y-auto"
331
+ z-30 fixed min-w-60 max-h-screen overflow-y-auto"
314
332
  style={css_position}
315
333
  bind:this={menu_root}>
316
334
 
@@ -181,8 +181,8 @@ let appearance_class;
181
181
  if (compact)
182
182
  appearance_class = "";
183
183
  else
184
- appearance_class = `bg-stone-50 border border-stone-300 rounded-md
185
- dark:bg-stone-700 dark:border-stone-600
184
+ appearance_class = `bg-stone-50 border border-stone-300 rounded-md
185
+ dark:bg-stone-700 dark:border-stone-600
186
186
  px-2.5`;
187
187
  let last_tick = -1;
188
188
  let lockNextBlurCallbacks = 0;
@@ -587,9 +587,9 @@ onMount(() => {
587
587
  TableCell,
588
588
  // custom
589
589
  CodeBlock,
590
- CommentBlock,
591
- WarningBlock,
592
- InfoBlock,
590
+ //CommentBlock,
591
+ //WarningBlock,
592
+ //InfoBlock,
593
593
  QuoteBlock,
594
594
  Bold,
595
595
  Code,
@@ -675,6 +675,7 @@ export function save() {
675
675
  if (saveData()) {
676
676
  last_tick = $data_tick_store + 1;
677
677
  $data_tick_store = last_tick;
678
+ refreshToolbarOperations();
678
679
  }
679
680
  }
680
681
  function saveData() {
@@ -988,6 +989,9 @@ export function preventBlur() {
988
989
  if (editor.isFocused)
989
990
  lockNextBlurCallbacks++;
990
991
  }
992
+ export function hasChanged() {
993
+ return hasChangedValue;
994
+ }
991
995
  const paletteMarksCommands = [
992
996
  { caption: "Bold", description: "Marks text as bolded", tags: "strong", icon: FaBold, on_choice: makeBold, is_active: () => editor?.isActive("bold") },
993
997
  { caption: "Italic", description: "Marks text as italic", tags: "strong", icon: FaItalic, on_choice: makeItalic, is_active: () => editor?.isActive("italic") },
@@ -1031,30 +1035,15 @@ const paletteStylesCommands = [
1031
1035
  else
1032
1036
  editor.chain().focus().setCodeBlock().run();
1033
1037
  }, is_active: () => editor?.isActive("CodeBlock") },
1034
- { caption: "Comment", description: "With this you can comment the above paragraph", icon: FaComment, on_choice: (range) => {
1035
- if (range)
1036
- editor.chain().focus().deleteRange(range).setAsComment().run();
1037
- else
1038
- editor.chain().focus().setAsComment().run();
1039
- }, is_active: () => editor?.isActive("CommentBlock") },
1038
+ // { caption: 'Comment', description: 'With this you can comment the above paragraph', icon: FaComment, on_choice: (range) => { if(range) editor.chain().focus().deleteRange(range).setAsComment().run(); else editor.chain().focus().setAsComment().run() }, is_active: () => editor?.isActive('CommentBlock') } ,
1040
1039
  { caption: "Quote", description: "To quote someone", icon: FaQuoteRight, on_choice: (range) => {
1041
1040
  if (range)
1042
1041
  editor.chain().focus().deleteRange(range).setAsQuote().run();
1043
1042
  else
1044
1043
  editor.chain().focus().setAsQuote().run();
1045
1044
  }, is_active: () => editor?.isActive("QuoteBlock") },
1046
- { caption: "Warning", description: "An important warning to above paragraph", icon: FaExclamationTriangle, on_choice: (range) => {
1047
- if (range)
1048
- editor.chain().focus().deleteRange(range).setAsWarning().run();
1049
- else
1050
- editor.chain().focus().setAsWarning().run();
1051
- }, is_active: () => editor?.isActive("WarningBlock") },
1052
- { caption: "Info", description: "An important info about above paragraph", icon: FaInfo, on_choice: (range) => {
1053
- if (range)
1054
- editor.chain().focus().deleteRange(range).setAsInfo().run();
1055
- else
1056
- editor.chain().focus().setAsInfo().run();
1057
- }, is_active: () => editor?.isActive("InfoBlock") },
1045
+ // { caption: 'Warning', description: 'An important warning to above paragraph', icon: FaExclamationTriangle, on_choice: (range) => { if(range) editor.chain().focus().deleteRange(range).setAsWarning().run(); else editor.chain().focus().setAsWarning().run() }, is_active: () => editor?.isActive('WarningBlock') } ,
1046
+ // { caption: 'Info', description: 'An important info about above paragraph', icon: FaInfo, on_choice: (range) => { if(range) editor.chain().focus().deleteRange(range).setAsInfo().run(); else editor.chain().focus().setAsInfo().run() }, is_active: () => editor?.isActive('InfoBlock') },
1058
1047
  { caption: "Bullet list", description: "Unordered list of items", icon: FaListUl, on_choice: (range) => {
1059
1048
  if (range)
1060
1049
  editor.chain().focus().deleteRange(range).toggleBulletList().run();
@@ -1202,18 +1191,18 @@ function getPaletteCommands() {
1202
1191
 
1203
1192
  <div bind:this={editorElement} />
1204
1193
 
1205
- <Palette commands={getPaletteCommands()}
1206
- bind:this={palette}
1194
+ <Palette commands={getPaletteCommands()}
1195
+ bind:this={palette}
1207
1196
  on:palette_shown={on_palette_shown}
1208
1197
  on:palette_hidden={on_palette_hidden}
1209
1198
  on:palette_mouse_click={on_palette_mouse_click}/>
1210
1199
 
1211
- <!--div contenteditable="true"
1200
+ <!--div contenteditable="true"
1212
1201
  bind:this={editorElement}
1213
1202
  on:keyup={on_keyup}
1214
1203
  on:keydown={on_keydown}
1215
1204
  on:mouseup={on_mouseup}
1216
- class="{cs} {appearance_class}
1205
+ class="{cs} {appearance_class}
1217
1206
  prose prose-base sm:prose-base dark:prose-invert {additional_class} overflow-y-auto whitespace-pre-wrap"
1218
1207
  on:blur={on_blur}
1219
1208
  on:focus={on_focus}
@@ -79,6 +79,7 @@ declare const __propDef: {
79
79
  isActiveTable?: (() => void) | undefined;
80
80
  isActiveHorizontalRule?: (() => boolean) | undefined;
81
81
  preventBlur?: (() => void) | undefined;
82
+ hasChanged?: (() => boolean) | undefined;
82
83
  };
83
84
  events: {
84
85
  [evt: string]: CustomEvent<any>;
@@ -147,5 +148,6 @@ export default class Editor extends SvelteComponentTyped<EditorProps, EditorEven
147
148
  get isActiveTable(): () => void;
148
149
  get isActiveHorizontalRule(): () => boolean;
149
150
  get preventBlur(): () => void;
151
+ get hasChanged(): () => boolean;
150
152
  }
151
153
  export {};
package/operations.svelte CHANGED
@@ -57,7 +57,8 @@ function update(...args) {
57
57
  caption: operationsRoot.caption ?? "",
58
58
  icon: operationsRoot.icon ?? FaEllipsisV,
59
59
  menu: allFlatOperations,
60
- tbr: operationsRoot.tbr
60
+ tbr: operationsRoot.tbr,
61
+ preAction: operationsRoot.preAction ?? void 0
61
62
  };
62
63
  switch (operationsRoot.tbr) {
63
64
  case "A":
@@ -121,9 +122,14 @@ function update(...args) {
121
122
  }
122
123
  hasOperations = leftOperations.length > 0 || rightOperations.length > 0;
123
124
  }
124
- function on_click(e, operation) {
125
+ function on_click(e, operation, isDisabled) {
125
126
  if (!operation)
126
127
  return;
128
+ if (isDisabled) {
129
+ e.preventDefault();
130
+ e.stopPropagation();
131
+ return;
132
+ }
127
133
  let owner = e.target;
128
134
  while (owner && owner.tagName != "BUTTON")
129
135
  owner = owner.parentElement;
@@ -143,8 +149,9 @@ function on_click(e, operation) {
143
149
  else if (operation.grid)
144
150
  showGridMenu(rect, operation.grid);
145
151
  }
146
- function mousedown(e) {
152
+ function mousedown(e, operation) {
147
153
  e.preventDefault();
154
+ e.stopPropagation();
148
155
  }
149
156
  function isOperationActivated(operation) {
150
157
  if (operation.activeFunc)
@@ -152,29 +159,38 @@ function isOperationActivated(operation) {
152
159
  else
153
160
  return operation.active ?? false;
154
161
  }
162
+ function isOperationDisabled(operation) {
163
+ if (operation.disabledFunc)
164
+ return operation.disabledFunc();
165
+ else
166
+ return operation.disabled ?? false;
167
+ }
155
168
  </script>
156
169
 
157
170
  {#if hasOperations}
158
- <section class="flex flex-row no-print h-10 bg-stone-50 dark:bg-stone-950 overflow-x-clip overflow-y-hidden py-0 text-xs whitespace-nowrap">
171
+ <section class="flex flex-row no-print h-10 bg-stone-50 dark:bg-stone-950 overflow-x-hidden overflow-y-clip py-0 text-xs whitespace-nowrap">
159
172
  <div class="flex flex-row"
160
173
  class:flex-row-reverse={mobile}>
161
174
 
162
175
  {#each leftOperations as operation}
163
176
  {#if !operation.separator}
164
177
  {@const isActive=isOperationActivated(operation)}
178
+ {@const isDisabled=isOperationDisabled(operation)}
165
179
  {#if operation.toolbox}
166
180
  {#each operation.toolbox as operation}
181
+ {@const textColor= isDisabled ? 'text-stone-600 dark:text-stone-500' : 'text-stone-800 dark:text-stone-300 dark:hover:text-white '}
167
182
  <button type="button"
168
- class="py-2.5 px-4
183
+ class="py-2.5 px-1
169
184
  text-xs font-thin
170
- text-stone-800 hover:bg-stone-700 active:bg-stone-300 border-stone-200
171
- dark:text-stone-300 dark:hover:text-white dark:hover:bg-stone-800 dark:active:bg-stone-600 dark:border-stone-600
185
+ {textColor}
186
+ hover:bg-stone-700 active:bg-stone-300 border-stone-200
187
+ dark:hover:bg-stone-800 dark:active:bg-stone-600 dark:border-stone-600
172
188
  focus:outline-none
173
189
  inline-flex items-center"
174
190
  class:bg-stone-700={isActive}
175
191
  class:dark:bg-stone-800={isActive}
176
- on:click={(e) => {on_click(e, operation)}}
177
- on:mousedown={mousedown}>
192
+ on:mousedown={(e) => mousedown(e, operation)}
193
+ on:click={(e) => {on_click(e, operation, isDisabled)}}>
178
194
  {#if operation.icon}
179
195
  <div class="w-5 h-5 mr-1"><svelte:component this={operation.icon}/></div>
180
196
  {/if}
@@ -184,18 +200,27 @@ function isOperationActivated(operation) {
184
200
  </button>
185
201
  {/each}
186
202
  {:else}
203
+ {@const enabledLightColors ='text-stone-600 hover:text-stone-800 hover:bg-stone-200 active:bg-stone-200 border-stone-200'}
204
+ {@const disabledLightColors ='text-stone-400 border-stone-200'}
205
+
206
+ {@const enabledDarkColors ='dark:text-stone-300 dark:hover:text-white dark:hover:bg-stone-800 dark:active:bg-stone-600 dark:border-stone-600'}
207
+ {@const disabledDarkColors ='dark:text-stone-500 dark:border-stone-600'}
208
+
209
+ {@const disabledColors =`${disabledLightColors} ${disabledDarkColors}`}
210
+ {@const enabledColors =`${enabledLightColors} ${enabledDarkColors}`}
211
+ {@const colors = isDisabled ? disabledColors : enabledColors}
187
212
 
188
213
  <button type="button"
189
- class="py-2.5 px-4
214
+ class="py-2.5 px-2
190
215
  text-xs font-thin
191
- text-stone-600 hover:text-stone-800 hover:bg-stone-200 active:bg-stone-200 border-stone-200
192
- dark:text-stone-300 dark:hover:text-white dark:hover:bg-stone-800 dark:active:bg-stone-600 dark:border-stone-600
193
216
  focus:outline-none
194
- inline-flex items-center"
217
+ inline-flex items-center
218
+ {colors}"
195
219
  class:bg-stone-700={isActive}
196
220
  class:dark:bg-stone-800={isActive}
197
- on:click={(e) => {on_click(e, operation)}}
198
- on:mousedown={mousedown}>
221
+ disabled={isDisabled}
222
+ on:mousedown={(e) => mousedown(e, operation)}
223
+ on:click={(e) => {on_click(e, operation, isDisabled)}}>
199
224
  {#if operation.icon}
200
225
  <div class="w-5 h-5 mr-1"><svelte:component this={operation.icon}/></div>
201
226
  {/if}
@@ -205,6 +230,7 @@ function isOperationActivated(operation) {
205
230
  </button>
206
231
  {/if}
207
232
  {:else}
233
+ <div class="border-l py-4"></div>
208
234
  <!--div class="border-l my-2"></div-->
209
235
  {/if}
210
236
  {/each}
@@ -214,17 +240,29 @@ function isOperationActivated(operation) {
214
240
  {#each rightOperations as operation}
215
241
  {#if !operation.separator}
216
242
  {@const isActive=isOperationActivated(operation)}
243
+ {@const isDisabled=isOperationDisabled(operation)}
244
+
245
+ {@const enabledLightColors ='text-stone-600 hover:text-stone-800 hover:bg-stone-200 active:bg-stone-200 border-stone-200'}
246
+ {@const disabledLightColors ='text-stone-400 border-stone-200'}
247
+
248
+ {@const enabledDarkColors ='dark:text-stone-300 dark:hover:text-white dark:hover:bg-stone-800 dark:active:bg-stone-600 dark:border-stone-600'}
249
+ {@const disabledDarkColors ='dark:text-stone-500 dark:border-stone-600'}
250
+
251
+ {@const disabledColors =`${disabledLightColors} ${disabledDarkColors}`}
252
+ {@const enabledColors =`${enabledLightColors} ${enabledDarkColors}`}
253
+ {@const colors = isDisabled ? disabledColors : enabledColors}
254
+
217
255
  <button type="button"
218
256
  class="py-2.5 px-4
219
257
  text-xs font-thin
220
- text-stone-600 hover:text-stone-800 hover:bg-stone-200 active:bg-stone-200 border-stone-200
221
- dark:text-stone-300 dark:hover:text-white dark:hover:bg-stone-800 dark:active:bg-stone-600 dark:border-stone-600
258
+ {colors}
222
259
  focus:outline-none
223
260
  inline-flex items-center"
224
261
  class:bg-stone-700={isActive}
225
262
  class:dark:bg-stone-800={isActive}
226
- on:click={(e) => {on_click(e, operation)}}
227
- on:mousedown={mousedown}>
263
+ disabled={isDisabled}
264
+ on:mousedown={(e) => mousedown(e, operation)}
265
+ on:click={(e) => {on_click(e, operation, isDisabled)}}>
228
266
  {#if operation.icon}
229
267
  <div class="w-5 h-5 mr-1"><svelte:component this={operation.icon}/></div>
230
268
  {/if}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humandialog/forms.svelte",
3
- "version": "1.4.4",
3
+ "version": "1.4.5",
4
4
  "description": "Basic Svelte UI components for Object Reef applications",
5
5
  "devDependencies": {
6
6
  "@playwright/test": "^1.28.1",