x4js 2.3.30 → 2.3.32

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.
@@ -88,6 +88,9 @@ $color--dark-base: #2d6fa5;
88
88
  --accent-color-focus: var(--color-primary-a0);
89
89
  --accent-color-active: var(--color-primary-a0);
90
90
 
91
+ // the accent as the colour of a text, on the background: a button checked, focused
92
+ --accent-text: var(--accent-background-active);
93
+
91
94
  // Borders
92
95
  --border: color-mix(in srgb, var(--color-primary-a100) 11.8%, var(--color-primary-a0)); // #e1e1e1
93
96
  --border-light: color-mix(in srgb, var(--color-primary-a100) 8.2%, var(--color-primary-a0)); // #eaeaea
@@ -162,6 +165,14 @@ html.x4theme-dark {
162
165
  --accent-color-focus: #ffffff;
163
166
  --accent-color-active: #ffffff;
164
167
 
168
+ // the accent as a text: the blues of the scale are dark, lost on the background; a light one (chosen)
169
+ --accent-text: #{color.adjust($color--dark-base, $lightness: 25%)};
170
+
171
+ // the edge of a button checked or focused, in that blue: the dark ones are lost on the background
172
+ --checkbox-button-border-checked: var( --accent-text );
173
+ --radio-button-border-checked: var( --accent-text );
174
+ --ol-button-border-focus: var( --accent-text );
175
+
165
176
  // the title bar of a Dialog: the one of the window of VS Code
166
177
  --color-dialog-caption: #181818; // titleBar.activeBackground
167
178
  --color-dialog-caption-text: #cccccc; // titleBar.activeForeground
@@ -177,5 +188,8 @@ html.x4theme-dark {
177
188
  // the marks of the events out of the view of a Planner: the darkest blue (a90 is the text here)
178
189
  --planner-edge-background: var( --accent-background-active );
179
190
 
191
+ // the icon of a tooltip: the dark blues are lost on its background; the colour of the descriptions
192
+ --tooltip-icon-color: var( --text-secondary );
193
+
180
194
  color-scheme: dark; // the native parts: select, scroll bars, number spinners
181
195
  }
@@ -16,7 +16,7 @@
16
16
 
17
17
  import { asap } from '../../core/core_tools';
18
18
  import { EventCallback } from '../../core/core_events';
19
- import { Component, ComponentEvent, ComponentEvents, ComponentProps, EvClick, EvDblClick, EvSelectionChange } from '../../core/component';
19
+ import { Component, ComponentEvent, ComponentEvents, ComponentProps, EvClick, EvContextMenu, EvDblClick, EvSelectionChange } from '../../core/component';
20
20
 
21
21
  import { ScrollView, Viewport } from '../viewport/viewport';
22
22
  import { Label, SimpleText } from '../label/label';
@@ -59,12 +59,14 @@ export interface TreeviewProps extends Omit<ComponentProps,"content"> {
59
59
  selectionChange?: EventCallback<EvSelectionChange>;
60
60
  dblClick?: EventCallback<EvDblClick>;
61
61
  click?: EventCallback<EvClick>;
62
+ contextMenu?: EventCallback<EvContextMenu>;
62
63
  }
63
64
 
64
65
  export interface TreeviewEvents extends ComponentEvents {
65
66
  selectionChange?: EvSelectionChange;
66
67
  dblClick?: EvDblClick;
67
68
  click?: EvClick;
69
+ contextMenu?: EvContextMenu;
68
70
  }
69
71
 
70
72
  /**
@@ -185,7 +187,15 @@ class CTreeViewItem extends Box {
185
187
 
186
188
 
187
189
  /**
188
- *
190
+ * A tree of items, folders that open and close.
191
+ *
192
+ * A right click selects the item under the mouse, then fires contextMenu, its context the
193
+ * id of the item (null out of the items); the menu of the browser is not shown.
194
+ *
195
+ * @example
196
+ * new Treeview( { items, contextMenu: ( ev ) => {
197
+ * new Menu( { items: [ { text: "Rename", click: ( ) => rename( ev.context ) } ] } ).displayAt( ev.uievent.clientX, ev.uievent.clientY );
198
+ * } } );
189
199
  */
190
200
 
191
201
  export class Treeview extends Component<TreeviewProps,TreeviewEvents> {
@@ -199,7 +209,7 @@ export class Treeview extends Component<TreeviewProps,TreeviewEvents> {
199
209
  constructor( props: TreeviewProps ) {
200
210
  super( props );
201
211
 
202
- this.mapPropEvents( props, "selectionChange", "dblClick", "click" );
212
+ this.mapPropEvents( props, "selectionChange", "dblClick", "click", "contextMenu" );
203
213
 
204
214
  const scroller = new ScrollView( { cls: "body" } );
205
215
  this._view = scroller.getViewport( );
@@ -218,6 +228,7 @@ export class Treeview extends Component<TreeviewProps,TreeviewEvents> {
218
228
  this.setDOMEvents( {
219
229
  click: ( ev ) => this._on_click( ev ),
220
230
  dblclick: (e) => this._on_click(e),
231
+ contextmenu: ( ev ) => this._on_ctx_menu( ev ),
221
232
  keydown: ( ev ) => this._onkey( ev ),
222
233
  });
223
234
 
@@ -244,10 +255,18 @@ export class Treeview extends Component<TreeviewProps,TreeviewEvents> {
244
255
  }
245
256
  }
246
257
 
258
+ /**
259
+ * the item of this tree an element is in, not one of a component around it; null when none
260
+ */
261
+
262
+ private _itemOf( target: EventTarget ): Component {
263
+ const c = Component.closest( target as Element, ".item" );
264
+ return c && this.contains( c ) ? c : null;
265
+ }
266
+
247
267
  private _on_click( ev: UIEvent ) {
248
- // an item of this tree, not of a component around it
249
- const c = Component.closest( ev.target as Element, ".item" );
250
- if( c && this.contains( c ) ) {
268
+ const c = this._itemOf( ev.target );
269
+ if( c ) {
251
270
  const id = c.getInternalData( "id" );
252
271
 
253
272
  const fev: ComponentEvent = { context:id };
@@ -268,6 +287,25 @@ export class Treeview extends Component<TreeviewProps,TreeviewEvents> {
268
287
  this.clearSelection( );
269
288
  }
270
289
 
290
+ /**
291
+ * a right click: the item under the mouse selected, then contextMenu
292
+ */
293
+
294
+ private _on_ctx_menu( ev: MouseEvent ) {
295
+ ev.preventDefault( );
296
+
297
+ const c = this._itemOf( ev.target );
298
+ if( c ) {
299
+ const id = c.getInternalData( "id" );
300
+
301
+ this._selectItem( id, c );
302
+ this.fire( "contextMenu", { uievent: ev, context: id } );
303
+ return;
304
+ }
305
+
306
+ this.fire( "contextMenu", { uievent: ev, context: null } );
307
+ }
308
+
271
309
  private _onkey( ev: KeyboardEvent ) {
272
310
  switch( ev.key ) {
273
311
  case "ArrowDown": {
@@ -47,6 +47,19 @@ export interface ClipboardRead extends ClipboardContent {
47
47
  /** what the application set last */
48
48
  let kept: ClipboardContent = null;
49
49
 
50
+ /**
51
+ * The image to read among the types of the clipboard: the PNG when there is one, every
52
+ * program reads it; else the first image (a program puts its own format first: a SVG).
53
+ */
54
+
55
+ function imageTypeOf( types: readonly string[] ): string {
56
+ if( types.includes( "image/png" ) ) {
57
+ return "image/png";
58
+ }
59
+
60
+ return types.find( type => type.startsWith( "image/" ) );
61
+ }
62
+
50
63
  function toPng( image: Blob ): Promise<Blob> {
51
64
  return new Promise( ( resolve, reject ) => {
52
65
  const url = URL.createObjectURL( image );
@@ -119,8 +132,9 @@ export async function setClipboard( data: ClipboardContent ): Promise<boolean> {
119
132
  /**
120
133
  * Read the clipboard, from a menu or a button.
121
134
  *
122
- * @returns what the system holds. When it refuses or cannot be asked, what
123
- * the application set last. Never files: see getEventClipboard.
135
+ * @returns what the system holds, its image as a PNG when it has one. When it
136
+ * refuses or cannot be asked, what the application set last. Never files: see
137
+ * getEventClipboard.
124
138
  *
125
139
  * @example
126
140
  * const data = await getClipboard( );
@@ -143,12 +157,14 @@ export async function getClipboard( ): Promise<ClipboardRead> {
143
157
  const data: ClipboardRead = { files: [] };
144
158
 
145
159
  for( const item of await system.read( ) ) {
160
+ const imageType = imageTypeOf( item.types );
161
+
146
162
  for( const type of item.types ) {
147
163
  if( type==="text/plain" && !data.text ) {
148
164
  const blob = await item.getType( type );
149
165
  data.text = ( await blob.text( ) ) || undefined;
150
166
  }
151
- else if( type.startsWith( "image/" ) && !data.image ) {
167
+ else if( type===imageType && !data.image ) {
152
168
  data.image = await item.getType( type );
153
169
  }
154
170
  }
@@ -212,8 +228,9 @@ export function setEventClipboard( ev: ClipboardEvent, data: ClipboardContent ):
212
228
  }
213
229
 
214
230
  /**
215
- * Read the clipboard in a "paste" event. The default of the event is left
216
- * as it is: prevent it when what was read is used.
231
+ * Read the clipboard in a "paste" event, its image the PNG file when there is
232
+ * one. The default of the event is left as it is: prevent it when what was
233
+ * read is used.
217
234
  *
218
235
  * @example
219
236
  * this.addDOMEvent( "paste", ev => {
@@ -232,7 +249,9 @@ export function getEventClipboard( ev: ClipboardEvent ): ClipboardRead {
232
249
  if( transfer ) {
233
250
  data.text = transfer.getData( "text/plain" ) || undefined;
234
251
  data.files = Array.from( transfer.files );
235
- data.image = data.files.find( file => file.type.startsWith( "image/" ) );
252
+
253
+ const imageType = imageTypeOf( data.files.map( file => file.type ) );
254
+ data.image = data.files.find( file => file.type===imageType );
236
255
  }
237
256
 
238
257
  return data;