anentrypoint-design 0.0.160 โ 0.0.162
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.
- package/app-shell.css +25 -0
- package/dist/247420.css +25 -0
- package/dist/247420.js +10 -10
- package/package.json +1 -1
- package/src/components/community.js +8 -3
- package/src/components/editor-primitives.js +16 -9
- package/src/components/shell.js +15 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anentrypoint-design",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.162",
|
|
4
4
|
"description": "247420 design system SDK โ webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/247420.js",
|
|
@@ -37,7 +37,8 @@ export function ServerRail({ servers = [], activeId, onSelect, onAdd } = {}) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export function ChannelItem({ id, name, type = 'text', active, voiceActive, voiceConnecting, badge, draggable, actions = [], participants = [], onClick, onContext } = {}) {
|
|
40
|
-
const
|
|
40
|
+
const ICON_FOR = { voice: 'speaker', forum: 'forum', threaded: 'thread', announcement: 'megaphone', page: 'page', thread: 'thread', text: 'hash' };
|
|
41
|
+
const icon = Icon(ICON_FOR[type] || 'hash', { size: 15 });
|
|
41
42
|
const handleActionClick = (a, e) => { e.stopPropagation(); a.onClick && a.onClick(id, e); };
|
|
42
43
|
return h('div', { class: 'cm-channel-item-wrap', 'data-channel-wrap': id },
|
|
43
44
|
h('div', {
|
|
@@ -238,13 +239,17 @@ export function VoiceStrip({ channelName, status, muted, deafened, onMute, onDea
|
|
|
238
239
|
);
|
|
239
240
|
}
|
|
240
241
|
|
|
241
|
-
export function MobileHeader({ title, onMenu, onMembers } = {}) {
|
|
242
|
+
export function MobileHeader({ title, channelType, channelName, onMenu, onMembers } = {}) {
|
|
243
|
+
const ICON_FOR = { voice: 'speaker', forum: 'forum', threaded: 'thread', announcement: 'megaphone', page: 'page', thread: 'thread', text: 'hash' };
|
|
244
|
+
const titleNode = channelType
|
|
245
|
+
? [Icon(ICON_FOR[channelType] || 'hash', { size: 16 }), ' ' + (channelName || '')]
|
|
246
|
+
: [title || ''];
|
|
242
247
|
return h('div', { class: 'cm-mobile-header', role: 'banner' },
|
|
243
248
|
h('button', {
|
|
244
249
|
class: 'cm-mh-btn', type: 'button', onclick: onMenu,
|
|
245
250
|
title: 'Menu', 'aria-label': 'open navigation menu'
|
|
246
251
|
}, Icon('menu')),
|
|
247
|
-
h('span', { class: 'cm-mh-title' },
|
|
252
|
+
h('span', { class: 'cm-mh-title' }, ...titleNode),
|
|
248
253
|
h('button', {
|
|
249
254
|
class: 'cm-mh-btn', type: 'button', onclick: onMembers,
|
|
250
255
|
title: 'Members', 'aria-label': 'show members'
|
|
@@ -325,15 +325,22 @@ export function ContextMenu({ items = [], anchor = { x: 0, y: 0 }, onClose } = {
|
|
|
325
325
|
ref: (el) => {
|
|
326
326
|
if (!el) return;
|
|
327
327
|
rootEl = el;
|
|
328
|
-
//
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
328
|
+
// Position at the anchor immediately, then clamp once layout has
|
|
329
|
+
// settled โ measuring synchronously in ref reads a zero-size box
|
|
330
|
+
// (children not yet painted), so the clamp must run post-layout.
|
|
331
|
+
const ax = anchor.x || 0, ay = anchor.y || 0;
|
|
332
|
+
el.style.left = ax + 'px';
|
|
333
|
+
el.style.top = ay + 'px';
|
|
334
|
+
const clamp = () => {
|
|
335
|
+
const vw = window.innerWidth, vh = window.innerHeight;
|
|
336
|
+
const r = el.getBoundingClientRect();
|
|
337
|
+
let x = ax, y = ay;
|
|
338
|
+
if (x + r.width > vw) x = Math.max(4, vw - r.width - 4);
|
|
339
|
+
if (y + r.height > vh) y = Math.max(4, vh - r.height - 4);
|
|
340
|
+
el.style.left = x + 'px';
|
|
341
|
+
el.style.top = y + 'px';
|
|
342
|
+
};
|
|
343
|
+
requestAnimationFrame(clamp);
|
|
337
344
|
queueMicrotask(() => { el.querySelector('button[data-ix]')?.focus(); });
|
|
338
345
|
}
|
|
339
346
|
},
|
package/src/components/shell.js
CHANGED
|
@@ -90,7 +90,12 @@ const ICON_PATHS = {
|
|
|
90
90
|
smile: '<circle cx="12" cy="12" r="9"/><path d="M8 14a4 4 0 0 0 8 0"/><path d="M9 9h.01M15 9h.01"/>',
|
|
91
91
|
'more-horizontal': '<circle cx="5" cy="12" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/>',
|
|
92
92
|
'arrow-up': '<path d="M12 19V5M5 12l7-7 7 7"/>',
|
|
93
|
-
send: '<path d="M22 2 11 13M22 2l-7 20-4-9-9-4z"/>'
|
|
93
|
+
send: '<path d="M22 2 11 13M22 2l-7 20-4-9-9-4z"/>',
|
|
94
|
+
hash: '<path d="M4 9h16M4 15h16M10 3 8 21M16 3l-2 18"/>',
|
|
95
|
+
megaphone: '<path d="M3 11v2a1 1 0 0 0 1 1h2l5 4V6L6 10H4a1 1 0 0 0-1 1z"/><path d="M15 8a4 4 0 0 1 0 8M18 5a8 8 0 0 1 0 14"/>',
|
|
96
|
+
forum: '<path d="M4 5h13a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H9l-4 3v-3H4a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1z"/>',
|
|
97
|
+
page: '<path d="M6 3h8l5 5v13a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/><path d="M14 3v5h5M8 13h8M8 17h6"/>',
|
|
98
|
+
thread: '<path d="M5 6h14M5 11h14M5 16h8"/><circle cx="17" cy="17" r="3"/>'
|
|
94
99
|
};
|
|
95
100
|
export function Icon(name, { size = 16 } = {}) {
|
|
96
101
|
const inner = ICON_PATHS[name];
|
|
@@ -189,6 +194,14 @@ function toggleSide(open) {
|
|
|
189
194
|
export function AppShell({ topbar, crumb, side, main, status, narrow } = {}) {
|
|
190
195
|
const hasSide = Boolean(side);
|
|
191
196
|
const sideNode = hasSide ? side : h('aside', { class: 'app-side', 'aria-hidden': 'true' });
|
|
197
|
+
// Topbar and crumb used to stack as two separate chrome bars โ a "double
|
|
198
|
+
// title bar". When both are present, fold them into one sticky row:
|
|
199
|
+
// brand + nav (topbar) and breadcrumb + right slot (crumb) share a single
|
|
200
|
+
// band so the chrome reads as one bar, not two. Either prop alone still
|
|
201
|
+
// renders on its own (consumers that pass only a topbar are unaffected).
|
|
202
|
+
const chrome = (topbar && crumb)
|
|
203
|
+
? h('div', { class: 'app-chrome' }, topbar, crumb)
|
|
204
|
+
: (topbar || crumb || null);
|
|
192
205
|
return h('div', { class: 'app' },
|
|
193
206
|
h('a', { href: '#app-main', class: 'skip-link' }, 'skip to main content'),
|
|
194
207
|
hasSide ? h('button', {
|
|
@@ -196,8 +209,7 @@ export function AppShell({ topbar, crumb, side, main, status, narrow } = {}) {
|
|
|
196
209
|
'aria-label': 'toggle navigation', 'aria-expanded': 'false', 'aria-controls': 'app-main',
|
|
197
210
|
onclick: () => toggleSide(),
|
|
198
211
|
}, Icon('menu')) : null,
|
|
199
|
-
|
|
200
|
-
crumb || null,
|
|
212
|
+
chrome,
|
|
201
213
|
h('div', { class: 'app-body' + (hasSide ? '' : ' no-side') },
|
|
202
214
|
h('div', { class: 'app-side-scrim', 'aria-hidden': 'true', onclick: () => toggleSide(false) }),
|
|
203
215
|
h('div', { class: 'app-side-shell', onclick: (e) => { if (e.target.closest('a')) toggleSide(false); } }, sideNode),
|