@asteby/metacore-ui (英语)
用于Metacore生态系统的可再使用的UI工具包:一个模块化的TanStack-Table数据表,一个外壳准备版式(侧边栏+头部+认证外壳),一个键盘驱动的命令调色板,钩子,对话框,以及一组被编织的shadcn/ui原始人——全部被构建在React 19,Tailwind 4和Radix的对照下.
安装
pnpm add @asteby/metacore-ui @asteby/metacore-theme react react-dom react-i18next \
@tanstack/react-router @tanstack/react-table @tanstack/react-query
有意松动同伴的依赖关系(反应) >=18坦斯塔克包 用于使用它们, tailwindcss >=4) (中文(简体) ).
快开始
导入 Tailwind 令牌 + shadcn 从 @asteby/metacore-theme,然后从相应的子路径取出组件:
import { AuthenticatedLayout, AppSidebar, NavUser } from '@asteby/metacore-ui/layout'
import { DataTableToolbar, DataTablePagination } from '@asteby/metacore-ui/data-table'
import { CommandMenu } from '@asteby/metacore-ui/command-menu'
import { useTableUrlState } from '@asteby/metacore-ui/hooks'
import { Button, Input } from '@asteby/metacore-ui/primitives'
import { cn } from '@asteby/metacore-ui/lib'
子路径导出
| 条目 | 住在这里的东西 |
|---|---|
@asteby/metacore-ui | 一切(避免——用子道来震树). |
@asteby/metacore-ui/data-table | DataTableToolbar, (中文(简体) ), DataTableBulkActions, (中文(简体) ), DataTableFacetedFilter, (中文(简体) ), DataTableViewOptions, (中文(简体) ), DataTablePagination, (中文(简体) ), DataTableColumnHeader, (中文(简体) ), FilterableColumnHeader。 。 。 . |
@asteby/metacore-ui/layout | AuthenticatedLayout, (中文(简体) ), AppSidebar, (中文(简体) ), Header, (中文(简体) ), NavGroup, (中文(简体) ), NavUser, (中文(简体) ), TeamSwitcher, (中文(简体) ), ProfileDropdown, (中文(简体) ), OrganizationCard。 。 。 . |
@asteby/metacore-ui/dialogs | ConfirmDialog, (中文(简体) ), LearnMore, (中文(简体) ), LongText, (中文(简体) ), PasswordInput, (中文(简体) ), SelectDropdown, (中文(简体) ), SkipToMain。 。 。 . |
@asteby/metacore-ui/command-menu | CommandMenu (路由-不可知论). |
@asteby/metacore-ui/hooks | useTableUrlState, (中文(简体) ), useDialogState, (中文(简体) ), useIsMobile。 。 。 . |
@asteby/metacore-ui/primitives | shadcn/ui原始语: Button, (中文(简体) ), Input, (中文(简体) ), Dialog, (中文(简体) ), DropdownMenu, (中文(简体) ), Popover, (中文(简体) ), Command, (中文(简体) ), Select, (中文(简体) ), Sidebar, (中文(简体) ), Sheet, (中文(简体) ), Table, (中文(简体) ), Tabs, (中文(简体) ), Tooltip, (中文(简体) ), ScrollArea, (中文(简体) ), Sonner, (中文(简体) ), Form, (中文(简体) ), Textarea, (中文(简体) ), Switch, (中文(简体) ), Badge, (中文(简体) ), Avatar, (中文(简体) ), Checkbox, (中文(简体) ), Label, (中文(简体) ), Separator, (中文(简体) ), Skeleton, (中文(简体) ), Collapsible, (中文(简体) ), AlertDialog。 。 。 . |
@asteby/metacore-ui/profile | 详细页包(机动第一): ProfileHeader, (中文(简体) ), SectionCard, (中文(简体) ), StatStrip, (中文(简体) ), DefinitionList, (中文(简体) ), RecordList编号 :RecordRow, (中文(简体) ), ContactLink, (中文(简体) ), EmptyState, (中文(简体) ), PillTabsList编号 :PillTabsTrigger。 。 。 . |
@asteby/metacore-ui/lib | cn, (中文(简体) ), getPageNumbers, (中文(简体) ), getCookie编号 :setCookie编号 :removeCookie, (中文(简体) ), resolveColorCss编号 :resolveColorHex编号 :generateBadgeStyles。 。 。 . |
Button 大小 : default | sm | lg | icon 加上选入室者 comfortable (h-11), (中文(简体) ), comfortable-lg (h-12) 和(h-12) icon-comfortable (大小为-11). 所有按钮都得到按下状态( E)scale .98,在 prefers-reduced-motion) (中文(简体) ). Sidebar 尊重可选主机变量 --app-topbar-h, (中文(简体) ), --app-notice-h (固定上铬)和 --app-bottombar-h (移动平面底部偏移);全部默认为0.
与应用程序内部脱钩
源代码应用程序中依赖 zustand 的多个组件 auth-store,一个 Vite 特定的 api 客户端,或 破旧路由器 <Link> 已通过道具重新设计接收数据:
AppSidebar——收到navGroups, (中文(简体) ),currentHref, (中文(简体) ),LinkComponent, (中文(简体) ),header, (中文(简体) ),footer,以及isLoading作为道具(没有内部认证/导航获取).NavGroup编号 :NavUser编号 :ProfileDropdown——不再从认证商店读取.NavUser编号 :ProfileDropdown接受孩子的菜单正文和可选的退出召回.CommandMenu——收到navGroups, (中文(简体) ),onNavigate选择onThemeChange而不是从useSearch编号 :useTheme/ 硬码sidebarData。 。 。 .AuthenticatedLayout纯外壳 消费者将自己的提供者树(主题、i18n、查询客户端、网络锁子等)组成,并传出sidebar, (中文(简体) ),headerChildren, (中文(简体) ),topBanner,以及widget插槽 .FilterableColumnHeader具体应用软件date_range筛选类型和远程filterSearchEndpoint变体被移除,以避免拉入react-day-picker和一个HTTP客户端.select, (中文(简体) ),boolean, (中文(简体) ),text,以及number_range留下来.
故意特征 没有 销售商: branch-switcher, (中文(简体) ), organization, (中文(简体) ), top-nav, (中文(简体) ), config-drawer, (中文(简体) ), notifications-dropdown, (中文(简体) ), ai-chat ——这些专有应用,属于消费者应用.
状态、页眉、QR和分块控制
只有主题符号(应用程序设置调色板),键盘和屏幕阅读器准备:
import { DataState, PageHeader, QrCodeFrame } from '@asteby/metacore-ui/shared'
import { SegmentedControl } from '@asteby/metacore-ui/primitives'
import { PillTabsList, PillTabsTrigger } from '@asteby/metacore-ui/profile'
// Every non-success state of a query-backed surface
<DataState kind="error" description="Hace 5 min" onRetry={refetch} />
<DataState kind="demo" compact description="Datos demostrativos, no mediciones" />
// kinds: loading | empty | error | forbidden | offline | stale | partial | demo
<PageHeader
icon={Inbox}
title="Bandeja"
description="Conversaciones de todos los canales"
badges={<Badge variant="muted">Demo</Badge>}
actions={<Button>Nueva</Button>}
overflowActions={[{ key: 'export', label: 'Exportar', onSelect: exportCsv }]}
/>
<QrCodeFrame src={qrDataUrl} alt="Código QR para vincular WhatsApp" expired={expired} onRefresh={restart} />
<SegmentedControl aria-label="Vista" value={view} onValueChange={setView}
items={[{ value: 'list', label: 'Lista', icon: List }, { value: 'kanban', label: 'Kanban', icon: Columns3 }]} />
<PillTabsTrigger value="open" count={12}>Abiertas</PillTabsTrigger>
可选 i18n 键(西班牙语后退) : data_state.<kind>, (中文(简体) ), data_state.retry, (中文(简体) ),
page_header.more, (中文(简体) ), qr_frame.loading, (中文(简体) ), qr_frame.expired, (中文(简体) ), qr_frame.refresh。 。 。 .
页面页眉,动作栏,PageShell和后链接(移动先行)
import { ActionBar, BackLink, PageHeader, PageShell, type ActionItem } from '@asteby/metacore-ui/shared'
const items: ActionItem[] = [
{ key: 'dispatch', label: 'Despachar', priority: 'primary', run: dispatch },
{ key: 'edit', label: 'Editar', icon: <Pencil />, run: edit },
{ key: 'print', label: 'Imprimir', icon: <Printer />, priority: 'overflow', run: print },
{ key: 'delete', label: 'Eliminar', destructive: true, confirm: { title: '¿Eliminar SO-00004?' }, run: remove },
]
<PageShell header={
<PageHeader
leading={<BackLink asChild><Link to='/m/warehouse_orders'>Órdenes</Link></BackLink>}
title='SO-00004' titleKind='identifier' subtitle={customerLink}
badges={<Badge>Por surtir</Badge>}
actions={<ActionBar items={items} />}
/>
}>
{body}
</PageShell>
ActionBar 规则(纯规划器导出为 planActionBar 适用于适配器/测试:
- 一个初级. 第一个
priority: 'primary'是唯一一个variant=default;后被降为二级. - 通过测量折叠,不仅仅是断点. A 类
ResizeObserver测量栏,并将二进制移入qq从尾到初级+二进制+qq适中.maxVisible(默认){ base: 2, md: 3, lg: 4 },初等包含,取景口断点)是上界和先漆计划. 栏从不包入两行;主行从不倒塌(取而代之的是其标签包入). - 破坏性 项从不向内渲染:它们最后在 qq 中,在分隔符后,在
text-destructive,并确认(ConfirmDialog destructive) 之前run。通过confirm: false如果主机已经确认; 通过{ title, description, confirmLabel, cancelLabel }来定制. - 过多 从
md(768px, (英语),MOBILE_BREAKPOINT上并作下面的底板(overflowAs='auto' | 'menu' | 'sheet') (中文(简体) ). 以下md,带有icon仅转换图标( 有标签) 按钮使用44pxcomfortable尺寸. run可能返回一个承诺:按钮显示自旋器和其他动作锁定,直到它解决为止。 错误发生到onActionError或被重新驱逐.disabledReason禁用动作并解释原因(桌面上的工具提示,菜单/表格中的文本).- 栏中填充其父( :
w-full内置大小的封装: 给它可能使用的房间.
PageHeader 以自己的宽度表示(@container:在448px下,它堆放领导~标题+徽章~动作;更宽,标题左(最大为60%,收缩)和动作右. titleKind='identifier' 保持单行/SKU(truncate,在 title(三); text (默认)包装。 标题大小为流体 (Y)clamp(1.25rem, 1rem + 2vw, 1.5rem)) (中文(简体) ). overflowActions 还在工作,但是 ActionBar 优先选择.
PageShell 是页面容器:单行沟 px-4 sm:px-6 lg:px-8, (中文(简体) ), min-w-0底部安全区, @container/page, (中文(简体) ), width='narrow' | 'default' | 'wide' | 'full'。 。 。 . BackLink 是一个44px «‹ Atrás",它使一个 <a href>页:1 <button> (无) href)或您的路由器链接(asChild) (中文(简体) ).
i18n 密钥( 均为西班牙默认) : action_bar.more, (中文(简体) ), action_bar.label, (中文(简体) ), action_bar.sheet_description, (中文(简体) ), action_bar.confirm_title (单位:千美元){{label}}, (中文(简体) ), action_bar.confirm_description, (中文(简体) ), action_bar.cancel, (中文(简体) ), back_link.label, (中文(简体) ), page_header.more。 。 。 .
反应分解、分解和分解@asteby/metacore-ui/modal(中文(简体) )
import { ResponsiveDialog } from '@asteby/metacore-ui/modal'
<ResponsiveDialog open={open} onOpenChange={setOpen} title='Despacho SO-00004' icon={<Warehouse />}
header={<ProcessStepper … />} // fixed, does not scroll
footer={{
primary: { label: 'Confirmar picking', run: confirmPicking }, // one CTA per step
secondary: [{ label: 'Imprimir surtido', icon: <Printer />, run: print }],
destructive: [{ label: 'Liberar apartado', run: release, confirm: { title: '¿Liberar el apartado?' } }],
extra: footerExtra, // host actions, e.g. ModalProps.footerExtra
}}
size='md' // sm | md | lg | xl | full (desktop)
mobile='sheet'> // sheet (default) | fullscreen | dialog
{body}
</ResponsiveDialog>
- 从768px(
MOBILE_BREAKPOINT(中文(简体) ): 居中对话框,max-h-[90dvh]页脚[destructive] ··· [start] [extra] [secondary] [PRIMARY]。 。 。 . - 以下:带有拖动手柄的底工作表(当
dismissable, (中文(简体) ),max-h-[92dvh],滚动的身体,和粘贴的脚env(safe-area-inset-bottom)高于屏幕键盘(visualViewport) (中文(简体) ). 堆叠:初等全宽,然后是初等+++(其他二等生,extra和破坏力最后用红色. - 脚下没有"Cerrar"按钮:44px X, Esc, Swipe并后关上.
dismissable={false}挡住他们. - 破坏行动得到证实
ConfirmDialog destructive(单位:千美元)confirm: false或自定义对象.run可能回到一个承诺: 旋转的动作,其他人锁定. - 标题包,他们永远不会被截断。 焦点转到打开的对话框, 打开时被困, 关闭时返回触发器 .
footerContent使自定义的页脚节点在同一粘贴页脚(legacy)中.
Modal 财务报告和审定财务报表 FormModal 现在已经建立在 ResponsiveDialog 同样的道具. Modal 添加 footerActions (分数)和 mobile。 。 。 . FormModal 将提交按钮作为主按钮( 电话上的全宽) 并接受 footerExtra。 。 。 .
i18n 密钥( 西班牙语默认值 ): responsive_dialog.close, (中文(简体) ), responsive_dialog.more, (中文(简体) ), responsive_dialog.confirm_title (单位:千美元){{label}}, (中文(简体) ), responsive_dialog.confirm_generic, (中文(简体) ), responsive_dialog.confirm_description, (中文(简体) ), responsive_dialog.cancel。 。 。 .
链接预览
(原始内容存档于2018-03-27). WhatsApp/Slack-style牌作新闻,帖子和证据. 构成部分 从不获取外部站点数字 :
后端提取元数据(og:title, (中文(简体) ), og:image,网站名,favicon...) 应用程序传入.
通过您自己的代理服务器运行图像 resolveImageUrl。 。 。 .
import { LinkPreviewCard, MediaGrid, SourceBadge, FaviconAvatar } from '@asteby/metacore-ui/shared'
const proxy = (u: string) => `/api/media/proxy?url=${encodeURIComponent(u)}`
<MediaGrid aria-label="Evidencias" minItemWidth={300}>
{items.map(n => (
<LinkPreviewCard
key={n.id}
variant="rich" // compact | row | rich | hero
data={{ url: n.url, title: n.title, description: n.summary, imageUrl: n.ogImage,
siteName: n.siteName, faviconUrl: n.favicon, kind: 'article', publishedAt: n.publishedAt }}
resolveImageUrl={proxy}
meta="Colima · Seguridad"
badges={<Badge variant="outline">+3 medios</Badge>}
onSelect={() => openDetail(n.id)} // optional: card becomes a button, external link stays secondary
/>
))}
</MediaGrid>
<SourceBadge domain="medio.mx" siteName="El Medio" faviconUrl={fav} suffix="· hace 2 h" />
<FaviconAvatar domain="medio.mx" size="md" />
- 固定纵横比(16:9)
rich编号 :hero平方缩略图row编号 :compact- 无布局变化; 骨架 + 加载时模糊; favicon + 域 + 当没有图像或图像失败时初始倒置. - 全卡可点击(接通链接/按钮),可显示焦点;徽章、脚印和二级
外部联系仍可突出重点。 外部链接使用
target="_blank" rel="noopener noreferrer nofollow"。 。 。 . loading做一个有相同足迹的骨架.formatRelativeTime(date, { now, locale })财务报告和审定财务报表domainFromUrl(url)导出。 标签跟着locale(单位:千美元)es默认,en) (中文(简体) ).
i18n (英语)
生成用户阵列的组件( Q)DataTablePagination, (中文(简体) ), DataTableViewOptions, (中文(简体) ), DataTableColumnHeader, (中文(简体) ), CommandMenu(a) 使用情况 react-i18next是因为 useTranslation() 钩并期望这些密钥:
datatable.view
datatable.columns
datatable.asc
datatable.desc
datatable.hide
datatable.page_x_of_y (interpolation: current, total)
datatable.rows_per_page
datatable.go_first_page / go_previous_page / go_next_page / go_last_page / go_page
common.search_command
common.no_results
common.theme / theme_light / theme_dark / theme_system
消费者应在他们的i18n资源中注册这些密钥. 包裹确实如此 没有 捆绑翻译.
构建
pnpm --filter @asteby/metacore-ui build
许可证
阿帕奇 - 2.0
触动( T)@asteby/metacore-ui/touch(中文(简体) )
(原始内容存档于2018-10-21) (英语). Primitivos sin marca para kioskos y pantallas de cliente. 埃尔塔马尼奥销售公司 --touch-min-target (60 px por 叛逃) y --touch-font-scale,克平塔语 @asteby/metacore-theme/touch; cada 成分受体 minTarget (原始内容存档于2018-09-26). para sobrescribirlo.
import { VirtualKeyboard, TouchButton, TouchGrid, useIdleReset, useWakeLock } from '@asteby/metacore-ui/touch'
const [email, setEmail] = useState('')
<VirtualKeyboard layout='email' value={email} onValueChange={setEmail} onEnter={next} />
const { warning, secondsLeft, reset } = useIdleReset(60, 10, () => navigate('/attract'))
useWakeLock()
VirtualKeyboard数字 :layouttext | numeric | email, (中文(简体) ),decimal(numérico),轮班off → una vez → bloqueo, (中文(简体) ),labels第i18n段,(a),onKey(原始内容存档于2013-10-12). para el flujo crudo de teclas.useIdleReset: cualquier指针/tecla/touch/rueda reicia;warning女演员warnSeconds。 。 。 .useWakeLock: 重新获得al-volver la spemaña的可见; sin soporte es no-op.