Compare commits
No commits in common. "a50a793306d1c96679cfd70f100c0c88f0dd6bf5" and "f2676caa80aeeb578b4c736c1880b0ce868cc094" have entirely different histories.
a50a793306
...
f2676caa80
@ -171,7 +171,6 @@
|
|||||||
- 提交前至少做与改动相关的最小验证(命令输出或手工步骤要可复现)。
|
- 提交前至少做与改动相关的最小验证(命令输出或手工步骤要可复现)。
|
||||||
- 视觉验证默认由用户完成:除非用户特别说明,所有需要视觉确认的修改(尤其是动画/过渡效果),构建/lint 通过后交由用户亲自查看确认,不要用 Playwright 截图或浏览器自动化代替用户验收。
|
- 视觉验证默认由用户完成:除非用户特别说明,所有需要视觉确认的修改(尤其是动画/过渡效果),构建/lint 通过后交由用户亲自查看确认,不要用 Playwright 截图或浏览器自动化代替用户验收。
|
||||||
- 运行根目录前端构建时,默认使用 `npm run build --silent 2>&1 | tail -n 5`。
|
- 运行根目录前端构建时,默认使用 `npm run build --silent 2>&1 | tail -n 5`。
|
||||||
- 构建/安装/Lint 类命令(如 `npm run build`、`npm install`、`npm run lint`)因沙箱权限失败时(如报 `EPERM` / `Operation not permitted` / 沙箱拒绝写入),直接向用户说明失败原因并申请权限或调整路径授权,禁止尝试任何绕过沙箱的做法(如换执行方式规避限制、向其他路径写入等)。
|
|
||||||
|
|
||||||
### CLI 当前交互约束(2026-05-15)
|
### CLI 当前交互约束(2026-05-15)
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, inject, nextTick, onBeforeUnmount, onMounted, onUpdated, ref, watch } from 'vue';
|
import { computed, inject, nextTick, onMounted, onUpdated, ref, watch } from 'vue';
|
||||||
import CodeBlock from './CodeBlock.vue';
|
import CodeBlock from './CodeBlock.vue';
|
||||||
import {
|
import {
|
||||||
parseMarkdownSegments,
|
parseMarkdownSegments,
|
||||||
@ -32,7 +32,6 @@ import {
|
|||||||
type MarkdownSegment
|
type MarkdownSegment
|
||||||
} from '@/composables/useMarkdownRenderer';
|
} from '@/composables/useMarkdownRenderer';
|
||||||
import { chunkRenderedHtml, type HtmlChunk } from '@/utils/htmlChunks';
|
import { chunkRenderedHtml, type HtmlChunk } from '@/utils/htmlChunks';
|
||||||
import { classifyMarkdownTables, observeMarkdownTables } from '@/utils/tableLayout';
|
|
||||||
import { enhanceCitationChips, type CitationAnnotation } from './citationChips';
|
import { enhanceCitationChips, type CitationAnnotation } from './citationChips';
|
||||||
|
|
||||||
defineOptions({ name: 'MarkdownRenderer' });
|
defineOptions({ name: 'MarkdownRenderer' });
|
||||||
@ -106,27 +105,6 @@ function enhanceCitations() {
|
|||||||
onMounted(enhanceCitations);
|
onMounted(enhanceCitations);
|
||||||
onUpdated(enhanceCitations);
|
onUpdated(enhanceCitations);
|
||||||
watch(() => [props.citations, props.citationsFinal], enhanceCitations);
|
watch(() => [props.citations, props.citationsFinal], enhanceCitations);
|
||||||
|
|
||||||
// 表格布局模式(换行/横向滚动):渲染后按内容自然宽度判定,并监听容器宽度变化重判
|
|
||||||
let stopTableObserver: (() => void) | null = null;
|
|
||||||
|
|
||||||
function classifyTables() {
|
|
||||||
nextTick(() => {
|
|
||||||
const el = containerRef.value;
|
|
||||||
if (!el) return;
|
|
||||||
classifyMarkdownTables(el);
|
|
||||||
stopTableObserver?.();
|
|
||||||
stopTableObserver = observeMarkdownTables(el);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(classifyTables);
|
|
||||||
onUpdated(classifyTables);
|
|
||||||
watch(() => props.content, classifyTables);
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
stopTableObserver?.();
|
|
||||||
stopTableObserver = null;
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -872,22 +872,17 @@
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 与正文表格同一横线风格:无外框/无竖线/无底色块;
|
|
||||||
布局模式(换行/横向滚动)由 utils/tableLayout.ts 判定 */
|
|
||||||
.user-message.user-message--multi-agent .bubble-text .md-table-scroll,
|
.user-message.user-message--multi-agent .bubble-text .md-table-scroll,
|
||||||
.user-message.user-message--multi-agent .bubble-text [data-md-table-scroll='1'] {
|
.user-message.user-message--multi-agent .bubble-text [data-md-table-scroll='1'] {
|
||||||
display: block;
|
display: block;
|
||||||
width: auto;
|
width: auto;
|
||||||
max-width: none;
|
max-width: none;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-message.user-message--multi-agent .bubble-text .md-table-scroll[data-md-table-mode='scroll'],
|
|
||||||
.user-message.user-message--multi-agent .bubble-text [data-md-table-scroll='1'][data-md-table-mode='scroll'] {
|
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
-webkit-overflow-scrolling: touch;
|
border: 1px solid var(--border-default);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: color-mix(in srgb, var(--text-primary) 4%, var(--chip-bg));
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-message.user-message--multi-agent .bubble-text .md-table-scroll > table,
|
.user-message.user-message--multi-agent .bubble-text .md-table-scroll > table,
|
||||||
@ -895,38 +890,18 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-message.user-message--multi-agent .bubble-text [data-md-table-mode='scroll'] > table {
|
|
||||||
width: max-content;
|
|
||||||
min-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-message.user-message--multi-agent .bubble-text [data-md-table-mode='scroll'] > table td {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-message.user-message--multi-agent .bubble-text th,
|
.user-message.user-message--multi-agent .bubble-text th,
|
||||||
.user-message.user-message--multi-agent .bubble-text td {
|
.user-message.user-message--multi-agent .bubble-text td {
|
||||||
border: none;
|
border: 1px solid var(--border-default);
|
||||||
padding: 8px 14px 8px 0;
|
padding: 6px 10px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: middle;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-message.user-message--multi-agent .bubble-text th:last-child,
|
.user-message.user-message--multi-agent .bubble-text th {
|
||||||
.user-message.user-message--multi-agent .bubble-text td:last-child {
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-message.user-message--multi-agent .bubble-text thead th {
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
white-space: nowrap;
|
background: color-mix(in srgb, var(--text-primary) 7%, var(--chip-bg));
|
||||||
border-bottom: 1.5px solid var(--border-strong);
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-message.user-message--multi-agent .bubble-text tbody td {
|
|
||||||
border-bottom: 1px solid var(--border-default);
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-block--last
|
.message-block--last
|
||||||
@ -2212,14 +2187,12 @@ show-html[data-rendered='1'] {
|
|||||||
animation: none !important; /* 防止外部动画样式影响代码块,导致视觉抖动 */
|
animation: none !important; /* 防止外部动画样式影响代码块,导致视觉抖动 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表格:清爽横线风格(无外框/无竖线/无底色块)。
|
|
||||||
布局模式由 utils/tableLayout.ts 按内容自然宽度判定:
|
|
||||||
默认换行模式(表格占满内容区、单元格折行);
|
|
||||||
自然宽度超过阈值时容器打 data-md-table-mode='scroll',退化为整表横向滚动。 */
|
|
||||||
.text-output .text-content table {
|
.text-output .text-content table {
|
||||||
width: 100%;
|
width: max-content;
|
||||||
|
min-width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
background: var(--theme-surface-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-output .text-content .md-table-scroll,
|
.text-output .text-content .md-table-scroll,
|
||||||
@ -2227,16 +2200,14 @@ show-html[data-rendered='1'] {
|
|||||||
display: block;
|
display: block;
|
||||||
width: auto;
|
width: auto;
|
||||||
max-width: none;
|
max-width: none;
|
||||||
margin: 12px calc(var(--chat-content-x) * -1);
|
margin: 16px calc(var(--chat-content-x) * -1);
|
||||||
padding: 0 var(--chat-content-x);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-output .text-content .md-table-scroll[data-md-table-mode='scroll'],
|
|
||||||
.text-output .text-content [data-md-table-scroll='1'][data-md-table-mode='scroll'] {
|
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
border: 1px solid var(--border-default);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--theme-surface-soft);
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-output .text-content .md-table-scroll > table,
|
.text-output .text-content .md-table-scroll > table,
|
||||||
@ -2244,62 +2215,47 @@ show-html[data-rendered='1'] {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-output .text-content [data-md-table-mode='scroll'] > table {
|
.text-output .text-content .md-table-scroll::-webkit-scrollbar,
|
||||||
width: max-content;
|
.text-output .text-content [data-md-table-scroll='1']::-webkit-scrollbar {
|
||||||
min-width: 100%;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-output .text-content [data-md-table-mode='scroll'] > table td {
|
.text-output .text-content .md-table-scroll::-webkit-scrollbar-track,
|
||||||
white-space: nowrap;
|
.text-output .text-content [data-md-table-scroll='1']::-webkit-scrollbar-track {
|
||||||
|
background: color-mix(in srgb, var(--theme-surface-muted) 70%, transparent);
|
||||||
|
border-radius: 999px;
|
||||||
|
margin: 0 8px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 细滚动条仅在滚动模式出现 */
|
.text-output .text-content .md-table-scroll::-webkit-scrollbar-thumb,
|
||||||
.text-output .text-content .md-table-scroll[data-md-table-mode='scroll']::-webkit-scrollbar,
|
.text-output .text-content [data-md-table-scroll='1']::-webkit-scrollbar-thumb {
|
||||||
.text-output .text-content [data-md-table-scroll='1'][data-md-table-mode='scroll']::-webkit-scrollbar {
|
background: color-mix(in srgb, var(--text-secondary) 55%, transparent);
|
||||||
height: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-output .text-content .md-table-scroll[data-md-table-mode='scroll']::-webkit-scrollbar-track,
|
|
||||||
.text-output .text-content [data-md-table-scroll='1'][data-md-table-mode='scroll']::-webkit-scrollbar-track {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-output .text-content .md-table-scroll[data-md-table-mode='scroll']::-webkit-scrollbar-thumb,
|
|
||||||
.text-output .text-content [data-md-table-scroll='1'][data-md-table-mode='scroll']::-webkit-scrollbar-thumb {
|
|
||||||
background: color-mix(in srgb, var(--text-secondary) 45%, transparent);
|
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-output .text-content .md-table-scroll[data-md-table-mode='scroll'],
|
.text-output .text-content .md-table-scroll,
|
||||||
.text-output .text-content [data-md-table-scroll='1'][data-md-table-mode='scroll'] {
|
.text-output .text-content [data-md-table-scroll='1'] {
|
||||||
scrollbar-color: color-mix(in srgb, var(--text-secondary) 45%, transparent) transparent;
|
scrollbar-color: color-mix(in srgb, var(--text-secondary) 55%, transparent)
|
||||||
|
color-mix(in srgb, var(--theme-surface-muted) 70%, transparent);
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-output .text-content thead {
|
||||||
|
background: var(--theme-chip-bg);
|
||||||
|
}
|
||||||
|
|
||||||
.text-output .text-content th,
|
.text-output .text-content th,
|
||||||
.text-output .text-content td {
|
.text-output .text-content td {
|
||||||
border: none;
|
border: 1px solid var(--border-default);
|
||||||
padding: 11px 18px 11px 0;
|
padding: 10px 14px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: middle;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-output .text-content th:last-child,
|
.text-output .text-content th {
|
||||||
.text-output .text-content td:last-child {
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-output .text-content thead th {
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
white-space: nowrap;
|
|
||||||
border-bottom: 1.5px solid var(--border-strong);
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-output .text-content tbody td {
|
|
||||||
border-bottom: 1px solid var(--border-default);
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-output .text-content hr {
|
.text-output .text-content hr {
|
||||||
@ -2734,7 +2690,14 @@ body[data-theme='dark'] {
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表格为无底色横线风格,三主题通用,无需覆盖 */
|
/* 表格 */
|
||||||
|
.text-output .text-content table {
|
||||||
|
background: var(--badge-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-output .text-content thead {
|
||||||
|
background: var(--surface-panel);
|
||||||
|
}
|
||||||
|
|
||||||
/* 滚动锁定按钮 */
|
/* 滚动锁定按钮 */
|
||||||
.scroll-lock-btn {
|
.scroll-lock-btn {
|
||||||
@ -2785,10 +2748,9 @@ body[data-theme='dark'] {
|
|||||||
|
|
||||||
/* ========== 明亮主题变体(对话区组件) ========== */
|
/* ========== 明亮主题变体(对话区组件) ========== */
|
||||||
/* 背景:浅色主题表面 token 阶梯近乎纯平(base/card/raised 全为 #ffffff),
|
/* 背景:浅色主题表面 token 阶梯近乎纯平(base/card/raised 全为 #ffffff),
|
||||||
基础样式中代码块白底落白底不可见;
|
基础样式中代码块白底落白底、表格 #f9f9f9 落白底均不可见;
|
||||||
参照上方深色覆盖块的做法,按用户确认的方向做组件级补偿:
|
参照上方深色覆盖块的做法,按用户确认的方向做组件级补偿:
|
||||||
代码块仅头部着色、代码区与对话底保持同色。
|
代码块仅头部着色、代码区与对话底保持同色;表格白体+浅灰表头+可见边框。 */
|
||||||
表格为无底色横线风格,三主题通用,无需补偿。 */
|
|
||||||
body[data-theme='light'] {
|
body[data-theme='light'] {
|
||||||
/* 代码块 - 头部浅灰、代码区与对话底同为白色,外框加强到可见 */
|
/* 代码块 - 头部浅灰、代码区与对话底同为白色,外框加强到可见 */
|
||||||
.code-block-wrapper {
|
.code-block-wrapper {
|
||||||
@ -2799,4 +2761,24 @@ body[data-theme='light'] {
|
|||||||
background: var(--surface-muted);
|
background: var(--surface-muted);
|
||||||
border-bottom-color: var(--border-strong);
|
border-bottom-color: var(--border-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 表格 - 白体 + 浅灰表头 + 可见边框 */
|
||||||
|
.text-output .text-content table {
|
||||||
|
background: var(--surface-raised);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-output .text-content thead {
|
||||||
|
background: var(--surface-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-output .text-content th,
|
||||||
|
.text-output .text-content td {
|
||||||
|
border-color: var(--border-strong);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-output .text-content .md-table-scroll,
|
||||||
|
.text-output .text-content [data-md-table-scroll='1'] {
|
||||||
|
border-color: var(--border-strong);
|
||||||
|
background: var(--surface-raised);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,87 +0,0 @@
|
|||||||
/**
|
|
||||||
* Markdown 表格布局模式判定(换行 / 横向滚动)。
|
|
||||||
*
|
|
||||||
* 测量表格内容的自然宽度(所有单元格单行不折行时的宽度),与滚动容器可用宽度比较:
|
|
||||||
* - 自然宽度 ≤ 可用宽度 × 阈值 → 换行模式(默认,单元格折行、表格占满内容区)
|
|
||||||
* - 自然宽度 > 可用宽度 × 阈值 → 容器打 data-md-table-mode="scroll",退化为整表横向滚动
|
|
||||||
*
|
|
||||||
* 样式侧见 styles/components/chat/_chat-area.scss 的表格段。
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** 自然宽度超出可用宽度的该倍数以内时,仍用换行模式吸收(避免略宽一点的表被迫滚动) */
|
|
||||||
const SCROLL_RATIO_THRESHOLD = 1.35;
|
|
||||||
|
|
||||||
const MODE_ATTR = 'data-md-table-mode';
|
|
||||||
|
|
||||||
const TABLE_SCROLLER_SELECTOR = '.md-table-scroll, [data-md-table-scroll="1"]';
|
|
||||||
|
|
||||||
function measureNaturalWidth(table: HTMLTableElement): number {
|
|
||||||
// 同一帧内临时切到「自然宽度 + 全部不折行」布局测量,读完立即恢复——
|
|
||||||
// 浏览器不会在两次样式变更之间绘制,无闪烁
|
|
||||||
const prevWidth = table.style.width;
|
|
||||||
table.style.width = 'max-content';
|
|
||||||
const cells = table.querySelectorAll('th, td');
|
|
||||||
const savedWhiteSpace: string[] = [];
|
|
||||||
cells.forEach((cell, i) => {
|
|
||||||
const el = cell as HTMLElement;
|
|
||||||
savedWhiteSpace[i] = el.style.whiteSpace;
|
|
||||||
el.style.whiteSpace = 'nowrap';
|
|
||||||
});
|
|
||||||
const width = table.offsetWidth;
|
|
||||||
table.style.width = prevWidth;
|
|
||||||
cells.forEach((cell, i) => {
|
|
||||||
(cell as HTMLElement).style.whiteSpace = savedWhiteSpace[i];
|
|
||||||
});
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
function availableWidth(scroller: HTMLElement): number {
|
|
||||||
const style = getComputedStyle(scroller);
|
|
||||||
return (
|
|
||||||
scroller.clientWidth -
|
|
||||||
parseFloat(style.paddingLeft || '0') -
|
|
||||||
parseFloat(style.paddingRight || '0')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function classifyOne(scroller: HTMLElement): void {
|
|
||||||
const table = scroller.querySelector('table');
|
|
||||||
if (!table) return;
|
|
||||||
const avail = availableWidth(scroller);
|
|
||||||
// 容器不可见(折叠块/未激活标签页内)时宽度为 0,跳过,等可见后由 ResizeObserver 补判
|
|
||||||
if (avail <= 0) return;
|
|
||||||
const natural = measureNaturalWidth(table);
|
|
||||||
const mode = natural <= avail * SCROLL_RATIO_THRESHOLD ? 'wrap' : 'scroll';
|
|
||||||
if (scroller.getAttribute(MODE_ATTR) !== mode) {
|
|
||||||
scroller.setAttribute(MODE_ATTR, mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 扫描 root 下所有 markdown 表格滚动容器,按当前可用宽度重新判定布局模式(幂等) */
|
|
||||||
export function classifyMarkdownTables(root: ParentNode): void {
|
|
||||||
root.querySelectorAll<HTMLElement>(TABLE_SCROLLER_SELECTOR).forEach(classifyOne);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 监听 root 下所有表格滚动容器的宽度变化(窗口缩放 / 侧栏开合),宽度变化时自动重判。
|
|
||||||
* 返回停止函数。仅宽度变化触发,折行引起的高度变化不会重复测量。
|
|
||||||
*/
|
|
||||||
export function observeMarkdownTables(root: ParentNode): () => void {
|
|
||||||
if (typeof ResizeObserver === 'undefined') return () => {};
|
|
||||||
const scrollers = Array.from(root.querySelectorAll<HTMLElement>(TABLE_SCROLLER_SELECTOR));
|
|
||||||
if (!scrollers.length) return () => {};
|
|
||||||
const lastWidths = new WeakMap<HTMLElement, number>();
|
|
||||||
const observer = new ResizeObserver((entries) => {
|
|
||||||
for (const entry of entries) {
|
|
||||||
const el = entry.target as HTMLElement;
|
|
||||||
const width = entry.contentRect.width;
|
|
||||||
const last = lastWidths.get(el);
|
|
||||||
if (last === undefined || Math.abs(width - last) > 1) {
|
|
||||||
lastWidths.set(el, width);
|
|
||||||
classifyOne(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
scrollers.forEach((el) => observer.observe(el));
|
|
||||||
return () => observer.disconnect();
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user