@exponential-at/ui-element 0.0.0-stage → 0.1.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.
@@ -0,0 +1,898 @@
1
+ // packages/exponential-ui-element/src/element.ts
2
+ import { Show, batch, createComponent, createEffect, createMemo, createRoot, createSignal, onCleanup, untrack } from "solid-js";
3
+ import { render } from "solid-js/web";
4
+ import { setPointer } from "@exponential-at/ui/web";
5
+ import { ExponentialSurface, createHostSurface, createSurface, extensionCatalogs, hostPlugin, px } from "@exponential-at/ui-solid";
6
+
7
+ // packages/exponential-ui-element/src/events.ts
8
+ function emit(target, name, detail, cancelable = false) {
9
+ return target.dispatchEvent(new CustomEvent(name, { detail, bubbles: true, composed: true, cancelable }));
10
+ }
11
+ var isThenable = (v) => typeof v === `object` && v !== null && typeof v.then === `function`;
12
+ function joinPending(results) {
13
+ const pending = results.filter(isThenable);
14
+ if (pending.length === 0)
15
+ return;
16
+ return Promise.all(pending).then(() => {
17
+ return;
18
+ });
19
+ }
20
+ function emitWaiting(target, name, base) {
21
+ const waits = [];
22
+ const detail = { ...base, waitUntil: (p) => void waits.push(Promise.resolve(p)) };
23
+ emit(target, name, detail);
24
+ return waits;
25
+ }
26
+
27
+ // packages/exponential-ui-element/src/transport.ts
28
+ import { DEFAULT_URL_SCHEMES, ExponentialHost, JsonlStreamTransport, SseTransport, WebSocketTransport, decideUrl } from "@exponential-at/ui";
29
+ import { ownPrivateHosts } from "@exponential-at/ui/web";
30
+ function transportKind2(attrs) {
31
+ if (attrs.transport === `ws` || /^wss?:/i.test(attrs.src))
32
+ return `ws`;
33
+ if (attrs.transport === `sse`)
34
+ return `sse`;
35
+ return `jsonl`;
36
+ }
37
+ function createTransport2(attrs) {
38
+ const kind = transportKind2(attrs);
39
+ const postUrl = attrs.post || undefined;
40
+ if (kind === `ws`)
41
+ return new WebSocketTransport({ url: attrs.src });
42
+ if (kind === `sse`)
43
+ return new SseTransport({ url: attrs.src, postUrl });
44
+ return new JsonlStreamTransport({ url: attrs.src, postUrl });
45
+ }
46
+ var WS_OF = { http: `ws`, https: `wss` };
47
+ function transportSchemes2(policy) {
48
+ const http = (policy?.schemes ?? DEFAULT_URL_SCHEMES).filter((s) => s === `http` || s === `https`);
49
+ return [...http, ...http.map((s) => WS_OF[s])];
50
+ }
51
+ var documentBase = () => typeof document !== `undefined` && document.baseURI ? document.baseURI : undefined;
52
+ function decideOne(url, policy, schemes) {
53
+ const baseUrl = policy?.baseUrl ?? documentBase();
54
+ let parsed;
55
+ try {
56
+ parsed = new URL(url.trim(), baseUrl);
57
+ } catch {
58
+ return { allowed: false, reason: `invalid` };
59
+ }
60
+ const scheme = parsed.protocol.replace(/:$/, ``).toLowerCase();
61
+ if (!schemes.includes(scheme))
62
+ return { allowed: false, url: parsed.href, reason: `scheme` };
63
+ const twin = scheme === `ws` ? `http:${parsed.href.slice(3)}` : scheme === `wss` ? `https:${parsed.href.slice(4)}` : parsed.href;
64
+ const own = ownPrivateHosts();
65
+ const allowPrivate = own.length ? [...policy?.allowPrivate ?? [], ...own] : policy?.allowPrivate;
66
+ const d = decideUrl({ schemes: [`http`, `https`], hosts: policy?.hosts, allowPrivate, baseUrl }, twin);
67
+ return d.allowed ? { allowed: true, url: parsed.href } : { allowed: false, url: parsed.href, reason: d.reason };
68
+ }
69
+ function decideTransport2(attrs, policy) {
70
+ const schemes = transportSchemes2(policy);
71
+ const src = decideOne(attrs.src, policy, schemes);
72
+ const post = attrs.post ? decideOne(attrs.post, policy, schemes) : undefined;
73
+ const denied = !src.allowed ? [`src`, src] : post && !post.allowed ? [`post`, post] : undefined;
74
+ return denied ? { allowed: false, src, post, reason: `${denied[0]} denied by the URL policy (${denied[1].reason})` } : { allowed: true, src, post };
75
+ }
76
+ function createHost2(attrs, extensions = [], policy) {
77
+ const decision = decideTransport2(attrs, policy);
78
+ if (!decision.allowed)
79
+ throw new Error(`exponential-ui: ${decision.reason}`);
80
+ return new ExponentialHost({ transport: createTransport2(attrs), extensions });
81
+ }
82
+ var transportKey = (attrs) => `${transportKind2(attrs)}\x00${attrs.src}\x00${attrs.post ?? ``}`;
83
+
84
+ // packages/exponential-ui-element/src/element.ts
85
+ var TAG2 = `exponential-surface`;
86
+ var ATTRIBUTES = {
87
+ theme: `theme`,
88
+ mode: `mode`,
89
+ density: `density`,
90
+ contrast: `contrast`,
91
+ locale: `locale`,
92
+ "time-zone": `timeZone`,
93
+ direction: `direction`,
94
+ width: `width`,
95
+ height: `height`,
96
+ "surface-id": `surfaceId`,
97
+ src: `src`,
98
+ post: `post`,
99
+ transport: `transport`
100
+ };
101
+ var ATTRIBUTE_OF = Object.fromEntries(Object.entries(ATTRIBUTES).map(([a, p]) => [p, a]));
102
+ var pick = (value, allowed) => typeof value === `string` && allowed.includes(value) ? value : undefined;
103
+ function lengthOf2(value) {
104
+ if (value === null || value === undefined || value === ``)
105
+ return;
106
+ if (typeof value === `number`)
107
+ return Number.isFinite(value) ? value : undefined;
108
+ const t = value.trim();
109
+ return /^-?\d+(\.\d+)?$/.test(t) ? Number(t) : t;
110
+ }
111
+ var PROPERTIES = [...Object.values(ATTRIBUTES), `surface`, `root`, `templates`, `data`, `host`, `plugin`, `extensions`, `strings`, `states`, `measure`, `viewportHeight`];
112
+ var isConnectable = (h) => h.hasTransport && h.status === `closed`;
113
+ var burst = null;
114
+
115
+ class ExponentialSurfaceElement2 extends HTMLElement {
116
+ static get observedAttributes() {
117
+ return Object.keys(ATTRIBUTES);
118
+ }
119
+ #theme = createSignal(undefined);
120
+ #mode = createSignal(undefined);
121
+ #density = createSignal(undefined);
122
+ #contrast = createSignal(undefined);
123
+ #locale = createSignal(undefined);
124
+ #timeZone = createSignal(undefined);
125
+ #direction = createSignal(undefined);
126
+ #width = createSignal(undefined);
127
+ #height = createSignal(undefined);
128
+ #surfaceId = createSignal(undefined);
129
+ #src = createSignal(undefined);
130
+ #post = createSignal(undefined);
131
+ #transport = createSignal(undefined);
132
+ #surface = createSignal(undefined);
133
+ #root = createSignal(undefined);
134
+ #templates = createSignal(undefined);
135
+ #data = createSignal(undefined);
136
+ #host = createSignal(undefined);
137
+ #plugin = createSignal(undefined);
138
+ #extensions = createSignal(undefined);
139
+ #strings = createSignal(undefined);
140
+ #states = createSignal(undefined);
141
+ #measure = createSignal(undefined);
142
+ #viewportHeight = createSignal(undefined);
143
+ #store = createSignal(null);
144
+ #storeDispose;
145
+ #built;
146
+ #status = createSignal(undefined);
147
+ #denied = createSignal(undefined);
148
+ #liveHost;
149
+ #currentSurface = () => null;
150
+ #handle = null;
151
+ #ready = false;
152
+ #dispose;
153
+ #reflecting = false;
154
+ attributeChangedCallback(name, _old, value) {
155
+ if (this.#reflecting)
156
+ return;
157
+ const prop = ATTRIBUTES[name];
158
+ if (prop)
159
+ this.#signal(prop)[1](() => value ?? undefined);
160
+ }
161
+ #signal(prop) {
162
+ switch (prop) {
163
+ case `theme`:
164
+ return this.#theme;
165
+ case `mode`:
166
+ return this.#mode;
167
+ case `density`:
168
+ return this.#density;
169
+ case `contrast`:
170
+ return this.#contrast;
171
+ case `locale`:
172
+ return this.#locale;
173
+ case `timeZone`:
174
+ return this.#timeZone;
175
+ case `direction`:
176
+ return this.#direction;
177
+ case `width`:
178
+ return this.#width;
179
+ case `height`:
180
+ return this.#height;
181
+ case `surfaceId`:
182
+ return this.#surfaceId;
183
+ case `src`:
184
+ return this.#src;
185
+ case `post`:
186
+ return this.#post;
187
+ case `transport`:
188
+ return this.#transport;
189
+ }
190
+ }
191
+ #setAttrProp(prop, value) {
192
+ const attr = ATTRIBUTE_OF[prop];
193
+ if (typeof value === `string` || value === null || value === undefined) {
194
+ this.#reflecting = true;
195
+ try {
196
+ if (typeof value === `string`)
197
+ this.setAttribute(attr, value);
198
+ else
199
+ this.removeAttribute(attr);
200
+ } finally {
201
+ this.#reflecting = false;
202
+ }
203
+ }
204
+ this.#signal(prop)[1](() => value ?? undefined);
205
+ }
206
+ get theme() {
207
+ return this.#theme[0]();
208
+ }
209
+ set theme(v) {
210
+ this.#setAttrProp(`theme`, v);
211
+ }
212
+ get mode() {
213
+ return this.#mode[0]();
214
+ }
215
+ set mode(v) {
216
+ this.#setAttrProp(`mode`, v);
217
+ }
218
+ get density() {
219
+ return this.#density[0]();
220
+ }
221
+ set density(v) {
222
+ this.#setAttrProp(`density`, v);
223
+ }
224
+ get contrast() {
225
+ return this.#contrast[0]();
226
+ }
227
+ set contrast(v) {
228
+ this.#setAttrProp(`contrast`, v);
229
+ }
230
+ get locale() {
231
+ return this.#locale[0]();
232
+ }
233
+ set locale(v) {
234
+ this.#setAttrProp(`locale`, v);
235
+ }
236
+ get timeZone() {
237
+ return this.#timeZone[0]();
238
+ }
239
+ set timeZone(v) {
240
+ this.#setAttrProp(`timeZone`, v);
241
+ }
242
+ get direction() {
243
+ return this.#direction[0]();
244
+ }
245
+ set direction(v) {
246
+ this.#setAttrProp(`direction`, v);
247
+ }
248
+ get width() {
249
+ return this.#width[0]();
250
+ }
251
+ set width(v) {
252
+ this.#setAttrProp(`width`, v);
253
+ }
254
+ get height() {
255
+ return this.#height[0]();
256
+ }
257
+ set height(v) {
258
+ this.#setAttrProp(`height`, v);
259
+ }
260
+ get surfaceId() {
261
+ return this.#surfaceId[0]() || `main`;
262
+ }
263
+ set surfaceId(v) {
264
+ this.#setAttrProp(`surfaceId`, v);
265
+ }
266
+ get src() {
267
+ return this.#src[0]();
268
+ }
269
+ set src(v) {
270
+ this.#setAttrProp(`src`, v);
271
+ }
272
+ get post() {
273
+ return this.#post[0]();
274
+ }
275
+ set post(v) {
276
+ this.#setAttrProp(`post`, v);
277
+ }
278
+ get transport() {
279
+ return this.#transport[0]();
280
+ }
281
+ set transport(v) {
282
+ this.#setAttrProp(`transport`, v);
283
+ }
284
+ get surface() {
285
+ return this.#surface[0]();
286
+ }
287
+ set surface(v) {
288
+ this.#surface[1](() => v ?? undefined);
289
+ }
290
+ get root() {
291
+ return this.#root[0]();
292
+ }
293
+ set root(v) {
294
+ this.#root[1](() => v);
295
+ }
296
+ get templates() {
297
+ return this.#templates[0]();
298
+ }
299
+ set templates(v) {
300
+ this.#templates[1](() => v ?? undefined);
301
+ }
302
+ get data() {
303
+ return this.#data[0]();
304
+ }
305
+ set data(v) {
306
+ this.#data[1](() => v ?? undefined);
307
+ }
308
+ get host() {
309
+ return this.#host[0]();
310
+ }
311
+ set host(v) {
312
+ this.#host[1](() => v ?? undefined);
313
+ }
314
+ get plugin() {
315
+ return this.#plugin[0]();
316
+ }
317
+ set plugin(v) {
318
+ this.#plugin[1](() => v ?? undefined);
319
+ }
320
+ get extensions() {
321
+ return this.#extensions[0]();
322
+ }
323
+ set extensions(v) {
324
+ this.#extensions[1](() => v ?? undefined);
325
+ }
326
+ get strings() {
327
+ return this.#strings[0]();
328
+ }
329
+ set strings(v) {
330
+ this.#strings[1](() => v ?? undefined);
331
+ }
332
+ get states() {
333
+ return this.#states[0]();
334
+ }
335
+ set states(v) {
336
+ this.#states[1](() => v ?? undefined);
337
+ }
338
+ get measure() {
339
+ return this.#measure[0]();
340
+ }
341
+ set measure(v) {
342
+ this.#measure[1](() => v ?? undefined);
343
+ }
344
+ get viewportHeight() {
345
+ return this.#viewportHeight[0]();
346
+ }
347
+ set viewportHeight(v) {
348
+ this.#viewportHeight[1](() => v ?? undefined);
349
+ }
350
+ get handle() {
351
+ return this.#handle;
352
+ }
353
+ get issues() {
354
+ return this.surfaceState?.issues ?? [];
355
+ }
356
+ get status() {
357
+ return (this.#liveHost ?? this.#host[0]())?.status ?? this.#status[0]()?.status;
358
+ }
359
+ get statusDetail() {
360
+ return (this.#liveHost ?? this.#host[0]())?.statusDetail ?? this.#status[0]()?.detail;
361
+ }
362
+ get surfaceState() {
363
+ return untrack(() => this.#surface[0]() ?? this.#currentSurface() ?? this.#ownStore());
364
+ }
365
+ #ownStore() {
366
+ const s = this.#store[0]();
367
+ return s && s.surfaceId === this.surfaceId ? s : null;
368
+ }
369
+ #activeHost() {
370
+ const given = this.#host[0]();
371
+ if (given) {
372
+ this.#dropBuilt();
373
+ this.#denied[1](undefined);
374
+ return given;
375
+ }
376
+ const src = this.#src[0]();
377
+ if (!src) {
378
+ this.#dropBuilt();
379
+ this.#denied[1](undefined);
380
+ return;
381
+ }
382
+ const attrs = { src, post: this.#post[0](), transport: this.#transport[0]() };
383
+ const policy = this.#plugin[0]()?.urls;
384
+ const decision = decideTransport2(attrs, policy);
385
+ if (!decision.allowed) {
386
+ this.#dropBuilt();
387
+ this.#denied[1](decision.reason);
388
+ return;
389
+ }
390
+ this.#denied[1](undefined);
391
+ const key = transportKey(attrs);
392
+ if (this.#built?.key !== key) {
393
+ this.#dropBuilt();
394
+ this.#built = { key, host: createHost2(attrs, extensionCatalogs(untrack(() => this.#extensions[0]()) ?? []), policy) };
395
+ }
396
+ return this.#built.host;
397
+ }
398
+ #dropBuilt() {
399
+ const b = this.#built;
400
+ this.#built = undefined;
401
+ b?.host.close();
402
+ }
403
+ apply(message) {
404
+ const given = untrack(() => this.#surface[0]());
405
+ if (given)
406
+ return given.apply(message);
407
+ const host = untrack(() => this.#activeHost());
408
+ if (host) {
409
+ host.receive(message);
410
+ return;
411
+ }
412
+ let store = untrack(() => this.#ownStore());
413
+ if (!store) {
414
+ this.#storeDispose?.();
415
+ const surfaceId = this.surfaceId;
416
+ store = createRoot((dispose) => {
417
+ this.#storeDispose = dispose;
418
+ return createSurface({ surfaceId });
419
+ });
420
+ this.#store[1](() => store);
421
+ }
422
+ store.apply(message);
423
+ }
424
+ setData(pointer, value) {
425
+ const state = this.surfaceState;
426
+ if (state)
427
+ state.setData(pointer, value);
428
+ else
429
+ this.data = setPointer(untrack(() => this.#data[0]()) ?? {}, pointer, value);
430
+ }
431
+ reset() {
432
+ this.surfaceState?.reset();
433
+ }
434
+ run(command) {
435
+ this.#handle?.run(command);
436
+ }
437
+ focus(id) {
438
+ if (typeof id !== `string`) {
439
+ super.focus(id);
440
+ return true;
441
+ }
442
+ return this.#handle?.focus(id) ?? false;
443
+ }
444
+ announce(text, live) {
445
+ this.#handle?.announce(text, live);
446
+ }
447
+ scrollIntoView(id) {
448
+ if (typeof id !== `string`) {
449
+ super.scrollIntoView(id);
450
+ return true;
451
+ }
452
+ return this.#handle?.scrollIntoView(id) ?? false;
453
+ }
454
+ scrollToIndex(id, index, align) {
455
+ return this.#handle?.scrollToIndex(id, index, align) ?? false;
456
+ }
457
+ #elementPlugin(base) {
458
+ return {
459
+ ...base,
460
+ onAction: (e) => {
461
+ const own = base.onAction?.(e);
462
+ return joinPending([own, ...emitWaiting(this, `xui-action`, e)]);
463
+ },
464
+ onInput: (e) => {
465
+ const own = base.onInput?.(e);
466
+ return joinPending([own, ...emitWaiting(this, `xui-input`, e)]);
467
+ },
468
+ onUpload: (files, target) => {
469
+ const own = base.onUpload?.(files, target);
470
+ return joinPending([own, ...emitWaiting(this, `xui-upload`, { files, target })]);
471
+ },
472
+ onFunctionCall: (call) => {
473
+ const own = base.onFunctionCall?.(call);
474
+ let answered = false;
475
+ let answer;
476
+ emit(this, `xui-function-call`, {
477
+ call,
478
+ respond: (value) => {
479
+ if (answered)
480
+ return;
481
+ answered = true;
482
+ answer = value;
483
+ }
484
+ });
485
+ return answered ? answer : own;
486
+ },
487
+ openUrl: (url) => {
488
+ if (!emit(this, `xui-open-url`, { url }, true))
489
+ return;
490
+ if (base.openUrl)
491
+ base.openUrl(url);
492
+ else if (typeof window !== `undefined`)
493
+ window.open(url, `_blank`, `noopener,noreferrer`);
494
+ },
495
+ onPaintError: (error) => {
496
+ base.onPaintError?.(error);
497
+ emit(this, `xui-paint-error`, { error });
498
+ },
499
+ onThemeIssues: (issues) => {
500
+ base.onThemeIssues?.(issues);
501
+ emit(this, `xui-theme-issues`, { issues });
502
+ },
503
+ onUnknown: (node) => {
504
+ base.onUnknown?.(node);
505
+ emit(this, `xui-unknown`, { node });
506
+ }
507
+ };
508
+ }
509
+ #hostPlugin(host, base) {
510
+ const merged = hostPlugin(host, this.#elementPlugin(base));
511
+ return {
512
+ ...merged,
513
+ openUrl: (url) => {
514
+ if (!emit(this, `xui-open-url`, { url }, true))
515
+ return;
516
+ if (base.openUrl)
517
+ base.openUrl(url);
518
+ else
519
+ host.openUrl(url);
520
+ }
521
+ };
522
+ }
523
+ #upgradeProperties() {
524
+ for (const name of PROPERTIES) {
525
+ if (!Object.prototype.hasOwnProperty.call(this, name))
526
+ continue;
527
+ const value = this[name];
528
+ delete this[name];
529
+ this[name] = value;
530
+ }
531
+ }
532
+ connectedCallback() {
533
+ this.#upgradeProperties();
534
+ if (this.#dispose)
535
+ return;
536
+ if (burst) {
537
+ burst.add(this);
538
+ return;
539
+ }
540
+ burst = new Set;
541
+ queueMicrotask(() => {
542
+ const pending = burst;
543
+ burst = null;
544
+ if (pending?.size)
545
+ batch(() => pending.forEach((el) => el.#mount()));
546
+ });
547
+ this.#mount();
548
+ }
549
+ #mount() {
550
+ if (this.#dispose || !this.isConnected)
551
+ return;
552
+ this.replaceChildren();
553
+ this.#ready = false;
554
+ this.#dispose = render(() => this.#view(), this);
555
+ }
556
+ disconnectedCallback() {
557
+ burst?.delete(this);
558
+ const dispose = this.#dispose;
559
+ this.#dispose = undefined;
560
+ dispose?.();
561
+ this.#handle = null;
562
+ this.#currentSurface = () => null;
563
+ this.#dropBuilt();
564
+ this.#status[1](undefined);
565
+ }
566
+ #view() {
567
+ const host = createMemo(() => this.#activeHost());
568
+ createEffect(() => {
569
+ const h = host();
570
+ this.#liveHost = h;
571
+ if (!h) {
572
+ const reason = this.#denied[0]();
573
+ const s = reason ? { status: `closed`, detail: reason } : undefined;
574
+ this.#status[1](s);
575
+ if (s)
576
+ emit(this, `xui-status`, s);
577
+ return;
578
+ }
579
+ let last;
580
+ const check = () => {
581
+ if (last && last.status === h.status && last.detail === h.statusDetail)
582
+ return;
583
+ last = { status: h.status, detail: h.statusDetail };
584
+ this.#status[1](last);
585
+ emit(this, `xui-status`, h.statusDetail === undefined ? { status: h.status } : { status: h.status, detail: h.statusDetail });
586
+ };
587
+ const unsubscribe = h.subscribe(check);
588
+ if (isConnectable(h))
589
+ h.connect();
590
+ check();
591
+ onCleanup(() => {
592
+ unsubscribe();
593
+ if (this.#liveHost === h)
594
+ this.#liveHost = undefined;
595
+ });
596
+ });
597
+ const hostSurface = createMemo(() => {
598
+ const h = host();
599
+ return h ? createHostSurface(h, this.surfaceId) : undefined;
600
+ });
601
+ const current = createMemo(() => this.#surface[0]() ?? hostSurface()?.() ?? this.#ownStore());
602
+ this.#currentSurface = current;
603
+ const plugin = createMemo(() => {
604
+ const base = this.#plugin[0]() ?? {};
605
+ const h = host();
606
+ return h ? this.#hostPlugin(h, base) : this.#elementPlugin(base);
607
+ });
608
+ const fixture = () => !current();
609
+ const height = () => lengthOf2(this.#height[0]());
610
+ const handleRef = (handle) => {
611
+ this.#handle = handle;
612
+ if (this.#ready)
613
+ return;
614
+ this.#ready = true;
615
+ queueMicrotask(() => {
616
+ if (this.#handle === handle && this.isConnected)
617
+ emit(this, `xui-ready`, { handle });
618
+ });
619
+ };
620
+ const el = this;
621
+ const props = {
622
+ get surface() {
623
+ return current() ?? undefined;
624
+ },
625
+ get root() {
626
+ return fixture() ? el.#root[0]() : undefined;
627
+ },
628
+ get templates() {
629
+ return fixture() ? el.#templates[0]() : undefined;
630
+ },
631
+ get data() {
632
+ return fixture() ? el.#data[0]() : undefined;
633
+ },
634
+ get theme() {
635
+ return current()?.theme ?? el.#theme[0]();
636
+ },
637
+ get mode() {
638
+ return pick(el.#mode[0](), [`light`, `dark`, `system`]);
639
+ },
640
+ get density() {
641
+ return pick(el.#density[0](), [`compact`, `default`, `comfortable`]);
642
+ },
643
+ get contrast() {
644
+ return pick(el.#contrast[0](), [`normal`, `high`, `system`]);
645
+ },
646
+ get locale() {
647
+ return el.#locale[0]() || undefined;
648
+ },
649
+ get timeZone() {
650
+ return el.#timeZone[0]() || undefined;
651
+ },
652
+ get direction() {
653
+ return pick(el.#direction[0](), [`ltr`, `rtl`]);
654
+ },
655
+ get width() {
656
+ return lengthOf2(el.#width[0]());
657
+ },
658
+ get style() {
659
+ const h = height();
660
+ return h === undefined ? undefined : { height: px(h) };
661
+ },
662
+ get viewportHeight() {
663
+ return el.#viewportHeight[0]();
664
+ },
665
+ get strings() {
666
+ return el.#strings[0]();
667
+ },
668
+ get extensions() {
669
+ return el.#extensions[0]();
670
+ },
671
+ get states() {
672
+ return el.#states[0]();
673
+ },
674
+ get measure() {
675
+ return el.#measure[0]();
676
+ },
677
+ get host() {
678
+ return plugin();
679
+ },
680
+ get id() {
681
+ return el.surfaceId;
682
+ },
683
+ handleRef
684
+ };
685
+ return createComponent(Show, {
686
+ get when() {
687
+ return !host() && !el.#denied[0]() || el.#surface[0]() !== undefined || current() !== null;
688
+ },
689
+ get children() {
690
+ return createComponent(ExponentialSurface, props);
691
+ }
692
+ });
693
+ }
694
+ }
695
+ // packages/exponential-ui-element/src/icons.ts
696
+ import { createRenderEffect } from "solid-js";
697
+ var SKIP = new Set([`size`, `class`, `color`, `strokeWidth`, `absoluteStrokeWidth`, `children`, `ref`, `width`, `height`]);
698
+ function sanitize(root) {
699
+ for (const el of Array.from(root.querySelectorAll(`script,foreignObject`)))
700
+ el.remove();
701
+ for (const el of [root, ...Array.from(root.querySelectorAll(`*`))]) {
702
+ for (const a of Array.from(el.attributes)) {
703
+ if (/^on/i.test(a.name) || /(^|:)href$/i.test(a.name) && /^\s*javascript:/i.test(a.value))
704
+ el.removeAttribute(a.name);
705
+ }
706
+ }
707
+ }
708
+ function parse(markup) {
709
+ if (typeof document === `undefined`)
710
+ return null;
711
+ const t = document.createElement(`template`);
712
+ t.innerHTML = markup.trim();
713
+ const svg = t.content.firstElementChild;
714
+ if (!svg || svg.localName !== `svg`)
715
+ return null;
716
+ sanitize(svg);
717
+ return svg;
718
+ }
719
+ var classTokens = (...values) => values.flatMap((v) => (v ?? ``).split(/\s+/)).filter((c, i, all) => c !== `` && all.indexOf(c) === i).join(` `);
720
+ function svgIcon2(markup) {
721
+ let template;
722
+ return (props) => {
723
+ if (template === undefined)
724
+ template = parse(markup);
725
+ if (!template)
726
+ return null;
727
+ const svg = template.cloneNode(true);
728
+ const base = template.getAttribute(`class`);
729
+ let written = new Set;
730
+ createRenderEffect(() => {
731
+ const next = new Set;
732
+ const set = (name, value) => {
733
+ if (value === undefined || value === null || value === false)
734
+ return;
735
+ svg.setAttribute(name, String(value));
736
+ next.add(name);
737
+ };
738
+ const size = props.size;
739
+ set(`width`, props.width ?? size ?? 24);
740
+ set(`height`, props.height ?? size ?? 24);
741
+ const cls = classTokens(base, props.class);
742
+ if (cls)
743
+ set(`class`, cls);
744
+ if (props.color !== undefined)
745
+ set(`stroke`, props.color);
746
+ if (props.strokeWidth !== undefined)
747
+ set(`stroke-width`, props.strokeWidth);
748
+ const keys = Object.keys(props);
749
+ const a11y = keys.some((k) => k.startsWith(`aria-`) || k === `role` || k === `title`);
750
+ if (!a11y)
751
+ set(`aria-hidden`, `true`);
752
+ for (const k of keys) {
753
+ if (SKIP.has(k))
754
+ continue;
755
+ const v = props[k];
756
+ if (typeof v === `string` || typeof v === `number` || v === true)
757
+ set(k, v);
758
+ }
759
+ for (const name of written) {
760
+ if (next.has(name))
761
+ continue;
762
+ const own = template.getAttribute(name);
763
+ if (own === null)
764
+ svg.removeAttribute(name);
765
+ else
766
+ svg.setAttribute(name, own);
767
+ }
768
+ written = next;
769
+ });
770
+ return svg;
771
+ };
772
+ }
773
+ function iconsFromSvg2(resolve) {
774
+ const byMarkup = new Map;
775
+ return (name) => {
776
+ const markup = resolve(name);
777
+ if (!markup)
778
+ return;
779
+ let icon = byMarkup.get(markup);
780
+ if (!icon) {
781
+ icon = svgIcon2(markup);
782
+ byMarkup.set(markup, icon);
783
+ }
784
+ return icon;
785
+ };
786
+ }
787
+ // packages/exponential-ui-element/src/extensions.ts
788
+ import { children as resolveChildren, createMemo as createMemo2, getOwner, runWithOwner, untrack as untrack2 } from "solid-js";
789
+ import { defineSolidExtension, registerExtension as registerSolidExtension } from "@exponential-at/ui-solid";
790
+ function applyRootProps2(el, rootProps) {
791
+ for (const [name, value] of Object.entries(rootProps)) {
792
+ if (value === undefined || value === null)
793
+ continue;
794
+ if (name === `class`) {
795
+ for (const c of String(value).split(/\s+/))
796
+ if (c)
797
+ el.classList.add(c);
798
+ } else if (name === `style`) {
799
+ const style = el.style;
800
+ if (!style || typeof value !== `object`)
801
+ continue;
802
+ for (const [k, v] of Object.entries(value))
803
+ if (v !== undefined && v !== null)
804
+ style.setProperty(k, String(v));
805
+ } else
806
+ el.setAttribute(name, String(value));
807
+ }
808
+ }
809
+ var toNodes = (value) => {
810
+ const out = [];
811
+ const visit = (v) => {
812
+ if (Array.isArray(v))
813
+ v.forEach(visit);
814
+ else if (typeof v === `function`)
815
+ visit(v());
816
+ else if (v instanceof Node)
817
+ out.push(v);
818
+ else if (typeof v === `string` || typeof v === `number`)
819
+ out.push(document.createTextNode(String(v)));
820
+ };
821
+ visit(value);
822
+ return out;
823
+ };
824
+ function adapt(painter) {
825
+ return (p) => {
826
+ const owner = getOwner();
827
+ const kids = resolveChildren(() => p.children);
828
+ const slots = new Map;
829
+ const slotOf = (name) => {
830
+ let hit = slots.get(name);
831
+ if (!hit) {
832
+ hit = runWithOwner(owner, () => resolveChildren(() => untrack2(() => p.slots)[name]));
833
+ slots.set(name, hit);
834
+ }
835
+ return hit;
836
+ };
837
+ for (const name of Object.keys(untrack2(() => p.node.slots) ?? {}))
838
+ slotOf(name);
839
+ const painted = createMemo2(() => {
840
+ const rootProps = p.rootProps;
841
+ const ctx = {
842
+ node: p.node,
843
+ props: p.props,
844
+ theme: p.theme,
845
+ mode: p.mode,
846
+ tokens: p.tokens,
847
+ emit: p.emit,
848
+ rootProps,
849
+ applyRootProps: (el) => applyRootProps2(el, rootProps),
850
+ children: () => toNodes(kids()),
851
+ slot: (name) => p.node.slots?.[name] ? toNodes(slotOf(name)()) : []
852
+ };
853
+ return painter(ctx);
854
+ });
855
+ return painted;
856
+ };
857
+ }
858
+ function defineElementExtension2(options) {
859
+ const components = {};
860
+ for (const [name, painter] of Object.entries(options.components))
861
+ components[name] = adapt(painter);
862
+ return defineSolidExtension({ catalog: options.catalog, components });
863
+ }
864
+ function registerExtension2(extension) {
865
+ const options = `catalog` in extension && extension.catalog === null ? { components: extension.components } : extension;
866
+ return registerSolidExtension(options);
867
+ }
868
+
869
+ // packages/exponential-ui-element/src/index.ts
870
+ import { defineSolidExtension as defineSolidExtension2, createSurface as createSurface2 } from "@exponential-at/ui-solid";
871
+ function define2(tag = TAG2) {
872
+ if (typeof customElements === `undefined`)
873
+ return;
874
+ const existing = customElements.get(tag);
875
+ if (existing) {
876
+ if (existing === ExponentialSurfaceElement2 || existing.prototype instanceof ExponentialSurfaceElement2)
877
+ return;
878
+ throw new Error(`exponential-ui: <${tag}> is already defined by another class (a second copy of @exponential-at/ui-element, or another library); pick another tag with define("my-surface")`);
879
+ }
880
+ customElements.define(tag, tag === TAG2 ? ExponentialSurfaceElement2 : class extends ExponentialSurfaceElement2 {
881
+ });
882
+ installHostRule2(tag);
883
+ }
884
+ function installHostRule2(tag) {
885
+ if (typeof document === `undefined` || !document.head)
886
+ return;
887
+ if (document.head.querySelector(`style[data-xui-element="${tag}"]`))
888
+ return;
889
+ const style = document.createElement(`style`);
890
+ style.setAttribute(`data-xui-element`, tag);
891
+ style.textContent = `:where(${tag}){display:contents}`;
892
+ document.head.appendChild(style);
893
+ }
894
+
895
+ export { transportKind2, createTransport2, transportSchemes2, decideTransport2, createHost2, TAG2, lengthOf2, ExponentialSurfaceElement2, svgIcon2, iconsFromSvg2, applyRootProps2, defineElementExtension2, registerExtension2, define2, installHostRule2, defineSolidExtension2, createSurface2 };
896
+
897
+ //# debugId=61792AA23A38D24D64756E2164756E21
898
+ //# sourceMappingURL=index-yte5bftp.js.map