Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .cursor/rules/exploration-design.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ Reference: `SegmentedToggleUIC` — Osaka | Amsterdam on `eip-7708` and `eip-803

Mobile stacks bands (steps → toggles → examples+Run grid). Desktop: steps left; toggles + action cluster right. Omit unused slots — do not leave empty flex wrappers.

On **touch**, `ActionButtonUIC` shows the Run tooltip as **inline** copy under the button. That caption must **not** set the action-row width (otherwise the examples select collapses to a chevron). Inline hints use `w-0 min-w-full`; the Run host is `flex min-w-0`, not `inline-flex`. The examples column is `minmax(10rem, 1fr)`.
On **touch**, `ActionButtonUIC` shows the Run tooltip as **inline** copy. That caption belongs on a **full-width row under** examples + Run — never in the Run column (a `w-0 min-w-full` caption beside a short “Run” label stacks one word per line). `.e-widget-chrome-run` uses `display: contents` below `md` so the hint can take `grid-area: hint`.

**Form-style explorations** (precompile E-Component, bytecode stepper, 7594) keep examples above the editor; they do **not** use `WidgetChromeUIC`. Bytecode Run/Step/Reset use **`decorative`** hints (no inline caption on touch). 7594 Run sits on its own row under a full-width examples select — same inline-width rule still applies.
**Form-style explorations** (precompile E-Component, bytecode stepper, 7594) keep examples above the editor; they do **not** use `WidgetChromeUIC`. Bytecode Run/Step/Reset use **`decorative`** hints (no inline caption on touch). 7594 Run sits on its own row under a full-width examples select.

**Layout / touch:** jsdom and default Cypress still report `(hover: hover) and (pointer: fine)`. After widget-chrome or Run-hint layout changes, run `cypress/e2e/widget-chrome-touch.cy.ts` (412px + `matchMedia` hover stub) before finishing.

## State chrome: selected must be obvious

Expand Down
35 changes: 35 additions & 0 deletions cypress/e2e/widget-chrome-touch.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { visitAsTouch } from '../support/touchVisit'

/**
* Widget chrome on a phone-sized viewport with hover disabled.
* Catches Run-hint / examples-select collisions that jsdom and default Cypress miss.
*/
describe('Widget chrome on touch', () => {
it('keeps the 8038 example title readable beside Run, hint below the row', () => {
visitAsTouch('/eip-8038-state-access-gas')
cy.get('#eip-8038-c', { timeout: 10000 }).should('exist')

cy.get('[data-testid="example-select"]')
.should('be.visible')
.and('contain.text', 'Update existing slot')
.then(($el) => {
expect($el[0].getBoundingClientRect().width).to.be.greaterThan(160)
})

cy.get('[data-testid="run-program"]').should('be.visible')

cy.get('#eip-8038-c .help-hint-inline')
.should('be.visible')
.and('contain.text', 'split touch')
.then(($hint) => {
const hint = $hint[0].getBoundingClientRect()
expect(hint.width, 'hint should span the chrome row, not a word column').to.be.greaterThan(
200,
)
expect(hint.height, 'hint should wrap as a caption, not a tall stack').to.be.lessThan(80)

const select = Cypress.$('[data-testid="example-select"]')[0].getBoundingClientRect()
expect(hint.top, 'hint sits under examples + Run').to.be.at.least(select.bottom - 12)
})
})
})
33 changes: 33 additions & 0 deletions cypress/support/touchVisit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/// <reference types="cypress" />

/**
* Pixel-ish width plus no-hover matchMedia. Default Cypress/Electron still
* reports (hover: hover) and (pointer: fine), so touch inline hints never mount.
*/
export function visitAsTouch(path: string) {
cy.viewport(412, 915)
cy.visit(path, {
onBeforeLoad(win) {
const native = win.matchMedia.bind(win)
win.matchMedia = ((query: string) => {
if (query === '(hover: hover) and (pointer: fine)') {
return {
matches: false,
media: query,
onchange: null,
addListener() {},
removeListener() {},
addEventListener() {},
removeEventListener() {},
dispatchEvent() {
return false
},
} as MediaQueryList
}
return native(query)
}) as typeof win.matchMedia
},
})
}

export {}
2 changes: 1 addition & 1 deletion src/eComponents/ui/HelpHintInlineUIC.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defineProps<{
<template>
<p
v-if="text.trim()"
class="help-hint-inline w-0 min-w-full font-mono text-xs leading-snug text-slate-500"
class="help-hint-inline font-mono text-xs leading-snug text-slate-500"
:class="hintClass"
>
{{ text }}
Expand Down
8 changes: 3 additions & 5 deletions src/eComponents/ui/__tests__/ActionButtonUIC.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function mockMatchMedia(canHover: boolean) {
}

describe('ActionButtonUIC', () => {
it('keeps the touch inline hint from setting the host intrinsic width', () => {
it('shows the tooltip as inline copy when hover is unavailable', () => {
mockMatchMedia(false)

const wrapper = mount(ActionButtonUIC, {
Expand All @@ -30,9 +30,7 @@ describe('ActionButtonUIC', () => {
})

expect(wrapper.get('.help-hint-host').classes()).toContain('min-w-0')
expect(wrapper.get('.help-hint-host').classes()).toContain('flex')
expect(wrapper.get('.help-hint-host').classes()).not.toContain('inline-flex')
expect(wrapper.get('.help-hint-inline').classes()).toContain('w-0')
expect(wrapper.get('.help-hint-inline').classes()).toContain('min-w-full')
expect(wrapper.get('[data-testid="run-program"]').text()).toBe('Run')
expect(wrapper.get('.help-hint-inline').text()).toContain('split touch')
})
})
2 changes: 0 additions & 2 deletions src/eComponents/ui/helpHint/__tests__/HelpHintUIC.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ describe('HelpHintUIC', () => {
})

expect(wrapper.find('.help-hint-inline').text()).toContain('Execute block')
expect(wrapper.find('.help-hint-inline').classes()).toContain('w-0')
expect(wrapper.find('.help-hint-inline').classes()).toContain('min-w-full')
expect(wrapper.find('.help-hint-popover-trigger').exists()).toBe(false)
})

Expand Down
29 changes: 28 additions & 1 deletion src/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,40 @@ body {
}

.e-widget-chrome-action {
@apply grid w-full grid-cols-[minmax(10rem,1fr)_auto] items-center gap-2 md:flex md:w-auto md:flex-row;
@apply grid w-full items-center gap-2 md:flex md:w-auto md:flex-row;
grid-template-columns: minmax(10rem, 1fr) auto;
grid-template-areas:
'examples run'
'hint hint';
}

.e-widget-chrome-action > :first-child {
grid-area: examples;
min-width: 0;
}

.e-widget-chrome-run {
@apply min-w-0 shrink-0 max-md:[&_.e-action-button]:min-h-9 max-md:[&_.e-action-button]:px-2 max-md:[&_.e-action-button]:py-1.5 max-md:[&_.e-action-button]:text-xs;
}

@media (max-width: 767px) {
.e-widget-chrome-run,
.e-widget-chrome-run .help-hint-host {
display: contents;
}

.e-widget-chrome-run .help-hint-trigger {
grid-area: run;
}

.e-widget-chrome-run .help-hint-inline {
grid-area: hint;
width: auto;
min-width: 0;
text-align: left;
}
}

/* --- Site shell (home, browse, card chrome) --- */
.fyp-shell-cta {
@apply inline-flex items-center justify-center px-3 py-2 min-h-11 rounded-md text-sm font-medium no-underline sm:min-h-0 sm:py-1.5 sm:px-2.5;
Expand Down