diff --git a/packages/json-render-ui/src/JsonRender.stories.ts b/packages/json-render-ui/src/JsonRender.stories.ts index 9f13fbd3..21c4517e 100644 --- a/packages/json-render-ui/src/JsonRender.stories.ts +++ b/packages/json-render-ui/src/JsonRender.stories.ts @@ -25,9 +25,11 @@ export const Gallery = story({ elements: { root: { type: 'Stack', props: { gap: 12 }, children: ['title', 'row', 'card', 'progress', 'table', 'tree'] }, title: { type: 'Text', props: { text: 'JSON-render gallery', variant: 'heading' }, children: [] }, - row: { type: 'Stack', props: { direction: 'row', gap: 8 }, children: ['b1', 'b2', 'badge'] }, + row: { type: 'Stack', props: { direction: 'row', gap: 8, wrap: true }, children: ['b1', 'b2', 'b3', 'b4', 'badge'] }, b1: { type: 'Button', props: { label: 'Primary', variant: 'primary' }, children: [] }, - b2: { type: 'Button', props: { label: 'Ghost', variant: 'ghost', icon: 'plus' }, children: [] }, + b2: { type: 'Button', props: { label: 'Secondary', variant: 'secondary' }, children: [] }, + b3: { type: 'Button', props: { label: 'Ghost', variant: 'ghost', icon: 'ph:plus' }, children: [] }, + b4: { type: 'Button', props: { label: 'Danger', variant: 'danger' }, children: [] }, badge: { type: 'Badge', props: { text: 'success', variant: 'success' }, children: [] }, card: { type: 'Card', props: { title: 'Details', collapsible: true }, children: ['kv'] }, kv: { type: 'KeyValueTable', props: { data: { name: 'devframe', version: '0.7.5' } }, children: [] }, @@ -49,6 +51,20 @@ export const Controls = story({ state: { name: '', enabled: true }, }) +export const ComponentSurfaces = story({ + root: 'root', + elements: { + root: { type: 'Stack', props: { gap: 12 }, children: ['openCard', 'collapsedCard', 'table'] }, + openCard: { type: 'Card', props: { title: 'Raised panel', collapsible: true }, children: ['input', 'code', 'inlineCode'] }, + input: { type: 'TextInput', props: { label: 'Sunken input', value: 'devframe' }, children: [] }, + code: { type: 'CodeBlock', props: { filename: 'panel.ts', language: 'ts', code: 'export const material = "sunken"' }, children: [] }, + inlineCode: { type: 'Text', props: { text: 'bg-panel-sunken', variant: 'code' }, children: [] }, + collapsedCard: { type: 'Card', props: { title: 'Collapsed panel', collapsible: true, defaultCollapsed: true }, children: ['collapsedText'] }, + collapsedText: { type: 'Text', props: { text: 'Hidden until expanded.' }, children: [] }, + table: { type: 'DataTable', props: { rows: [{ layer: 'raised', alpha: '13%' }, { layer: 'sunken', alpha: '5%' }] }, children: [] }, + }, +}) + export const Loading: StoryObj = story({ root: 'a', elements: { a: { type: 'Text', props: {}, children: [] } } }, { loading: true }) export const ConnectionError: StoryObj = story( diff --git a/packages/json-render-ui/src/components/Button.ts b/packages/json-render-ui/src/components/Button.ts index 3dc21fad..4c0dc28d 100644 --- a/packages/json-render-ui/src/components/Button.ts +++ b/packages/json-render-ui/src/components/Button.ts @@ -27,10 +27,14 @@ export const Button: JrComponent = ({ props, on }) => { ActionButton, { variant: buttonVariant[variant] ?? 'action', + size: 'sm', disabled: props.disabled, loading: props.loading, // `danger` isn't an ActionButton variant — override the primary tint. - class: variant === 'danger' ? 'bg-red! color-white! border-red! hover:bg-red/90!' : undefined, + class: [ + 'h-8 px-2.5!', + variant === 'danger' ? 'bg-red! color-white! border-red! hover:bg-red/90!' : undefined, + ], onClick: () => on('press').emit(), }, // Render the dynamic Icon in the slot (ActionButton's own `icon` prop is a diff --git a/packages/json-render-ui/src/components/Card.ts b/packages/json-render-ui/src/components/Card.ts index dbeeb8ee..1850d1d6 100644 --- a/packages/json-render-ui/src/components/Card.ts +++ b/packages/json-render-ui/src/components/Card.ts @@ -21,16 +21,16 @@ export const Card: JrComponent = ({ props, children, loading }) => { : (children as any) if (props.collapsible) { - return h(LayoutCard, { padding: false }, () => h('details', { open: !props.defaultCollapsed }, [ - h('summary', { class: `${headerClass} cursor-pointer select-none list-none` }, [ + return h(LayoutCard, { padding: false, class: 'bg-panel-raised!' }, () => h('details', { class: 'group', open: !props.defaultCollapsed }, [ + h('summary', { class: `${headerClass} cursor-pointer select-none list-none [&::-webkit-details-marker]:hidden` }, [ h('span', props.title ?? ''), - h('span', { class: 'color-faint text-xs' }, '▾'), + h('span', { 'class': 'i-ph:caret-right size-4 shrink-0 color-muted transition-transform group-open:rotate-90', 'aria-hidden': 'true' }), ]), h('div', { class: 'p4' }, [body]), ])) } - return h(LayoutCard, { padding: false }, () => [ + return h(LayoutCard, { padding: false, class: 'bg-panel-raised!' }, () => [ props.title ? h('div', { class: headerClass }, props.title) : null, h('div', { class: 'p4' }, [body]), ]) diff --git a/packages/json-render-ui/src/components/CodeBlock.ts b/packages/json-render-ui/src/components/CodeBlock.ts index d69fed11..de2edf04 100644 --- a/packages/json-render-ui/src/components/CodeBlock.ts +++ b/packages/json-render-ui/src/components/CodeBlock.ts @@ -10,13 +10,13 @@ interface CodeBlockProps { export const CodeBlock: JrComponent = ({ props }) => { const header = props.filename || props.language - ? h('div', { class: 'flex items-center justify-between px2 py1 border-b border-base bg-secondary text-xs color-faint' }, [ + ? h('div', { class: 'flex items-center justify-between px2 py1 border-b border-base bg-panel-raised text-xs color-faint' }, [ h('span', props.filename ?? ''), props.language ? h('span', { class: 'font-mono uppercase' }, props.language) : null, ]) : null const preStyle = props.height != null ? { maxHeight: `${props.height}px` } : undefined - return h('div', { 'class': 'rounded border border-base overflow-hidden bg-base', 'data-language': props.language }, [ + return h('div', { 'class': 'rounded border border-base overflow-hidden bg-panel-sunken', 'data-language': props.language }, [ header, h( 'pre', diff --git a/packages/json-render-ui/src/components/DataTable.ts b/packages/json-render-ui/src/components/DataTable.ts index 64cc7ac9..f9e89d14 100644 --- a/packages/json-render-ui/src/components/DataTable.ts +++ b/packages/json-render-ui/src/components/DataTable.ts @@ -29,15 +29,15 @@ export const DataTable: JrComponent = ({ props, on, bindings, lo const [, setSelected] = useBoundProp(undefined, bindings?.value) const wrapperStyle = props.height != null ? { maxHeight: `${props.height}px` } : undefined - return h('div', { class: 'rounded border border-base overflow-auto', style: wrapperStyle }, [ + return h('div', { class: 'rounded border border-base overflow-auto bg-panel-sunken', style: wrapperStyle }, [ h('table', { class: 'w-full text-sm border-collapse' }, [ - h('thead', { class: 'sticky top-0 bg-secondary' }, [ + h('thead', { class: 'sticky top-0 bg-panel-raised' }, [ h('tr', columns.map(col => h('th', { class: 'text-left px2 py1.5 color-muted font-medium border-b border-base' }, col.label ?? col.key))), ]), h('tbody', rows.map((row, index) => h('tr', { - class: 'border-b border-base hover:bg-secondary cursor-pointer', + class: 'border-b border-base hover:bg-panel-raised cursor-pointer', onClick: () => { // Deliver row + index into bound state, then fire the action. setSelected({ row, index }) diff --git a/packages/json-render-ui/src/components/Text.ts b/packages/json-render-ui/src/components/Text.ts index 56a8b5f9..c6b1eb8a 100644 --- a/packages/json-render-ui/src/components/Text.ts +++ b/packages/json-render-ui/src/components/Text.ts @@ -13,7 +13,7 @@ const textVariant: Record = { subheading: { tag: 'h3', class: 'text-base font-medium' }, body: { tag: 'p', class: 'text-sm' }, caption: { tag: 'span', class: 'text-xs color-faint' }, - code: { tag: 'code', class: 'text-sm font-mono bg-secondary rounded px1 py0.5' }, + code: { tag: 'code', class: 'text-sm font-mono bg-panel-sunken rounded px1 py0.5' }, } const colorClass: Record = { diff --git a/packages/json-render-ui/src/components/TextInput.ts b/packages/json-render-ui/src/components/TextInput.ts index cc284c6b..c9991348 100644 --- a/packages/json-render-ui/src/components/TextInput.ts +++ b/packages/json-render-ui/src/components/TextInput.ts @@ -24,6 +24,7 @@ export const TextInput: JrComponent = ({ props, on, bindings }) 'placeholder': props.placeholder, 'type': props.type ?? 'text', 'disabled': props.disabled || props.loading, + 'class': 'bg-panel-sunken!', }) if (props.label) { return h('label', { class: 'flex flex-col gap-1 text-sm color-muted' }, [ diff --git a/packages/json-render-ui/src/renderer.ts b/packages/json-render-ui/src/renderer.ts index 9dedc1f0..34f73058 100644 --- a/packages/json-render-ui/src/renderer.ts +++ b/packages/json-render-ui/src/renderer.ts @@ -103,7 +103,7 @@ export const JsonRenderView = defineComponent({ const staticNote = !props.interactive ? h('div', { - class: 'rounded border border-base bg-secondary color-faint text-xs px2 py1 mb2', + class: 'rounded border border-base bg-panel-raised color-faint text-xs px2 py1 mb2', }, 'Interactive actions are unavailable in static output.') : null diff --git a/packages/json-render-ui/src/spa/uno.config.ts b/packages/json-render-ui/src/spa/uno.config.ts index b85eaf72..90533db3 100644 --- a/packages/json-render-ui/src/spa/uno.config.ts +++ b/packages/json-render-ui/src/spa/uno.config.ts @@ -25,6 +25,8 @@ export default defineConfig({ // classes need safelisting. safelist: ['badge-color-green', 'badge-color-amber', 'badge-color-red', 'badge-color-blue'], shortcuts: { + 'bg-panel-raised': 'bg-hover', + 'bg-panel-sunken': 'bg-code', 'z-nav': 'z-[30]', 'z-dropdown': 'z-[40]', 'z-tooltip': 'z-[45]', diff --git a/packages/json-render-ui/uno.config.ts b/packages/json-render-ui/uno.config.ts index 758cf7d1..dbd3be4b 100644 --- a/packages/json-render-ui/uno.config.ts +++ b/packages/json-render-ui/uno.config.ts @@ -37,6 +37,8 @@ export default defineConfig({ // shadow-root surface/text tokens. safelist: [...shadowSurfaceSafelist, 'badge-color-green', 'badge-color-amber', 'badge-color-red', 'badge-color-blue'], shortcuts: { + 'bg-panel-raised': 'bg-hover', + 'bg-panel-sunken': 'bg-code', 'z-nav': 'z-[30]', 'z-dropdown': 'z-[40]', 'z-tooltip': 'z-[45]',