@raylang/elements 0.11.0 → 0.12.0

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.
@@ -73,6 +73,11 @@ export class RayInput extends FieldControl {
73
73
  syncComplete(this);
74
74
  }
75
75
 
76
+ /** The highlight range under a point of the viewport, or null. */
77
+ highlightAt(x, y) {
78
+ return this._textLayer?.rangeAt(x, y) ?? null;
79
+ }
80
+
76
81
  /** Runs `highlight` again (what it marks changed, not the text). */
77
82
  refreshHighlight() {
78
83
  syncHighlight(this);
@@ -142,6 +142,13 @@ export class RayMenu extends Floating {
142
142
  return this.context && this._point ? this._point : super.anchorRect();
143
143
  }
144
144
 
145
+ // A context menu's trigger is the area it serves: a press there, outside
146
+ // the panel, closes it like a system context menu (a right click reopens
147
+ // it at the new point).
148
+ triggerDismisses() {
149
+ return Boolean(this.context);
150
+ }
151
+
145
152
  toggled(open) {
146
153
  if (open) {
147
154
  this._focus(this._focusOnOpen ?? "first");
@@ -77,6 +77,11 @@ export class RayTextarea extends FieldControl {
77
77
  syncComplete(this);
78
78
  }
79
79
 
80
+ /** The highlight range under a point of the viewport, or null. */
81
+ highlightAt(x, y) {
82
+ return this._textLayer?.rangeAt(x, y) ?? null;
83
+ }
84
+
80
85
  /** Runs `highlight` again (what it marks changed, not the text). */
81
86
  refreshHighlight() {
82
87
  syncHighlight(this);
package/core/floating.js CHANGED
@@ -35,6 +35,7 @@ export class Floating extends RayElement {
35
35
  open: { type: Boolean, reflect: true },
36
36
  placement: { type: String, reflect: true, default: "bottom" },
37
37
  offset: { type: Number, default: 8 },
38
+ anchor: { attribute: false },
38
39
  };
39
40
  /** popover attribute of the panel ("manual": closing is handled here). */
40
41
  static popoverMode = "manual";
@@ -102,8 +103,15 @@ export class Floating extends RayElement {
102
103
  /** Subclasses attach their trigger listeners here. */
103
104
  wireTrigger(_trigger) {}
104
105
 
105
- /** The rectangle the panel is placed against (default: the trigger). */
106
+ /**
107
+ * The rectangle the panel is placed against: `anchor` when set (an element,
108
+ * a DOMRect or a function returning one: a text range, the pointer), else
109
+ * the trigger.
110
+ */
106
111
  anchorRect() {
112
+ const a = typeof this.anchor === "function" ? this.anchor() : this.anchor;
113
+ if (a instanceof Element) return a.getBoundingClientRect();
114
+ if (a && typeof a.left === "number") return a;
107
115
  return (this.trigger ?? this).getBoundingClientRect();
108
116
  }
109
117
 
@@ -132,7 +140,20 @@ export class Floating extends RayElement {
132
140
  _dismissable() {
133
141
  const ctor = /** @type {typeof Floating} */ (this.constructor);
134
142
  if (this.#undismiss || !ctor.lightDismiss || ctor.popoverMode !== "manual") return;
135
- this.#undismiss = dismissable({ panel: this.panel, owner: this, trigger: this.trigger, close: () => { this.open = false; } });
143
+ // When the trigger dismisses, so does the rest of the host's light DOM
144
+ // (the area is a child of the host): only the panel is inside then.
145
+ const area = this.triggerDismisses();
146
+ this.#undismiss = dismissable({ panel: this.panel, owner: area ? this.panel : this, trigger: area ? null : this.trigger, close: () => { this.open = false; } });
147
+ }
148
+
149
+ /**
150
+ * Whether a press on the trigger counts as outside and closes the panel.
151
+ * Default false: a button that toggles the panel handles its own click
152
+ * (closing it there too would reopen it). A context menu's trigger is the
153
+ * whole area it serves, so there it is true.
154
+ */
155
+ triggerDismisses() {
156
+ return false;
136
157
  }
137
158
 
138
159
  /** The keyframes the panel leaves with (subclasses may change them). */
@@ -166,6 +187,15 @@ export class Floating extends RayElement {
166
187
 
167
188
  _onToggle(e) {
168
189
  const opening = e.newState === "open";
190
+ // `toggle` is a task: `open` may have changed again since the state it
191
+ // reports. An open that a later `open = false` is already animating out,
192
+ // or a close that a later `open = true` re-showed, must not win over
193
+ // that newer value; only the pair of events is still emitted.
194
+ const stale = opening ? !this.open && Boolean(this.#exit) : Boolean(this.open) && this.panel.matches(":popover-open");
195
+ if (stale) {
196
+ this.emit(opening ? "ray-open" : "ray-close");
197
+ return;
198
+ }
169
199
  if (this.popupKind()) this.#trigger?.setAttribute("aria-expanded", String(opening));
170
200
  if (opening) {
171
201
  this.reposition();
package/core/textlayer.js CHANGED
@@ -176,10 +176,18 @@ export class TextLayer {
176
176
 
177
177
  /** The range under a point of the viewport, or null. */
178
178
  rangeAt(x, y) {
179
+ return this.hitAt(x, y)?.range ?? null;
180
+ }
181
+
182
+ /**
183
+ * The range under a point of the viewport and the box of the line of it
184
+ * the point is on (a range may wrap), or null.
185
+ */
186
+ hitAt(x, y) {
179
187
  const marks = [...this.text.querySelectorAll("mark")];
180
188
  for (let i = 0; i < marks.length; i++) {
181
189
  for (const r of marks[i].getClientRects()) {
182
- if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) return this.ranges[i];
190
+ if (x >= r.left && x <= r.right && y >= r.top && y <= r.bottom) return { range: this.ranges[i], rect: r };
183
191
  }
184
192
  }
185
193
  return null;
@@ -189,7 +197,9 @@ export class TextLayer {
189
197
  /**
190
198
  * Paints `host.highlight(text)` behind `host.control` (ray-input,
191
199
  * ray-textarea): the layer is made the first time a highlight function is
192
- * set. A range's `title` becomes the field's tooltip under the pointer.
200
+ * set. A range's `title` becomes the field's tooltip under the pointer, and
201
+ * `ray-highlight-hover` fires when the range under it changes (null leaving
202
+ * one), with its box, so an app can show its own popover over a range.
193
203
  */
194
204
  export function syncHighlight(host) {
195
205
  const fn = typeof host.highlight === "function" ? host.highlight : null;
@@ -197,10 +207,18 @@ export function syncHighlight(host) {
197
207
  host._textLayer ??= new TextLayer(host.control);
198
208
  if (!host._highlightTitles) {
199
209
  host._highlightTitles = true;
200
- host.control.addEventListener("pointermove", (e) => {
201
- const title = host._textLayer.rangeAt(e.clientX, e.clientY)?.title ?? "";
210
+ let over = null;
211
+ const hover = (x, y) => {
212
+ const hit = host._textLayer.hitAt(x, y);
213
+ const title = hit?.range.title ?? "";
202
214
  if (host.control.title !== title) host.control.title = title;
203
- });
215
+ const range = hit?.range ?? null;
216
+ if (range === over) return;
217
+ over = range;
218
+ host.emit("ray-highlight-hover", { range, rect: hit?.rect ?? null });
219
+ };
220
+ host.control.addEventListener("pointermove", (e) => hover(e.clientX, e.clientY));
221
+ host.control.addEventListener("pointerleave", () => hover(-1, -1));
204
222
  }
205
223
  let ranges = [];
206
224
  if (fn) {
@@ -4746,6 +4746,11 @@
4746
4746
  "name": "select",
4747
4747
  "description": "Selects the text."
4748
4748
  },
4749
+ {
4750
+ "kind": "method",
4751
+ "name": "highlightAt",
4752
+ "description": "The highlight range under a point of the viewport (clientX, clientY), or null."
4753
+ },
4749
4754
  {
4750
4755
  "kind": "method",
4751
4756
  "name": "refreshHighlight",
@@ -4760,6 +4765,13 @@
4760
4765
  },
4761
4766
  "description": "A suggestion was accepted (the text already has it)."
4762
4767
  },
4768
+ {
4769
+ "name": "ray-highlight-hover",
4770
+ "type": {
4771
+ "text": "CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>"
4772
+ },
4773
+ "description": "The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title."
4774
+ },
4763
4775
  {
4764
4776
  "name": "input",
4765
4777
  "type": {
@@ -5301,6 +5313,13 @@
5301
5313
  },
5302
5314
  "description": "A suggestion was accepted (the text already has it)."
5303
5315
  },
5316
+ {
5317
+ "name": "ray-highlight-hover",
5318
+ "type": {
5319
+ "text": "CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>"
5320
+ },
5321
+ "description": "The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title."
5322
+ },
5304
5323
  {
5305
5324
  "name": "input",
5306
5325
  "type": {
@@ -6301,6 +6320,13 @@
6301
6320
  },
6302
6321
  "description": "A suggestion was accepted (the text already has it)."
6303
6322
  },
6323
+ {
6324
+ "name": "ray-highlight-hover",
6325
+ "type": {
6326
+ "text": "CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>"
6327
+ },
6328
+ "description": "The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title."
6329
+ },
6304
6330
  {
6305
6331
  "name": "input",
6306
6332
  "type": {
@@ -6765,6 +6791,13 @@
6765
6791
  },
6766
6792
  "description": "A suggestion was accepted (the text already has it)."
6767
6793
  },
6794
+ {
6795
+ "name": "ray-highlight-hover",
6796
+ "type": {
6797
+ "text": "CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>"
6798
+ },
6799
+ "description": "The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title."
6800
+ },
6768
6801
  {
6769
6802
  "name": "input",
6770
6803
  "type": {
@@ -9540,6 +9573,11 @@
9540
9573
  "attribute": "radius",
9541
9574
  "reflects": true
9542
9575
  },
9576
+ {
9577
+ "kind": "method",
9578
+ "name": "highlightAt",
9579
+ "description": "The highlight range under a point of the viewport (clientX, clientY), or null."
9580
+ },
9543
9581
  {
9544
9582
  "kind": "method",
9545
9583
  "name": "refreshHighlight",
@@ -9554,6 +9592,13 @@
9554
9592
  },
9555
9593
  "description": "A suggestion was accepted (the text already has it)."
9556
9594
  },
9595
+ {
9596
+ "name": "ray-highlight-hover",
9597
+ "type": {
9598
+ "text": "CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>"
9599
+ },
9600
+ "description": "The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title."
9601
+ },
9557
9602
  {
9558
9603
  "name": "input",
9559
9604
  "type": {
@@ -13496,6 +13541,14 @@
13496
13541
  "attribute": "native",
13497
13542
  "reflects": true
13498
13543
  },
13544
+ {
13545
+ "kind": "field",
13546
+ "name": "anchor",
13547
+ "type": {
13548
+ "text": "Element | DOMRect | (() => DOMRect) | null"
13549
+ },
13550
+ "description": "What the panel is placed against instead of the trigger: an element, a DOMRect or a function returning one (a text range, the pointer; read again on every reposition). The trigger still opens it."
13551
+ },
13499
13552
  {
13500
13553
  "kind": "field",
13501
13554
  "name": "offset",
@@ -13571,7 +13624,7 @@
13571
13624
  "slots": [
13572
13625
  {
13573
13626
  "name": "trigger",
13574
- "description": "The button that opens it, or the area for a context menu."
13627
+ "description": "The button that opens it, or the area for a context menu (a press on the area outside the open menu closes it; a right click reopens it at the new point)."
13575
13628
  },
13576
13629
  {
13577
13630
  "name": "",
@@ -13940,6 +13993,14 @@
13940
13993
  "reflects": false,
13941
13994
  "default": "8"
13942
13995
  },
13996
+ {
13997
+ "kind": "field",
13998
+ "name": "anchor",
13999
+ "type": {
14000
+ "text": "Element | DOMRect | (() => DOMRect) | null"
14001
+ },
14002
+ "description": "What the panel is placed against instead of the trigger: an element, a DOMRect or a function returning one (a text range, the pointer; read again on every reposition). The trigger still opens it."
14003
+ },
13943
14004
  {
13944
14005
  "kind": "field",
13945
14006
  "name": "width",
package/llms-full.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # ray-elements
2
2
 
3
- > Web components (custom elements, Shadow DOM, no dependencies) for any web app: plain HTML, React, Vue or a raylang app. npm: `@raylang/elements`, `@raylang/react`, `@raylang/vue`; raylang: the `elements` package. This file describes version 0.11.0.
3
+ > Web components (custom elements, Shadow DOM, no dependencies) for any web app: plain HTML, React, Vue or a raylang app. npm: `@raylang/elements`, `@raylang/react`, `@raylang/vue`; raylang: the `elements` package. This file describes version 0.12.0.
4
4
 
5
5
  ray-elements is a design system of standard web components (custom elements
6
6
  with Shadow DOM, no dependencies): `<ray-button>`, `<ray-input>`,
@@ -918,6 +918,7 @@ Attributes (forwarded to the inner element):
918
918
  Events:
919
919
 
920
920
  - `ray-complete` (detail `{ item: CompletionItem; from: number; to: number }`): A suggestion was accepted (the text already has it).
921
+ - `ray-highlight-hover` (detail `{ range: HighlightRange | null; rect: DOMRect | null }`): The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title.
921
922
  - `input`: On every edit (value already updated).
922
923
  - `change`: When an edit is committed (blur, Enter).
923
924
 
@@ -944,6 +945,7 @@ Parts (`::part()`):
944
945
  Methods and properties:
945
946
 
946
947
  - `select(): void`: Selects the text.
948
+ - `highlightAt(x: number, y: number): HighlightRange | null`: The highlight range under a point of the viewport (clientX, clientY), or null.
947
949
  - `refreshHighlight(): void`: Runs highlight again, when what it marks changed but the text did not.
948
950
 
949
951
  Vue `v-model`: `value` (updated on input).
@@ -1480,6 +1482,7 @@ Attributes (forwarded to the inner element):
1480
1482
  Events:
1481
1483
 
1482
1484
  - `ray-complete` (detail `{ item: CompletionItem; from: number; to: number }`): A suggestion was accepted (the text already has it).
1485
+ - `ray-highlight-hover` (detail `{ range: HighlightRange | null; rect: DOMRect | null }`): The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title.
1483
1486
  - `input`: On every edit.
1484
1487
  - `change`: When an edit is committed.
1485
1488
 
@@ -1497,6 +1500,7 @@ Parts (`::part()`):
1497
1500
 
1498
1501
  Methods and properties:
1499
1502
 
1503
+ - `highlightAt(x: number, y: number): HighlightRange | null`: The highlight range under a point of the viewport (clientX, clientY), or null.
1500
1504
  - `refreshHighlight(): void`: Runs highlight again, when what it marks changed but the text did not.
1501
1505
 
1502
1506
  Vue `v-model`: `value` (updated on input).
@@ -2191,6 +2195,7 @@ Properties:
2191
2195
  - `context`: boolean, reflects. Opens on right click (contextmenu) over the trigger area, at the pointer.
2192
2196
  - `keepOpen` (attribute `keep-open`): boolean, reflects. Choosing an item does not close the menu.
2193
2197
  - `native`: boolean, reflects. With a native host (ray-elements/core/raylang.js in a std/ui window), opens as the system's context menu at the pointer: items and dividers, same ray-select.
2198
+ - `anchor` (property only): `Element | DOMRect | (() => DOMRect) | null`. What the panel is placed against instead of the trigger: an element, a DOMRect or a function returning one (a text range, the pointer; read again on every reposition). The trigger still opens it.
2194
2199
 
2195
2200
  Also the properties of Floating: `offset`.
2196
2201
 
@@ -2203,7 +2208,7 @@ Events:
2203
2208
 
2204
2209
  Slots:
2205
2210
 
2206
- - `trigger`: The button that opens it, or the area for a context menu.
2211
+ - `trigger`: The button that opens it, or the area for a context menu (a press on the area outside the open menu closes it; a right click reopens it at the new point).
2207
2212
  - (default): ray-menu-item, ray-menu-label and ray-menu-divider elements.
2208
2213
 
2209
2214
  Parts (`::part()`):
@@ -2294,6 +2299,7 @@ Properties:
2294
2299
  - `open`: boolean, reflects. Shown.
2295
2300
  - `placement`: `bottom` | `bottom-start` | `bottom-end` | `top` | `top-start` | `top-end` | `left` | `left-start` | `left-end` | `right` | `right-start` | `right-end`, default `bottom`, reflects. Preferred side and alignment: top/bottom/left/right are sides of the screen; on top and bottom, -start/-end follow the writing direction (right to left, "bottom-start" lines up the right edges).
2296
2301
  - `offset`: number, default `8`. Gap to the trigger in px.
2302
+ - `anchor` (property only): `Element | DOMRect | (() => DOMRect) | null`. What the panel is placed against instead of the trigger: an element, a DOMRect or a function returning one (a text range, the pointer; read again on every reposition). The trigger still opens it.
2297
2303
  - `width`: string. Panel width (px number or CSS length). Default: its content.
2298
2304
  - `matchWidth` (attribute `match-width`): boolean. At least as wide as the trigger.
2299
2305
  - `padding`: `0` | `xs` | `sm` | `md` | `lg`, default `md`, reflects. Panel padding.
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # ray-elements
2
2
 
3
- > Web components (custom elements, Shadow DOM, no dependencies) for any web app: plain HTML, React, Vue or a raylang app. npm: `@raylang/elements`, `@raylang/react`, `@raylang/vue`; raylang: the `elements` package. This file describes version 0.11.0.
3
+ > Web components (custom elements, Shadow DOM, no dependencies) for any web app: plain HTML, React, Vue or a raylang app. npm: `@raylang/elements`, `@raylang/react`, `@raylang/vue`; raylang: the `elements` package. This file describes version 0.12.0.
4
4
 
5
5
  ray-elements is a design system of standard web components (custom elements
6
6
  with Shadow DOM, no dependencies): `<ray-button>`, `<ray-input>`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raylang/elements",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Web components for any app, with raylang extras (shadcn/ui + Mantine inspired)",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": ["web-components", "custom-elements", "design-system", "ui", "raylang"],
package/ray-elements.d.ts CHANGED
@@ -855,6 +855,8 @@ export declare class RayInput extends FieldControl {
855
855
  suggestionsLabel: string;
856
856
  /** Selects the text. */
857
857
  select(): void;
858
+ /** The highlight range under a point of the viewport (clientX, clientY), or null. */
859
+ highlightAt(x: number, y: number): HighlightRange | null;
858
860
  /** Runs highlight again, when what it marks changed but the text did not. */
859
861
  refreshHighlight(): void;
860
862
  addEventListener<K extends keyof RayInputEventMap>(type: K, listener: (this: RayInput, ev: RayInputEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions): void;
@@ -865,6 +867,8 @@ export declare class RayInput extends FieldControl {
865
867
  export interface RayInputEventMap extends HTMLElementEventMap {
866
868
  /** A suggestion was accepted (the text already has it). */
867
869
  "ray-complete": CustomEvent<{ item: CompletionItem; from: number; to: number }>;
870
+ /** The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title. */
871
+ "ray-highlight-hover": CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>;
868
872
  }
869
873
 
870
874
  // --- Mode input (mode-input)
@@ -900,6 +904,8 @@ export interface RayModeInputEventMap extends HTMLElementEventMap {
900
904
  "ray-mode-change": CustomEvent<{ mode: string; previous: string | null; option: ModeOption }>;
901
905
  /** A suggestion was accepted (the text already has it). */
902
906
  "ray-complete": CustomEvent<{ item: CompletionItem; from: number; to: number }>;
907
+ /** The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title. */
908
+ "ray-highlight-hover": CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>;
903
909
  }
904
910
 
905
911
  // --- Number input (number-input)
@@ -960,6 +966,8 @@ export interface RayPasswordInputEventMap extends HTMLElementEventMap {
960
966
  "ray-visibility-change": CustomEvent<{ visible: boolean }>;
961
967
  /** A suggestion was accepted (the text already has it). */
962
968
  "ray-complete": CustomEvent<{ item: CompletionItem; from: number; to: number }>;
969
+ /** The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title. */
970
+ "ray-highlight-hover": CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>;
963
971
  }
964
972
 
965
973
  // --- Path input (path-input)
@@ -991,6 +999,8 @@ export interface RayPathInputEventMap extends HTMLElementEventMap {
991
999
  "ray-error": CustomEvent<{ error: Error }>;
992
1000
  /** A suggestion was accepted (the text already has it). */
993
1001
  "ray-complete": CustomEvent<{ item: CompletionItem; from: number; to: number }>;
1002
+ /** The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title. */
1003
+ "ray-highlight-hover": CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>;
994
1004
  }
995
1005
 
996
1006
  // --- Radio group (radio)
@@ -1250,6 +1260,8 @@ export declare class RayTextarea extends FieldControl {
1250
1260
  complete: ((text: string, caret: number) => CompletionResult | null | Promise<CompletionResult | null>) | null;
1251
1261
  /** Accessible name of the suggestion list. */
1252
1262
  suggestionsLabel: string;
1263
+ /** The highlight range under a point of the viewport (clientX, clientY), or null. */
1264
+ highlightAt(x: number, y: number): HighlightRange | null;
1253
1265
  /** Runs highlight again, when what it marks changed but the text did not. */
1254
1266
  refreshHighlight(): void;
1255
1267
  addEventListener<K extends keyof RayTextareaEventMap>(type: K, listener: (this: RayTextarea, ev: RayTextareaEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions): void;
@@ -1260,6 +1272,8 @@ export declare class RayTextarea extends FieldControl {
1260
1272
  export interface RayTextareaEventMap extends HTMLElementEventMap {
1261
1273
  /** A suggestion was accepted (the text already has it). */
1262
1274
  "ray-complete": CustomEvent<{ item: CompletionItem; from: number; to: number }>;
1275
+ /** The highlight range under the pointer changed: the range and the box of the line of it the pointer is on, or null on leaving a range. Anchor a ray-popover to rect (its anchor property) to show more than the title. */
1276
+ "ray-highlight-hover": CustomEvent<{ range: HighlightRange | null; rect: DOMRect | null }>;
1263
1277
  }
1264
1278
 
1265
1279
  // --- Bottom nav (bottom-nav)
@@ -1747,6 +1761,8 @@ export declare class RayMenu extends Floating {
1747
1761
  keepOpen: boolean | undefined;
1748
1762
  /** With a native host (ray-elements/core/raylang.js in a std/ui window), opens as the system's context menu at the pointer: items and dividers, same ray-select. */
1749
1763
  native: boolean | undefined;
1764
+ /** What the panel is placed against instead of the trigger: an element, a DOMRect or a function returning one (a text range, the pointer; read again on every reposition). The trigger still opens it. */
1765
+ anchor: Element | DOMRect | (() => DOMRect) | null;
1750
1766
  /** Opens the items as the system's context menu (needs a native host); resolves to the chosen item, or null. */
1751
1767
  popupNative(): Promise<RayMenuItem | null>;
1752
1768
  /** Opens it. */
@@ -1807,6 +1823,8 @@ export declare class RayPopover extends Floating {
1807
1823
  placement: "bottom" | "bottom-start" | "bottom-end" | "top" | "top-start" | "top-end" | "left" | "left-start" | "left-end" | "right" | "right-start" | "right-end";
1808
1824
  /** Gap to the trigger in px. */
1809
1825
  offset: number;
1826
+ /** What the panel is placed against instead of the trigger: an element, a DOMRect or a function returning one (a text range, the pointer; read again on every reposition). The trigger still opens it. */
1827
+ anchor: Element | DOMRect | (() => DOMRect) | null;
1810
1828
  /** Panel width (px number or CSS length). Default: its content. */
1811
1829
  width: string | undefined;
1812
1830
  /** At least as wide as the trigger. */