@threadlabs/looma 0.1.11 → 0.1.12

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 (56) hide show
  1. package/dist/{chunk-DYIMEQY7.js → chunk-DQZJTDIB.js} +27 -27
  2. package/dist/cjs/ui-affordance-scope.cjs.entry.js +5 -4
  3. package/dist/collection/components/ui-affordance-scope/ui-affordance-scope.js +4 -4
  4. package/dist/collection/icons.js +66 -0
  5. package/dist/collection/overlay/positioning.js +3 -2
  6. package/dist/components/ui-affordance-scope.js +1 -1
  7. package/dist/esm/ui-affordance-scope.entry.js +5 -4
  8. package/dist/index.cjs +79 -7
  9. package/dist/index.d.cts +52 -1
  10. package/dist/index.d.ts +52 -1
  11. package/dist/index.js +112 -3
  12. package/dist/looma/looma.esm.js +1 -1
  13. package/dist/looma/p-3ac2e0d4.entry.js +1 -0
  14. package/dist/types/components.d.ts +2 -2
  15. package/dist/types/icons.d.ts +48 -0
  16. package/dist/types/overlay/positioning.d.ts +1 -0
  17. package/dist/{ui-affordance-scope.entry-ZKUJ5AT4.js → ui-affordance-scope.entry-SWTDTGGU.js} +6 -5
  18. package/dist/{ui-avatar-group.entry-I4XM44BI.js → ui-avatar-group.entry-VUYE2XOM.js} +1 -1
  19. package/dist/{ui-avatar.entry-ZZAMZAVF.js → ui-avatar.entry-2CKHEJTS.js} +1 -1
  20. package/dist/{ui-badge.entry-DQXYMC3E.js → ui-badge.entry-4SWSD3R5.js} +1 -1
  21. package/dist/{ui-button.entry-DM7BUZLI.js → ui-button.entry-SS3AS32R.js} +1 -1
  22. package/dist/{ui-checkbox.entry-X3PPWKIJ.js → ui-checkbox.entry-V7OYTOLW.js} +1 -1
  23. package/dist/{ui-context-menu.entry-KAW4NIFE.js → ui-context-menu.entry-UCLTQESP.js} +1 -1
  24. package/dist/{ui-dialog.entry-D23SNXWB.js → ui-dialog.entry-PXIVZF7D.js} +1 -1
  25. package/dist/{ui-disclosure.entry-DOG6JZU7.js → ui-disclosure.entry-ZADBPM2D.js} +1 -1
  26. package/dist/{ui-floating-action-button.entry-VPQ7VBFS.js → ui-floating-action-button.entry-WNBWY36T.js} +1 -1
  27. package/dist/{ui-form-field.entry-SYZ6XSCG.js → ui-form-field.entry-RZPSWN6Y.js} +1 -1
  28. package/dist/{ui-icon-button.entry-2SZBOIH5.js → ui-icon-button.entry-ILU7RD7M.js} +1 -1
  29. package/dist/{ui-input.entry-PALICYLZ.js → ui-input.entry-FEIUK4EE.js} +1 -1
  30. package/dist/{ui-menu-item.entry-W6TEFP5Y.js → ui-menu-item.entry-UJVECPSK.js} +1 -1
  31. package/dist/{ui-menu.entry-7NARDV6S.js → ui-menu.entry-MTCE3F5U.js} +1 -1
  32. package/dist/{ui-popover.entry-ZXYHLDTP.js → ui-popover.entry-OAME35VB.js} +1 -1
  33. package/dist/{ui-radio-group.entry-XEUKMD6J.js → ui-radio-group.entry-CPFX4LVA.js} +1 -1
  34. package/dist/{ui-radio.entry-4ABBHDLN.js → ui-radio.entry-44OTRYPB.js} +1 -1
  35. package/dist/{ui-search-result-row.entry-3HHM7OV4.js → ui-search-result-row.entry-ZU5SL5OP.js} +1 -1
  36. package/dist/{ui-search-shell.entry-PJTFOBPT.js → ui-search-shell.entry-G7HG4RKU.js} +1 -1
  37. package/dist/{ui-select.entry-A3RI5XCG.js → ui-select.entry-NAONXMFG.js} +1 -1
  38. package/dist/{ui-switch.entry-JNRS2YTN.js → ui-switch.entry-SE4ZTCS2.js} +1 -1
  39. package/dist/{ui-tabs.entry-MQ4V5XCP.js → ui-tabs.entry-2YG2JE3K.js} +1 -1
  40. package/dist/{ui-textarea.entry-JJXJQZQR.js → ui-textarea.entry-PV3APDLY.js} +1 -1
  41. package/dist/{ui-toast-region.entry-STHVESL5.js → ui-toast-region.entry-WH2OL3FR.js} +1 -1
  42. package/dist/{ui-tooltip.entry-4W7CRIKI.js → ui-tooltip.entry-FY563DP4.js} +1 -1
  43. package/dist/{ui-top-bar.entry-WM3SS2HR.js → ui-top-bar.entry-LJSZXFAH.js} +1 -1
  44. package/editor/{chunk-F4AYF33M.js → chunk-OHD4OS32.js} +11 -11
  45. package/editor/{chunk-4VGVEHU2.js → chunk-RTHHTPWK.js} +110 -69
  46. package/editor/extensions/index.d.ts +4 -3
  47. package/editor/extensions/index.js +1 -1
  48. package/editor/index.d.ts +2 -1
  49. package/editor/index.js +2 -2
  50. package/editor/{table-overlay-jjvdARTJ.d.ts → table-overlay-DoiLie4h.d.ts} +2 -1
  51. package/editor/ui.d.ts +4 -2
  52. package/editor/ui.js +1 -1
  53. package/editor.css +107 -60
  54. package/package.json +2 -1
  55. package/vue/editor/index.js +88 -36
  56. package/dist/looma/p-95340a13.entry.js +0 -1
@@ -6,33 +6,33 @@ var __glob = (map) => (path) => {
6
6
 
7
7
  // import("./**/*.entry.js") in dist/esm/index-CEeiinfk.js
8
8
  var globImport_entry_js = __glob({
9
- "./ui-affordance-scope.entry.js": () => import("./ui-affordance-scope.entry-ZKUJ5AT4.js"),
10
- "./ui-avatar-group.entry.js": () => import("./ui-avatar-group.entry-I4XM44BI.js"),
11
- "./ui-avatar.entry.js": () => import("./ui-avatar.entry-ZZAMZAVF.js"),
12
- "./ui-badge.entry.js": () => import("./ui-badge.entry-DQXYMC3E.js"),
13
- "./ui-button.entry.js": () => import("./ui-button.entry-DM7BUZLI.js"),
14
- "./ui-checkbox.entry.js": () => import("./ui-checkbox.entry-X3PPWKIJ.js"),
15
- "./ui-context-menu.entry.js": () => import("./ui-context-menu.entry-KAW4NIFE.js"),
16
- "./ui-dialog.entry.js": () => import("./ui-dialog.entry-D23SNXWB.js"),
17
- "./ui-disclosure.entry.js": () => import("./ui-disclosure.entry-DOG6JZU7.js"),
18
- "./ui-floating-action-button.entry.js": () => import("./ui-floating-action-button.entry-VPQ7VBFS.js"),
19
- "./ui-form-field.entry.js": () => import("./ui-form-field.entry-SYZ6XSCG.js"),
20
- "./ui-icon-button.entry.js": () => import("./ui-icon-button.entry-2SZBOIH5.js"),
21
- "./ui-input.entry.js": () => import("./ui-input.entry-PALICYLZ.js"),
22
- "./ui-menu-item.entry.js": () => import("./ui-menu-item.entry-W6TEFP5Y.js"),
23
- "./ui-menu.entry.js": () => import("./ui-menu.entry-7NARDV6S.js"),
24
- "./ui-popover.entry.js": () => import("./ui-popover.entry-ZXYHLDTP.js"),
25
- "./ui-radio-group.entry.js": () => import("./ui-radio-group.entry-XEUKMD6J.js"),
26
- "./ui-radio.entry.js": () => import("./ui-radio.entry-4ABBHDLN.js"),
27
- "./ui-search-result-row.entry.js": () => import("./ui-search-result-row.entry-3HHM7OV4.js"),
28
- "./ui-search-shell.entry.js": () => import("./ui-search-shell.entry-PJTFOBPT.js"),
29
- "./ui-select.entry.js": () => import("./ui-select.entry-A3RI5XCG.js"),
30
- "./ui-switch.entry.js": () => import("./ui-switch.entry-JNRS2YTN.js"),
31
- "./ui-tabs.entry.js": () => import("./ui-tabs.entry-MQ4V5XCP.js"),
32
- "./ui-textarea.entry.js": () => import("./ui-textarea.entry-JJXJQZQR.js"),
33
- "./ui-toast-region.entry.js": () => import("./ui-toast-region.entry-STHVESL5.js"),
34
- "./ui-tooltip.entry.js": () => import("./ui-tooltip.entry-4W7CRIKI.js"),
35
- "./ui-top-bar.entry.js": () => import("./ui-top-bar.entry-WM3SS2HR.js")
9
+ "./ui-affordance-scope.entry.js": () => import("./ui-affordance-scope.entry-SWTDTGGU.js"),
10
+ "./ui-avatar-group.entry.js": () => import("./ui-avatar-group.entry-VUYE2XOM.js"),
11
+ "./ui-avatar.entry.js": () => import("./ui-avatar.entry-2CKHEJTS.js"),
12
+ "./ui-badge.entry.js": () => import("./ui-badge.entry-4SWSD3R5.js"),
13
+ "./ui-button.entry.js": () => import("./ui-button.entry-SS3AS32R.js"),
14
+ "./ui-checkbox.entry.js": () => import("./ui-checkbox.entry-V7OYTOLW.js"),
15
+ "./ui-context-menu.entry.js": () => import("./ui-context-menu.entry-UCLTQESP.js"),
16
+ "./ui-dialog.entry.js": () => import("./ui-dialog.entry-PXIVZF7D.js"),
17
+ "./ui-disclosure.entry.js": () => import("./ui-disclosure.entry-ZADBPM2D.js"),
18
+ "./ui-floating-action-button.entry.js": () => import("./ui-floating-action-button.entry-WNBWY36T.js"),
19
+ "./ui-form-field.entry.js": () => import("./ui-form-field.entry-RZPSWN6Y.js"),
20
+ "./ui-icon-button.entry.js": () => import("./ui-icon-button.entry-ILU7RD7M.js"),
21
+ "./ui-input.entry.js": () => import("./ui-input.entry-FEIUK4EE.js"),
22
+ "./ui-menu-item.entry.js": () => import("./ui-menu-item.entry-UJVECPSK.js"),
23
+ "./ui-menu.entry.js": () => import("./ui-menu.entry-MTCE3F5U.js"),
24
+ "./ui-popover.entry.js": () => import("./ui-popover.entry-OAME35VB.js"),
25
+ "./ui-radio-group.entry.js": () => import("./ui-radio-group.entry-CPFX4LVA.js"),
26
+ "./ui-radio.entry.js": () => import("./ui-radio.entry-44OTRYPB.js"),
27
+ "./ui-search-result-row.entry.js": () => import("./ui-search-result-row.entry-ZU5SL5OP.js"),
28
+ "./ui-search-shell.entry.js": () => import("./ui-search-shell.entry-G7HG4RKU.js"),
29
+ "./ui-select.entry.js": () => import("./ui-select.entry-NAONXMFG.js"),
30
+ "./ui-switch.entry.js": () => import("./ui-switch.entry-SE4ZTCS2.js"),
31
+ "./ui-tabs.entry.js": () => import("./ui-tabs.entry-2YG2JE3K.js"),
32
+ "./ui-textarea.entry.js": () => import("./ui-textarea.entry-PV3APDLY.js"),
33
+ "./ui-toast-region.entry.js": () => import("./ui-toast-region.entry-WH2OL3FR.js"),
34
+ "./ui-tooltip.entry.js": () => import("./ui-tooltip.entry-FY563DP4.js"),
35
+ "./ui-top-bar.entry.js": () => import("./ui-top-bar.entry-LJSZXFAH.js")
36
36
  });
37
37
 
38
38
  // dist/esm/index-CEeiinfk.js
@@ -2,6 +2,7 @@
2
2
 
3
3
  var index = require('./index-D07f6BOw.js');
4
4
 
5
+ const DEFAULT_AFFORDANCE_NEAR_RADIUS = 16;
5
6
  function distanceFromPointToRect(point, rect) {
6
7
  const dx = Math.max(rect.left - point.x, 0, point.x - rect.right);
7
8
  const dy = Math.max(rect.top - point.y, 0, point.y - rect.bottom);
@@ -19,10 +20,10 @@ function createProximityCoordinator(scope, options = {}) {
19
20
  const owner = scope.ownerDocument.defaultView ?? window;
20
21
  const pointerTarget = options.pointerTarget ?? scope;
21
22
  const anchorSelector = options.anchorSelector ?? "[data-ui-affordance]";
22
- const configuredRadius = options.nearRadius ?? 32;
23
+ const configuredRadius = options.nearRadius ?? DEFAULT_AFFORDANCE_NEAR_RADIUS;
23
24
  const nearRadius = Number.isFinite(configuredRadius)
24
25
  ? Math.max(0, configuredRadius)
25
- : 32;
26
+ : DEFAULT_AFFORDANCE_NEAR_RADIUS;
26
27
  const abort = new AbortController();
27
28
  let anchors = [];
28
29
  let frame = null;
@@ -120,7 +121,7 @@ const UIAffordanceScope = class {
120
121
  }
121
122
  get host() { return index.getElement(this); }
122
123
  /** Distance outside each registered affordance that reveals its near state. */
123
- nearRadius = 32;
124
+ nearRadius = DEFAULT_AFFORDANCE_NEAR_RADIUS;
124
125
  coordinator = null;
125
126
  componentDidLoad() {
126
127
  this.connectCoordinator();
@@ -139,7 +140,7 @@ const UIAffordanceScope = class {
139
140
  this.coordinator?.refresh();
140
141
  };
141
142
  render() {
142
- return (index.h(index.Host, { key: '2bc861652826e6227deaba6d1030ecf43753f575' }, index.h("slot", { key: '5e0544939e6b20747f12023dbb45329eb3853715', onSlotchange: this.onSlotChange })));
143
+ return (index.h(index.Host, { key: '184b0a908494d480ed23aa14b75d4f7b94e5275b' }, index.h("slot", { key: '570e810db588c1514c6fd85985c9bc4532993a2b', onSlotchange: this.onSlotChange })));
143
144
  }
144
145
  static get watchers() { return {
145
146
  "nearRadius": [{
@@ -1,9 +1,9 @@
1
1
  import { Host, h } from "@stencil/core";
2
- import { createProximityCoordinator } from "../../overlay/positioning";
2
+ import { createProximityCoordinator, DEFAULT_AFFORDANCE_NEAR_RADIUS, } from "../../overlay/positioning";
3
3
  export class UIAffordanceScope {
4
4
  host;
5
5
  /** Distance outside each registered affordance that reveals its near state. */
6
- nearRadius = 32;
6
+ nearRadius = DEFAULT_AFFORDANCE_NEAR_RADIUS;
7
7
  coordinator = null;
8
8
  componentDidLoad() {
9
9
  this.connectCoordinator();
@@ -22,7 +22,7 @@ export class UIAffordanceScope {
22
22
  this.coordinator?.refresh();
23
23
  };
24
24
  render() {
25
- return (h(Host, { key: '2bc861652826e6227deaba6d1030ecf43753f575' }, h("slot", { key: '5e0544939e6b20747f12023dbb45329eb3853715', onSlotchange: this.onSlotChange })));
25
+ return (h(Host, { key: '184b0a908494d480ed23aa14b75d4f7b94e5275b' }, h("slot", { key: '570e810db588c1514c6fd85985c9bc4532993a2b', onSlotchange: this.onSlotChange })));
26
26
  }
27
27
  static get is() { return "ui-affordance-scope"; }
28
28
  static get encapsulation() { return "shadow"; }
@@ -56,7 +56,7 @@ export class UIAffordanceScope {
56
56
  "setter": false,
57
57
  "reflect": true,
58
58
  "attribute": "near-radius",
59
- "defaultValue": "32"
59
+ "defaultValue": "DEFAULT_AFFORDANCE_NEAR_RADIUS"
60
60
  }
61
61
  };
62
62
  }
@@ -0,0 +1,66 @@
1
+ import { AlignCenter, AlignLeft, AlignRight, Bold, Braces, ChevronDown, ChevronLeft, CodeXml, Columns3, Ellipsis, Eraser, GripHorizontal, GripVertical, Heading1, Heading2, Heading3, Highlighter, Image, Italic, List, ListOrdered, ListTodo, Merge, Minus, PaintBucket, PanelBottom, PanelLeft, PanelRight, PanelTop, Pilcrow, Plus, Quote, Redo2, Rows3, Split, Strikethrough, Table2, Trash2, Underline, Undo2, } from "lucide";
2
+ /** The opinionated Lucide set used by Looma's shipped interaction surfaces. */
3
+ export const LOOMA_ICONS = {
4
+ 'align-center': AlignCenter,
5
+ 'align-left': AlignLeft,
6
+ 'align-right': AlignRight,
7
+ bold: Bold,
8
+ braces: Braces,
9
+ 'chevron-down': ChevronDown,
10
+ 'chevron-left': ChevronLeft,
11
+ 'code-xml': CodeXml,
12
+ columns: Columns3,
13
+ ellipsis: Ellipsis,
14
+ eraser: Eraser,
15
+ 'grip-horizontal': GripHorizontal,
16
+ 'grip-vertical': GripVertical,
17
+ 'heading-1': Heading1,
18
+ 'heading-2': Heading2,
19
+ 'heading-3': Heading3,
20
+ highlighter: Highlighter,
21
+ image: Image,
22
+ italic: Italic,
23
+ list: List,
24
+ 'list-ordered': ListOrdered,
25
+ 'list-todo': ListTodo,
26
+ merge: Merge,
27
+ minus: Minus,
28
+ 'paint-bucket': PaintBucket,
29
+ 'panel-bottom': PanelBottom,
30
+ 'panel-left': PanelLeft,
31
+ 'panel-right': PanelRight,
32
+ 'panel-top': PanelTop,
33
+ pilcrow: Pilcrow,
34
+ plus: Plus,
35
+ quote: Quote,
36
+ redo: Redo2,
37
+ rows: Rows3,
38
+ split: Split,
39
+ strikethrough: Strikethrough,
40
+ table: Table2,
41
+ trash: Trash2,
42
+ underline: Underline,
43
+ undo: Undo2,
44
+ };
45
+ function serializeAttributes(attributes) {
46
+ return Object.entries(attributes)
47
+ .map(([name, value]) => ` ${name}="${escapeAttribute(value)}"`)
48
+ .join('');
49
+ }
50
+ function escapeAttribute(value) {
51
+ return String(value).replaceAll('&', '&').replaceAll('"', '"');
52
+ }
53
+ function serializeIconNode(node) {
54
+ const [tag, attributes] = node;
55
+ return `<${tag}${serializeAttributes(attributes)}></${tag}>`;
56
+ }
57
+ /** Creates consistent, currentColor-driven SVG markup for framework-neutral components. */
58
+ export function loomaIconMarkup(name, className = 'looma-icon') {
59
+ return [
60
+ `<svg class="${escapeAttribute(className)}" data-looma-icon="${name}" aria-hidden="true" focusable="false"`,
61
+ ' viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"',
62
+ ' stroke-linecap="round" stroke-linejoin="round">',
63
+ LOOMA_ICONS[name].map(serializeIconNode).join(''),
64
+ '</svg>',
65
+ ].join('');
66
+ }
@@ -1,3 +1,4 @@
1
+ export const DEFAULT_AFFORDANCE_NEAR_RADIUS = 16;
1
2
  export function getVisualViewportRect(owner = window) {
2
3
  const viewport = owner.visualViewport;
3
4
  const left = viewport?.offsetLeft ?? 0;
@@ -41,10 +42,10 @@ export function createProximityCoordinator(scope, options = {}) {
41
42
  const owner = scope.ownerDocument.defaultView ?? window;
42
43
  const pointerTarget = options.pointerTarget ?? scope;
43
44
  const anchorSelector = options.anchorSelector ?? "[data-ui-affordance]";
44
- const configuredRadius = options.nearRadius ?? 32;
45
+ const configuredRadius = options.nearRadius ?? DEFAULT_AFFORDANCE_NEAR_RADIUS;
45
46
  const nearRadius = Number.isFinite(configuredRadius)
46
47
  ? Math.max(0, configuredRadius)
47
- : 32;
48
+ : DEFAULT_AFFORDANCE_NEAR_RADIUS;
48
49
  const abort = new AbortController();
49
50
  let anchors = [];
50
51
  let frame = null;
@@ -1 +1 @@
1
- import{p as t,t as e,H as a,h as n,c as i}from"./p-CIA4RyEp.js";function o(t,e){return Math.hypot(Math.max(e.left-t.x,0,t.x-e.right),Math.max(e.top-t.y,0,t.y-e.bottom))}const r=t(class extends a{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow()}get host(){return this}nearRadius=32;coordinator=null;componentDidLoad(){this.connectCoordinator()}disconnectedCallback(){this.coordinator?.destroy(),this.coordinator=null}connectCoordinator(){this.coordinator?.destroy(),this.coordinator=function(t,e={}){const a=t.ownerDocument.defaultView??window,n=e.pointerTarget??t,i=e.anchorSelector??"[data-ui-affordance]",r=e.nearRadius??32,s=Number.isFinite(r)?Math.max(0,r):32,c=new AbortController;let d=[],u=null,l=null,f=!1;const p=()=>{for(const{element:t}of d)t.hasAttribute("data-ui-proximity")&&t.removeAttribute("data-ui-proximity");t.hasAttribute("data-ui-interaction")&&t.removeAttribute("data-ui-interaction")},h=()=>{d=Array.from(t.querySelectorAll(i)).filter((t=>!t.hasAttribute("disabled")&&"true"!==t.getAttribute("aria-disabled"))).map((t=>({element:t,rect:t.getBoundingClientRect()}))),f=!1},g=()=>{if(u=null,f&&h(),!l)return void p();let e=!1;for(const t of d){const a=o(l,t.rect)<=s;a&&"near"!==t.element.getAttribute("data-ui-proximity")?t.element.setAttribute("data-ui-proximity","near"):!a&&t.element.hasAttribute("data-ui-proximity")&&t.element.removeAttribute("data-ui-proximity"),e||=a}e&&"engaged"!==t.getAttribute("data-ui-interaction")?t.setAttribute("data-ui-interaction","engaged"):!e&&t.hasAttribute("data-ui-interaction")&&t.removeAttribute("data-ui-interaction")},m=()=>{null===u&&(u=a.requestAnimationFrame(g))},y=()=>{f=!0,m()};return n.addEventListener("pointermove",(t=>{l="touch"===t.pointerType?null:{x:t.clientX,y:t.clientY},m()}),{passive:!0,signal:c.signal}),a.addEventListener("resize",y,{passive:!0,signal:c.signal}),a.addEventListener("scroll",y,{passive:!0,capture:!0,signal:c.signal}),a.visualViewport?.addEventListener("resize",y,{passive:!0,signal:c.signal}),a.visualViewport?.addEventListener("scroll",y,{passive:!0,signal:c.signal}),h(),{refresh:y,destroy(){c.abort(),null!==u&&a.cancelAnimationFrame(u),u=null,l=null,p(),d=[]}}}(this.host,{nearRadius:this.nearRadius})}onSlotChange=()=>{this.coordinator?.refresh()};render(){return n(i,{key:"2bc861652826e6227deaba6d1030ecf43753f575"},n("slot",{key:"5e0544939e6b20747f12023dbb45329eb3853715",onSlotchange:this.onSlotChange}))}static get watchers(){return{nearRadius:[{connectCoordinator:0}]}}static get style(){return":host{display:contents;--ui-affordance-scope-engaged:0}:host([data-ui-interaction='engaged']){--ui-affordance-scope-engaged:1}"}},[769,"ui-affordance-scope",{nearRadius:[514,"near-radius"]},void 0,{nearRadius:[{connectCoordinator:0}]}]),s=r,c=function(){"undefined"!=typeof customElements&&["ui-affordance-scope"].forEach((t=>{"ui-affordance-scope"===t&&(customElements.get(e(t))||customElements.define(e(t),r))}))};export{s as UiAffordanceScope,c as defineCustomElement}
1
+ import{p as t,t as a,H as e,h as n,c as i}from"./p-CIA4RyEp.js";function o(t,a){return Math.hypot(Math.max(a.left-t.x,0,t.x-a.right),Math.max(a.top-t.y,0,t.y-a.bottom))}const r=t(class extends e{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow()}get host(){return this}nearRadius=16;coordinator=null;componentDidLoad(){this.connectCoordinator()}disconnectedCallback(){this.coordinator?.destroy(),this.coordinator=null}connectCoordinator(){this.coordinator?.destroy(),this.coordinator=function(t,a={}){const e=t.ownerDocument.defaultView??window,n=a.pointerTarget??t,i=a.anchorSelector??"[data-ui-affordance]",r=a.nearRadius??16,s=Number.isFinite(r)?Math.max(0,r):16,c=new AbortController;let d=[],u=null,l=null,p=!1;const f=()=>{for(const{element:t}of d)t.hasAttribute("data-ui-proximity")&&t.removeAttribute("data-ui-proximity");t.hasAttribute("data-ui-interaction")&&t.removeAttribute("data-ui-interaction")},h=()=>{d=Array.from(t.querySelectorAll(i)).filter((t=>!t.hasAttribute("disabled")&&"true"!==t.getAttribute("aria-disabled"))).map((t=>({element:t,rect:t.getBoundingClientRect()}))),p=!1},g=()=>{if(u=null,p&&h(),!l)return void f();let a=!1;for(const t of d){const e=o(l,t.rect)<=s;e&&"near"!==t.element.getAttribute("data-ui-proximity")?t.element.setAttribute("data-ui-proximity","near"):!e&&t.element.hasAttribute("data-ui-proximity")&&t.element.removeAttribute("data-ui-proximity"),a||=e}a&&"engaged"!==t.getAttribute("data-ui-interaction")?t.setAttribute("data-ui-interaction","engaged"):!a&&t.hasAttribute("data-ui-interaction")&&t.removeAttribute("data-ui-interaction")},m=()=>{null===u&&(u=e.requestAnimationFrame(g))},y=()=>{p=!0,m()};return n.addEventListener("pointermove",(t=>{l="touch"===t.pointerType?null:{x:t.clientX,y:t.clientY},m()}),{passive:!0,signal:c.signal}),e.addEventListener("resize",y,{passive:!0,signal:c.signal}),e.addEventListener("scroll",y,{passive:!0,capture:!0,signal:c.signal}),e.visualViewport?.addEventListener("resize",y,{passive:!0,signal:c.signal}),e.visualViewport?.addEventListener("scroll",y,{passive:!0,signal:c.signal}),h(),{refresh:y,destroy(){c.abort(),null!==u&&e.cancelAnimationFrame(u),u=null,l=null,f(),d=[]}}}(this.host,{nearRadius:this.nearRadius})}onSlotChange=()=>{this.coordinator?.refresh()};render(){return n(i,{key:"184b0a908494d480ed23aa14b75d4f7b94e5275b"},n("slot",{key:"570e810db588c1514c6fd85985c9bc4532993a2b",onSlotchange:this.onSlotChange}))}static get watchers(){return{nearRadius:[{connectCoordinator:0}]}}static get style(){return":host{display:contents;--ui-affordance-scope-engaged:0}:host([data-ui-interaction='engaged']){--ui-affordance-scope-engaged:1}"}},[769,"ui-affordance-scope",{nearRadius:[514,"near-radius"]},void 0,{nearRadius:[{connectCoordinator:0}]}]),s=r,c=function(){"undefined"!=typeof customElements&&["ui-affordance-scope"].forEach((t=>{"ui-affordance-scope"===t&&(customElements.get(a(t))||customElements.define(a(t),r))}))};export{s as UiAffordanceScope,c as defineCustomElement}
@@ -1,5 +1,6 @@
1
1
  import { r as registerInstance, g as getElement, h, H as Host } from './index-CEeiinfk.js';
2
2
 
3
+ const DEFAULT_AFFORDANCE_NEAR_RADIUS = 16;
3
4
  function distanceFromPointToRect(point, rect) {
4
5
  const dx = Math.max(rect.left - point.x, 0, point.x - rect.right);
5
6
  const dy = Math.max(rect.top - point.y, 0, point.y - rect.bottom);
@@ -17,10 +18,10 @@ function createProximityCoordinator(scope, options = {}) {
17
18
  const owner = scope.ownerDocument.defaultView ?? window;
18
19
  const pointerTarget = options.pointerTarget ?? scope;
19
20
  const anchorSelector = options.anchorSelector ?? "[data-ui-affordance]";
20
- const configuredRadius = options.nearRadius ?? 32;
21
+ const configuredRadius = options.nearRadius ?? DEFAULT_AFFORDANCE_NEAR_RADIUS;
21
22
  const nearRadius = Number.isFinite(configuredRadius)
22
23
  ? Math.max(0, configuredRadius)
23
- : 32;
24
+ : DEFAULT_AFFORDANCE_NEAR_RADIUS;
24
25
  const abort = new AbortController();
25
26
  let anchors = [];
26
27
  let frame = null;
@@ -118,7 +119,7 @@ const UIAffordanceScope = class {
118
119
  }
119
120
  get host() { return getElement(this); }
120
121
  /** Distance outside each registered affordance that reveals its near state. */
121
- nearRadius = 32;
122
+ nearRadius = DEFAULT_AFFORDANCE_NEAR_RADIUS;
122
123
  coordinator = null;
123
124
  componentDidLoad() {
124
125
  this.connectCoordinator();
@@ -137,7 +138,7 @@ const UIAffordanceScope = class {
137
138
  this.coordinator?.refresh();
138
139
  };
139
140
  render() {
140
- return (h(Host, { key: '2bc861652826e6227deaba6d1030ecf43753f575' }, h("slot", { key: '5e0544939e6b20747f12023dbb45329eb3853715', onSlotchange: this.onSlotChange })));
141
+ return (h(Host, { key: '184b0a908494d480ed23aa14b75d4f7b94e5275b' }, h("slot", { key: '570e810db588c1514c6fd85985c9bc4532993a2b', onSlotchange: this.onSlotChange })));
141
142
  }
142
143
  static get watchers() { return {
143
144
  "nearRadius": [{
package/dist/index.cjs CHANGED
@@ -38,8 +38,8 @@ function createProximityCoordinator(scope, options = {}) {
38
38
  const owner = scope.ownerDocument.defaultView ?? window;
39
39
  const pointerTarget = options.pointerTarget ?? scope;
40
40
  const anchorSelector = options.anchorSelector ?? "[data-ui-affordance]";
41
- const configuredRadius = options.nearRadius ?? 32;
42
- const nearRadius = Number.isFinite(configuredRadius) ? Math.max(0, configuredRadius) : 32;
41
+ const configuredRadius = options.nearRadius ?? DEFAULT_AFFORDANCE_NEAR_RADIUS;
42
+ const nearRadius = Number.isFinite(configuredRadius) ? Math.max(0, configuredRadius) : DEFAULT_AFFORDANCE_NEAR_RADIUS;
43
43
  const abort = new AbortController();
44
44
  let anchors = [];
45
45
  let frame = null;
@@ -123,10 +123,11 @@ function createProximityCoordinator(scope, options = {}) {
123
123
  }
124
124
  };
125
125
  }
126
- var uiAffordanceScopeCss, UIAffordanceScope;
126
+ var DEFAULT_AFFORDANCE_NEAR_RADIUS, uiAffordanceScopeCss, UIAffordanceScope;
127
127
  var init_ui_affordance_scope_entry = __esm({
128
128
  "dist/esm/ui-affordance-scope.entry.js"() {
129
129
  init_index_CEeiinfk();
130
+ DEFAULT_AFFORDANCE_NEAR_RADIUS = 16;
130
131
  uiAffordanceScopeCss = () => `:host{display:contents;--ui-affordance-scope-engaged:0}:host([data-ui-interaction='engaged']){--ui-affordance-scope-engaged:1}`;
131
132
  UIAffordanceScope = class {
132
133
  constructor(hostRef) {
@@ -136,7 +137,7 @@ var init_ui_affordance_scope_entry = __esm({
136
137
  return getElement(this);
137
138
  }
138
139
  /** Distance outside each registered affordance that reveals its near state. */
139
- nearRadius = 32;
140
+ nearRadius = DEFAULT_AFFORDANCE_NEAR_RADIUS;
140
141
  coordinator = null;
141
142
  componentDidLoad() {
142
143
  this.connectCoordinator();
@@ -155,7 +156,7 @@ var init_ui_affordance_scope_entry = __esm({
155
156
  this.coordinator?.refresh();
156
157
  };
157
158
  render() {
158
- return h(Host, { key: "2bc861652826e6227deaba6d1030ecf43753f575" }, h("slot", { key: "5e0544939e6b20747f12023dbb45329eb3853715", onSlotchange: this.onSlotChange }));
159
+ return h(Host, { key: "184b0a908494d480ed23aa14b75d4f7b94e5275b" }, h("slot", { key: "570e810db588c1514c6fd85985c9bc4532993a2b", onSlotchange: this.onSlotChange }));
159
160
  }
160
161
  static get watchers() {
161
162
  return {
@@ -4070,6 +4071,8 @@ var init_index_CEeiinfk = __esm({
4070
4071
  // index.ts
4071
4072
  var index_exports = {};
4072
4073
  __export(index_exports, {
4074
+ DEFAULT_AFFORDANCE_NEAR_RADIUS: () => DEFAULT_AFFORDANCE_NEAR_RADIUS2,
4075
+ LOOMA_ICONS: () => LOOMA_ICONS,
4073
4076
  clampRectToViewport: () => clampRectToViewport,
4074
4077
  closeOverlay: () => closeOverlay2,
4075
4078
  createProximityCoordinator: () => createProximityCoordinator2,
@@ -4077,6 +4080,7 @@ __export(index_exports, {
4077
4080
  getTopOverlay: () => getTopOverlay2,
4078
4081
  getVisualViewportRect: () => getVisualViewportRect,
4079
4082
  isTopOverlay: () => isTopOverlay,
4083
+ loomaIconMarkup: () => loomaIconMarkup,
4080
4084
  openOverlay: () => openOverlay2,
4081
4085
  requestTopOverlayClose: () => requestTopOverlayClose2
4082
4086
  });
@@ -4203,6 +4207,7 @@ function requestTopOverlayClose2(reason, trigger) {
4203
4207
  }
4204
4208
 
4205
4209
  // src/overlay/positioning.ts
4210
+ var DEFAULT_AFFORDANCE_NEAR_RADIUS2 = 16;
4206
4211
  function getVisualViewportRect(owner = window) {
4207
4212
  const viewport = owner.visualViewport;
4208
4213
  const left = viewport?.offsetLeft ?? 0;
@@ -4240,8 +4245,8 @@ function createProximityCoordinator2(scope, options = {}) {
4240
4245
  const owner = scope.ownerDocument.defaultView ?? window;
4241
4246
  const pointerTarget = options.pointerTarget ?? scope;
4242
4247
  const anchorSelector = options.anchorSelector ?? "[data-ui-affordance]";
4243
- const configuredRadius = options.nearRadius ?? 32;
4244
- const nearRadius = Number.isFinite(configuredRadius) ? Math.max(0, configuredRadius) : 32;
4248
+ const configuredRadius = options.nearRadius ?? DEFAULT_AFFORDANCE_NEAR_RADIUS2;
4249
+ const nearRadius = Number.isFinite(configuredRadius) ? Math.max(0, configuredRadius) : DEFAULT_AFFORDANCE_NEAR_RADIUS2;
4245
4250
  const abort = new AbortController();
4246
4251
  let anchors = [];
4247
4252
  let frame = null;
@@ -4323,10 +4328,76 @@ function createProximityCoordinator2(scope, options = {}) {
4323
4328
  };
4324
4329
  }
4325
4330
 
4331
+ // src/icons.ts
4332
+ var import_lucide = require("lucide");
4333
+ var LOOMA_ICONS = {
4334
+ "align-center": import_lucide.AlignCenter,
4335
+ "align-left": import_lucide.AlignLeft,
4336
+ "align-right": import_lucide.AlignRight,
4337
+ bold: import_lucide.Bold,
4338
+ braces: import_lucide.Braces,
4339
+ "chevron-down": import_lucide.ChevronDown,
4340
+ "chevron-left": import_lucide.ChevronLeft,
4341
+ "code-xml": import_lucide.CodeXml,
4342
+ columns: import_lucide.Columns3,
4343
+ ellipsis: import_lucide.Ellipsis,
4344
+ eraser: import_lucide.Eraser,
4345
+ "grip-horizontal": import_lucide.GripHorizontal,
4346
+ "grip-vertical": import_lucide.GripVertical,
4347
+ "heading-1": import_lucide.Heading1,
4348
+ "heading-2": import_lucide.Heading2,
4349
+ "heading-3": import_lucide.Heading3,
4350
+ highlighter: import_lucide.Highlighter,
4351
+ image: import_lucide.Image,
4352
+ italic: import_lucide.Italic,
4353
+ list: import_lucide.List,
4354
+ "list-ordered": import_lucide.ListOrdered,
4355
+ "list-todo": import_lucide.ListTodo,
4356
+ merge: import_lucide.Merge,
4357
+ minus: import_lucide.Minus,
4358
+ "paint-bucket": import_lucide.PaintBucket,
4359
+ "panel-bottom": import_lucide.PanelBottom,
4360
+ "panel-left": import_lucide.PanelLeft,
4361
+ "panel-right": import_lucide.PanelRight,
4362
+ "panel-top": import_lucide.PanelTop,
4363
+ pilcrow: import_lucide.Pilcrow,
4364
+ plus: import_lucide.Plus,
4365
+ quote: import_lucide.Quote,
4366
+ redo: import_lucide.Redo2,
4367
+ rows: import_lucide.Rows3,
4368
+ split: import_lucide.Split,
4369
+ strikethrough: import_lucide.Strikethrough,
4370
+ table: import_lucide.Table2,
4371
+ trash: import_lucide.Trash2,
4372
+ underline: import_lucide.Underline,
4373
+ undo: import_lucide.Undo2
4374
+ };
4375
+ function serializeAttributes(attributes) {
4376
+ return Object.entries(attributes).map(([name, value]) => ` ${name}="${escapeAttribute(value)}"`).join("");
4377
+ }
4378
+ function escapeAttribute(value) {
4379
+ return String(value).replaceAll("&", "&amp;").replaceAll('"', "&quot;");
4380
+ }
4381
+ function serializeIconNode(node) {
4382
+ const [tag, attributes] = node;
4383
+ return `<${tag}${serializeAttributes(attributes)}></${tag}>`;
4384
+ }
4385
+ function loomaIconMarkup(name, className = "looma-icon") {
4386
+ return [
4387
+ `<svg class="${escapeAttribute(className)}" data-looma-icon="${name}" aria-hidden="true" focusable="false"`,
4388
+ ' viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"',
4389
+ ' stroke-linecap="round" stroke-linejoin="round">',
4390
+ LOOMA_ICONS[name].map(serializeIconNode).join(""),
4391
+ "</svg>"
4392
+ ].join("");
4393
+ }
4394
+
4326
4395
  // index.ts
4327
4396
  defineCustomElements();
4328
4397
  // Annotate the CommonJS export names for ESM import in node:
4329
4398
  0 && (module.exports = {
4399
+ DEFAULT_AFFORDANCE_NEAR_RADIUS,
4400
+ LOOMA_ICONS,
4330
4401
  clampRectToViewport,
4331
4402
  closeOverlay,
4332
4403
  createProximityCoordinator,
@@ -4334,6 +4405,7 @@ defineCustomElements();
4334
4405
  getTopOverlay,
4335
4406
  getVisualViewportRect,
4336
4407
  isTopOverlay,
4408
+ loomaIconMarkup,
4337
4409
  openOverlay,
4338
4410
  requestTopOverlayClose
4339
4411
  });
package/dist/index.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ import { IconNode } from 'lucide';
2
+
1
3
  type OverlayCloseReason = "programmatic" | "light-dismiss" | "escape" | "action";
2
4
  type OverlayTrigger = "keyboard" | "pointer" | "programmatic";
3
5
  interface OverlayRecord {
@@ -41,6 +43,7 @@ interface ProximityCoordinator {
41
43
  /** Removes the scope-level listeners and all reflected interaction state. */
42
44
  destroy(): void;
43
45
  }
46
+ declare const DEFAULT_AFFORDANCE_NEAR_RADIUS = 16;
44
47
  declare function getVisualViewportRect(owner?: Window): ViewportRect;
45
48
  declare function clampRectToViewport(rect: RectLike, viewport?: ViewportRect, gutter?: number): Point;
46
49
  declare function distanceFromPointToRect(point: Point, rect: RectLike): number;
@@ -54,4 +57,52 @@ declare function distanceFromPointToRect(point: Point, rect: RectLike): number;
54
57
  */
55
58
  declare function createProximityCoordinator(scope: HTMLElement, options?: ProximityCoordinatorOptions): ProximityCoordinator;
56
59
 
57
- export { type OverlayCloseReason, type OverlayRecord, type OverlayTrigger, type Point, type ProximityCoordinator, type ProximityCoordinatorOptions, type RectLike, type ViewportRect, clampRectToViewport, closeOverlay, createProximityCoordinator, distanceFromPointToRect, getTopOverlay, getVisualViewportRect, isTopOverlay, openOverlay, requestTopOverlayClose };
60
+ /** The opinionated Lucide set used by Looma's shipped interaction surfaces. */
61
+ declare const LOOMA_ICONS: {
62
+ 'align-center': IconNode;
63
+ 'align-left': IconNode;
64
+ 'align-right': IconNode;
65
+ bold: IconNode;
66
+ braces: IconNode;
67
+ 'chevron-down': IconNode;
68
+ 'chevron-left': IconNode;
69
+ 'code-xml': IconNode;
70
+ columns: IconNode;
71
+ ellipsis: IconNode;
72
+ eraser: IconNode;
73
+ 'grip-horizontal': IconNode;
74
+ 'grip-vertical': IconNode;
75
+ 'heading-1': IconNode;
76
+ 'heading-2': IconNode;
77
+ 'heading-3': IconNode;
78
+ highlighter: IconNode;
79
+ image: IconNode;
80
+ italic: IconNode;
81
+ list: IconNode;
82
+ 'list-ordered': IconNode;
83
+ 'list-todo': IconNode;
84
+ merge: IconNode;
85
+ minus: IconNode;
86
+ 'paint-bucket': IconNode;
87
+ 'panel-bottom': IconNode;
88
+ 'panel-left': IconNode;
89
+ 'panel-right': IconNode;
90
+ 'panel-top': IconNode;
91
+ pilcrow: IconNode;
92
+ plus: IconNode;
93
+ quote: IconNode;
94
+ redo: IconNode;
95
+ rows: IconNode;
96
+ split: IconNode;
97
+ strikethrough: IconNode;
98
+ table: IconNode;
99
+ trash: IconNode;
100
+ underline: IconNode;
101
+ undo: IconNode;
102
+ };
103
+ type LoomaIconName = keyof typeof LOOMA_ICONS;
104
+ type LoomaIconNode = IconNode;
105
+ /** Creates consistent, currentColor-driven SVG markup for framework-neutral components. */
106
+ declare function loomaIconMarkup(name: LoomaIconName, className?: string): string;
107
+
108
+ export { DEFAULT_AFFORDANCE_NEAR_RADIUS, LOOMA_ICONS, type LoomaIconName, type LoomaIconNode, type OverlayCloseReason, type OverlayRecord, type OverlayTrigger, type Point, type ProximityCoordinator, type ProximityCoordinatorOptions, type RectLike, type ViewportRect, clampRectToViewport, closeOverlay, createProximityCoordinator, distanceFromPointToRect, getTopOverlay, getVisualViewportRect, isTopOverlay, loomaIconMarkup, openOverlay, requestTopOverlayClose };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { IconNode } from 'lucide';
2
+
1
3
  type OverlayCloseReason = "programmatic" | "light-dismiss" | "escape" | "action";
2
4
  type OverlayTrigger = "keyboard" | "pointer" | "programmatic";
3
5
  interface OverlayRecord {
@@ -41,6 +43,7 @@ interface ProximityCoordinator {
41
43
  /** Removes the scope-level listeners and all reflected interaction state. */
42
44
  destroy(): void;
43
45
  }
46
+ declare const DEFAULT_AFFORDANCE_NEAR_RADIUS = 16;
44
47
  declare function getVisualViewportRect(owner?: Window): ViewportRect;
45
48
  declare function clampRectToViewport(rect: RectLike, viewport?: ViewportRect, gutter?: number): Point;
46
49
  declare function distanceFromPointToRect(point: Point, rect: RectLike): number;
@@ -54,4 +57,52 @@ declare function distanceFromPointToRect(point: Point, rect: RectLike): number;
54
57
  */
55
58
  declare function createProximityCoordinator(scope: HTMLElement, options?: ProximityCoordinatorOptions): ProximityCoordinator;
56
59
 
57
- export { type OverlayCloseReason, type OverlayRecord, type OverlayTrigger, type Point, type ProximityCoordinator, type ProximityCoordinatorOptions, type RectLike, type ViewportRect, clampRectToViewport, closeOverlay, createProximityCoordinator, distanceFromPointToRect, getTopOverlay, getVisualViewportRect, isTopOverlay, openOverlay, requestTopOverlayClose };
60
+ /** The opinionated Lucide set used by Looma's shipped interaction surfaces. */
61
+ declare const LOOMA_ICONS: {
62
+ 'align-center': IconNode;
63
+ 'align-left': IconNode;
64
+ 'align-right': IconNode;
65
+ bold: IconNode;
66
+ braces: IconNode;
67
+ 'chevron-down': IconNode;
68
+ 'chevron-left': IconNode;
69
+ 'code-xml': IconNode;
70
+ columns: IconNode;
71
+ ellipsis: IconNode;
72
+ eraser: IconNode;
73
+ 'grip-horizontal': IconNode;
74
+ 'grip-vertical': IconNode;
75
+ 'heading-1': IconNode;
76
+ 'heading-2': IconNode;
77
+ 'heading-3': IconNode;
78
+ highlighter: IconNode;
79
+ image: IconNode;
80
+ italic: IconNode;
81
+ list: IconNode;
82
+ 'list-ordered': IconNode;
83
+ 'list-todo': IconNode;
84
+ merge: IconNode;
85
+ minus: IconNode;
86
+ 'paint-bucket': IconNode;
87
+ 'panel-bottom': IconNode;
88
+ 'panel-left': IconNode;
89
+ 'panel-right': IconNode;
90
+ 'panel-top': IconNode;
91
+ pilcrow: IconNode;
92
+ plus: IconNode;
93
+ quote: IconNode;
94
+ redo: IconNode;
95
+ rows: IconNode;
96
+ split: IconNode;
97
+ strikethrough: IconNode;
98
+ table: IconNode;
99
+ trash: IconNode;
100
+ underline: IconNode;
101
+ undo: IconNode;
102
+ };
103
+ type LoomaIconName = keyof typeof LOOMA_ICONS;
104
+ type LoomaIconNode = IconNode;
105
+ /** Creates consistent, currentColor-driven SVG markup for framework-neutral components. */
106
+ declare function loomaIconMarkup(name: LoomaIconName, className?: string): string;
107
+
108
+ export { DEFAULT_AFFORDANCE_NEAR_RADIUS, LOOMA_ICONS, type LoomaIconName, type LoomaIconNode, type OverlayCloseReason, type OverlayRecord, type OverlayTrigger, type Point, type ProximityCoordinator, type ProximityCoordinatorOptions, type RectLike, type ViewportRect, clampRectToViewport, closeOverlay, createProximityCoordinator, distanceFromPointToRect, getTopOverlay, getVisualViewportRect, isTopOverlay, loomaIconMarkup, openOverlay, requestTopOverlayClose };