Skip to content

delay for form elements; fix enumeration with divider elements - #1454

Open
A7700 wants to merge 3 commits into
devfrom
al/613_delay_form_elements
Open

A7700 wants to merge 3 commits into
devfrom
al/613_delay_form_elements

Conversation

@A7700

@A7700 A7700 commented Sep 3, 2026

Copy link
Copy Markdown

Does this PR close any open issues?

Closes #613

Give a longer description of what this PR addresses and why it's needed

Arbitrary Form elements can now be disabled for a specified amount of time in ms. This PR also fixes the enumeration issue with dividers.

@A7700
A7700 marked this pull request as draft September 3, 2026 13:56
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

A preview of 7afbae9 is uploaded and can be seen here:

https://revisit.dev/study/PR1454

Changes may take a few minutes to propagate.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1123ef3d18

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

{(isDelayedDisabled: boolean) => (
<div
style={{
pointerEvents: isDelayedDisabled ? 'none' : 'auto',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Make delayed content inert to keyboard input

When delay is set, this CSS suppresses only pointer targeting. A textOnly prompt can contain Markdown links and TextOnlyInput never consumes the disabled state, so Tab+Enter activates those links immediately; likewise, ResponseSwitcher returns false before consulting its disabled prop when the next component enables previousButton or the current component precedes a dynamic block, leaving normal inputs keyboard-editable. These paths let keyboard participants interact before the experimental delay expires and can invalidate timing results; make the wrapper inert or otherwise suppress focus while also preserving native disabled state.

Useful? React with 👍 / 👎.

Comment on lines +678 to +679
if ('restartEnumeration' in response) {
index = 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor false for restartEnumeration

When a textOnly response explicitly sets restartEnumeration: false, the in check still succeeds, resetting the index so the next numbered response incorrectly starts over at 1. This is a valid schema-backed configuration and differs from the previous truthiness check; test the property's boolean value rather than merely its presence.

Useful? React with 👍 / 👎.

@A7700
A7700 marked this pull request as ready for review September 8, 2026 14:38

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b4d9d663c1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread tests/demo-form-elements.spec.ts Outdated

// Slider
await page.locator('.mantine-Slider-track').click();
page.locator('[data-question-id="q-slider"] .mantine-Slider-track').click();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Await the scoped slider click

In the form-elements Playwright workflow, this click is started without awaiting its promise, so it can race the subsequent short- and long-text interactions; if the locator is still auto-waiting or the click fails, the rejection is detached from the intended test step and can make the suite flaky. Restore the await before continuing.

Useful? React with 👍 / 👎.

@JackWilb JackWilb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the focused delay and enumeration work. I found two existing behavior regressions that need to be addressed before merge: the added wrapper changes the response DOM structure used by shipped and external styles, and passing disabledAttempts into the inert wrapper overrides existing editability behavior in training and navigation flows. I also left smaller comments on the schema reference, delay validation, test coverage, and an unnecessary compatibility branch.

/>
>
{(isDelayedDisabled: boolean) => (
<div

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This extra div is now inserted around every response, including responses without a delay. The demo-style layout and existing study styles rely on .responseBlock > div > .response and on the response being the direct child of the outer wrapper, so these selectors stop matching. Please keep the existing DOM structure and apply the delay state to the existing .response element, or otherwise avoid adding a wrapper node.

config={config}
<DelayedResponseWrapper
delay={response.delay}
disabled={disabledAttempts}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing disabledAttempts into this wrapper makes the whole response inert, even in the existing flows where ResponseSwitcher intentionally keeps inputs editable before a dynamic block or when the next page has a Previous button. Please keep the timer-disabled state separate from the existing training-state behavior and only make the response inert while its delay timer is active.

"max": 100,
"min": 0,
"withDontKnow": true,
"delay": 5000

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This demo still points at the v2.4.3 schema, but that schema does not define delay and rejects this new property as an additional property. Please point the example at the current/dev schema so the example validates and editor tooling recognizes the field.

Comment thread src/parser/types.ts
/** Exclude response from randomization. If present, will override the `responseOrder` randomization setting in the components. Defaults to false. */
excludeFromRandomization?: boolean;
/** Delay in milliseconds before an element activates. Defaults to 0 meaning the element is always visible. */
delay?: number;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The schema currently accepts negative delays, but the implementation silently treats them as zero. A negative duration has no meaningful interpretation here. Please constrain delay to non-negative values in the type metadata and regenerate both schemas.

expect(wrapperWithStyles?.style.opacity).toBe('0.4');
});

test('does not apply delay styles to non-delayed responses and maintains sequential index', async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name says it checks sequential enumeration, but it never asserts either response index; it only checks styles on q1. The divider regression would still pass if numbering were wrong. Please capture the index or render the real labels and cover divider plus restartEnumeration false and true.

if (isInCurrentLocation) {
// Increment index for each response, unless it is a textOnly response
if (response.type !== 'textOnly') {
const isNonQuestion = response.type === 'textOnly' || response.type === 'divider' || ('divider' in response && Boolean(response.divider));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No response type or generated schema defines a divider property; the supported response-level field is withDivider, while an actual divider is identified by type: divider. This compatibility branch cannot be reached by a valid parsed config and adds unnecessary complexity. Please remove it.

@A7700

A7700 commented Sep 10, 2026

Copy link
Copy Markdown
Author

delay until stimulus is satisfied

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants