Initial import

This commit is contained in:
how2ice
2026-04-21 03:33:23 +09:00
commit 9e4b70f1f1
495 changed files with 94680 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
import { Card, Space, Tag, Typography } from 'antd';
import { forwardRef, useImperativeHandle, useRef } from 'react';
import { resolveWidgetFeatures } from './registry/widget-features';
import type { WidgetHandle, WidgetShellProps } from './types/widget';
const { Title } = Typography;
export const WidgetShell = forwardRef<WidgetHandle, WidgetShellProps>(function WidgetShell(
{ id, title, features = [], featureSlot, cardWrapper = true, children },
ref,
) {
const wrapperRef = useRef<HTMLDivElement>(null);
const resolvedFeatures = resolveWidgetFeatures(features);
const hasHeader = Boolean(title) || resolvedFeatures.length > 0 || Boolean(featureSlot);
useImperativeHandle(
ref,
() => ({
focus: () => {
wrapperRef.current?.focus();
},
scrollIntoView: (options) => {
wrapperRef.current?.scrollIntoView(options);
},
getId: () => id,
getFeatures: () => features,
}),
[features, id],
);
const content = (
<Space direction="vertical" size={16} className="widget-shell__stack">
{hasHeader ? (
<div className="widget-shell__header">
<Title level={4} className="widget-shell__title">
{title}
</Title>
<Space size={[8, 8]} wrap>
{resolvedFeatures.map((feature) => (
<Tag key={feature.key} color="blue">
{feature.label}
</Tag>
))}
{featureSlot}
</Space>
</div>
) : null}
<div className="widget-shell__content">{children}</div>
</Space>
);
if (!cardWrapper) {
return (
<div ref={wrapperRef} className="widget-shell widget-shell--plain" tabIndex={-1}>
{content}
</div>
);
}
return (
<Card ref={wrapperRef} className="widget-shell" tabIndex={-1}>
{content}
</Card>
);
});