ranui
Version:
A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.
176 lines (175 loc) • 8.31 kB
JavaScript
import { T as h, i as a, n as f, p } from "./factory-WDxu11V0.js";
import { t as _ } from "./events-Cqz3ramM.js";
import "./builder-EH76YCFS.js";
import { a as u, i as l, n as d, o as b, t as m } from "./utils-U-9uH7EX.js";
import { a as w, n as g } from "./ssr-BzykYefm.js";
import { createBottomFollower as y } from "ranuts/utils";
import { createConversationEngine as x } from "ranuts/conversation";
var E = ":host{display:flex;flex-direction:column;min-height:0;color:var(--ran-conversation-color, var(--ran-color-text));font-size:var(--ran-conversation-font-size, var(--ran-text-copy-2))}:host([hidden]){display:none}.ran-conversation{display:flex;flex:1;flex-direction:column;min-height:0;overflow-y:auto;overscroll-behavior:contain;background:var(--ran-conversation-background, var(--ran-color-bg));overflow-anchor:none}.ran-conversation-list{display:flex;flex-direction:column;box-sizing:border-box;gap:var(--ran-conversation-gap, var(--ran-space-4));margin:0 auto;padding:var(--ran-conversation-padding, var(--ran-space-4));width:100%;max-width:var(--ran-conversation-measure, 46rem)}.ran-conversation-row{display:block;min-width:0;content-visibility:auto;contain-intrinsic-size:auto 8rem}.ran-conversation-older{display:flex;box-sizing:border-box;justify-content:center;margin:0 auto;padding:var(--ran-conversation-padding, var(--ran-space-4)) var(--ran-conversation-padding, var(--ran-space-4)) 0;width:100%;max-width:var(--ran-conversation-measure, 46rem)}.ran-conversation-older[hidden]{display:none}.ran-conversation-older button{border:1px solid var(--ran-conversation-older-border-color, var(--ran-color-border));border-radius:var(--ran-conversation-older-radius, var(--ran-radius-full));background:none;padding:var(--ran-conversation-older-padding, var(--ran-space-1) var(--ran-space-3));color:var(--ran-conversation-older-color, var(--ran-color-text-secondary));font:inherit;font-size:var(--ran-conversation-older-font-size, var(--ran-text-label-3));cursor:pointer}.ran-conversation-older button:hover:not(:disabled){border-color:var(--ran-conversation-older-hover-border-color, var(--ran-color-border-hover));color:var(--ran-conversation-older-hover-color, var(--ran-color-text))}.ran-conversation-older button:disabled{cursor:default;opacity:.6}.ran-conversation-older button:focus-visible{outline:2px solid var(--ran-conversation-focus-color, var(--ran-color-primary));outline-offset:2px}.ran-conversation-footer{flex:none;background:var(--ran-conversation-footer-background, var(--ran-color-bg))}.ran-conversation-empty{padding:var(--ran-conversation-empty-padding, var(--ran-space-8));color:var(--ran-conversation-empty-color, var(--ran-color-text-secondary));text-align:center}", k = "olderrequest", C = class extends g {
_events = new _();
_shadowDom;
_scroll;
_list;
_older;
_olderButton;
_footer;
_views = [];
_engine = null;
_unsubscribe = null;
_follower = null;
_rows = /* @__PURE__ */ new Map();
_emptyRow = null;
static get observedAttributes() {
return [
"follow",
"empty",
"older",
"loading-older",
"sheet"
];
}
constructor() {
super(), this._shadowDom = m(this, E);
const e = h(), t = h(), n = h();
this._scroll = a().class("ran-conversation").attr("part", "conversation").children(a().class("ran-conversation-older").ref(t).attr("part", "older").children(f().ref(n).attr("type", "button").build()).build(), a().class("ran-conversation-list").ref(e).attr("part", "list").build()).build(), this._shadowDom.appendChild(this._scroll), this._footer = a().class("ran-conversation-footer").attr("part", "footer").children(p().attr("name", "footer").build()).build(), this._shadowDom.appendChild(this._footer), this._list = u(e, "list"), this._older = u(t, "older"), this._olderButton = u(n, "older button"), this._older.hidden = !0;
}
get older() {
return d(this, "older");
}
set older(e) {
l(this, "older", e);
}
get loadingOlder() {
return this.hasAttribute("loading-older");
}
set loadingOlder(e) {
e ? this.setAttribute("loading-older", "") : this.removeAttribute("loading-older");
}
get follow() {
return d(this, "follow", "true") !== "false";
}
set follow(e) {
l(this, "follow", e ? "true" : "false");
}
get empty() {
return d(this, "empty");
}
set empty(e) {
l(this, "empty", e);
}
get sheet() {
return d(this, "sheet");
}
set sheet(e) {
l(this, "sheet", e);
}
get pinned() {
return this._follower?.pinned ?? !0;
}
register(e) {
if (this._engine !== null) throw new Error(`r-conversation: register("${e.kind}") after the first push — register every view first`);
this._views.push(e);
}
push(e) {
this._ensureEngine().push(e);
}
truncate(e) {
return this._engine?.truncate(e) ?? 0;
}
batch(e) {
this._ensureEngine().batch(e);
}
reset() {
this._engine?.reset();
}
scrollToBottom() {
this._follower?.toBottom();
}
captureAnchor(e) {
const t = e === void 0 ? this._list.firstElementChild : this._rows.get(e);
return !(t instanceof HTMLElement) || this._follower === null ? !1 : (this._follower.captureAnchor(t), !0);
}
restoreAnchor() {
return this._follower?.restoreAnchor() ?? !1;
}
connectedCallback() {
this.handlerExternalCss(), this._syncEmpty(), this._syncOlder(), this._events.on(this._olderButton, "click", this._requestOlder), this._follower = y({
scrollport: this._scroll,
observe: [this._list, this._footer],
onPinnedChange: (e) => {
this.dispatchEvent(new CustomEvent("pinnedchange", {
detail: { pinned: e },
bubbles: !0,
composed: !0
}));
}
}), this.follow || this._follower.releaseAnchor();
}
disconnectedCallback() {
this._events.abort(), this._unsubscribe?.(), this._unsubscribe = null, this._follower?.destroy(), this._follower = null, this._engine?.destroy(), this._engine = null;
}
attributeChangedCallback(e, t, n) {
t !== n && (e === "sheet" && this.handlerExternalCss(), e === "empty" && this._syncEmpty(), (e === "older" || e === "loading-older") && this._syncOlder());
}
handlerExternalCss = () => {
b(this, this._shadowDom, "sheet", null, this.sheet);
};
_ensureEngine() {
if (this._engine !== null) return this._engine;
const e = x({ definitions: this._views });
return this._unsubscribe = e.subscribe((t, n) => {
this._renderNodes(t, n);
}), this._engine = e, e;
}
_viewFor(e) {
return this._views.find((t) => t.kind === e);
}
_renderNodes(e, t) {
const n = /* @__PURE__ */ new Set();
for (const r of e) {
const o = this._viewFor(r.kind);
if (o?.mount === void 0) continue;
n.add(r.key);
let i = this._rows.get(r.key), v = !1;
if (i === void 0) {
const s = o.mount(r);
if (s === null) continue;
s.classList.add("ran-conversation-row"), s.setAttribute("part", "row"), s.dataset.kind = r.kind, s.dataset.key = r.key, this._rows.set(r.key, s), i = s, v = !0;
}
(v || t === void 0 || t.has(r.key)) && o.patch?.(i, r);
}
for (const [r, o] of this._rows)
n.has(r) || (o.remove(), this._rows.delete(r));
let c = null;
for (const r of e) {
const o = this._rows.get(r.key);
if (o === void 0) continue;
const i = c === null ? this._list.firstChild : c.nextSibling;
i !== o && this._list.insertBefore(o, i), c = o;
}
this._syncEmpty(), this.follow && this._follower?.follow();
}
_requestOlder = () => {
this.loadingOlder || (this.captureAnchor(), this.dispatchEvent(new CustomEvent(k, {
bubbles: !0,
composed: !0
})));
};
_syncOlder() {
const e = this.older;
this._older.hidden = e === "", this._olderButton.textContent = e, this._olderButton.disabled = this.loadingOlder;
}
_syncEmpty() {
const e = this.empty;
if (!(this._rows.size === 0 && e !== "")) {
this._emptyRow?.remove(), this._emptyRow = null;
return;
}
this._emptyRow ??= a().class("ran-conversation-empty").attr("part", "empty").build(), this._emptyRow.textContent = e, this._emptyRow.parentNode === null && this._list.appendChild(this._emptyRow);
}
};
w("r-conversation", C);
export {
k as n,
C as t
};