Skip to content

feat: implement HstDate input#822

Open
Kapcash wants to merge 4 commits intohistoire-dev:mainfrom
Kapcash:feature/hst-date-input
Open

feat: implement HstDate input#822
Kapcash wants to merge 4 commits intohistoire-dev:mainfrom
Kapcash:feature/hst-date-input

Conversation

@Kapcash
Copy link
Copy Markdown
Contributor

@Kapcash Kapcash commented Dec 26, 2025

Description

Use case

In some cases, we need to pass Date object instance to component props. But we lack support for native Histoire controllers for selecting dates.

I personally need this on my company's Histoire environment, and I had to tweak a HstText component to validate only date texts, convert it to date instance, and make sure it doesn't break anything.

Since HstText enforces the input type to be text (the v-bind is overridden), we can't use it with type="date". And I thought we probably shouldn't, as it would make the component too versatile. It would not handle edge cases, validation and so on.

Solution

So I implemented this new controller component HstDate to select a Date. It's a native input date / datetime picker, which emits the Date instance object, and also the textual value hold by the <input> element.

My first thought was to support both Date and string models, both synced together. But it brings a whole lot of issues, especially if we use both models at the same time (which one takes precedence?). So I decided to focus on the Date model instead, which is I think the main use case we would use this controller component.

Additional context

Since it's my first contribution, I'm not sure if this component respects the repo best practices and code style.
I also need feedback over the component naming and its story organization.

Should I add some examples in the examples package?


What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

  • If it's a new feature, provide a convincing reason to add it. Ideally, you should open a suggestion issue first and have it approved before working on it.
  • Read the Contributing Guidelines.
  • Read the Pull Request Guidelines and follow the Commit Convention.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Ideally, include relevant tests that fail without this PR but pass with it.

It will emit an event to get the textual input value, but the main model is a Date object.
@codesandbox
Copy link
Copy Markdown

codesandbox bot commented Dec 26, 2025

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@bolt-new-by-stackblitz
Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@netlify
Copy link
Copy Markdown

netlify bot commented Dec 26, 2025

Deploy Preview for histoire-site ready!

Name Link
🔨 Latest commit bef3840
🔍 Latest deploy log https://app.netlify.com/projects/histoire-site/deploys/6950eb6b0f831d0008ba5e1d
😎 Deploy Preview https://deploy-preview-822--histoire-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify bot commented Dec 26, 2025

Deploy Preview for histoire-controls ready!

Name Link
🔨 Latest commit bef3840
🔍 Latest deploy log https://app.netlify.com/projects/histoire-controls/deploys/6950eb6b440e5c0008fd7618
😎 Deploy Preview https://deploy-preview-822--histoire-controls.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify bot commented Dec 26, 2025

Deploy Preview for histoire-examples-vue3 ready!

Name Link
🔨 Latest commit bef3840
🔍 Latest deploy log https://app.netlify.com/projects/histoire-examples-vue3/deploys/6950eb6b7ce3810008321d96
😎 Deploy Preview https://deploy-preview-822--histoire-examples-vue3.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @Kapcash, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new HstDate control component to the Histoire library, providing a much-needed solution for handling Date object instances within component props. Previously, developers had to resort to workarounds with HstText for date inputs, which was not ideal due to limitations in input type enforcement and proper date validation. The new HstDate component offers a native date/datetime picker experience, emitting both a Date object and its string value, and supports toggling between date-only and datetime-local input types. This enhancement streamlines the process of integrating date-related controls into Histoire stories.

Highlights

  • New HstDate Component: Introduces a dedicated control component for selecting dates and datetimes, addressing the lack of native Histoire controllers for Date objects.
  • Native Input Integration: Utilizes native HTML input elements with type="date" or type="datetime-local" for a familiar user experience.
  • Date Object Model: Primarily focuses on emitting and receiving Date object instances via v-model, simplifying integration with component props that expect Date types.
  • Flexible Output: Emits both a Date object (update:modelValue) and its string representation (update:dateString) on input changes.
  • Datetime Support: Includes a datetime prop to easily switch between date-only and date-time input modes.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@netlify
Copy link
Copy Markdown

netlify bot commented Dec 26, 2025

Deploy Preview for histoire-examples-svelte3 ready!

Name Link
🔨 Latest commit bef3840
🔍 Latest deploy log https://app.netlify.com/projects/histoire-examples-svelte3/deploys/6950eb6bd01ccb00084de8db
😎 Deploy Preview https://deploy-preview-822--histoire-examples-svelte3.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new HstDate component for selecting dates and datetimes. This is a great addition and the implementation is solid, including comprehensive tests and a story file. My review focuses on a few key areas to improve robustness and clarity:

  • I've identified a reactivity issue in HstDate.vue where the component doesn't update when its modelValue prop changes, and I've suggested a fix using a watch effect.
  • I've also suggested adding a unit test to cover this reactivity scenario to prevent future regressions.
  • Finally, I've provided feedback on the story file to improve the clarity of the controls for demonstration purposes.
    Overall, this is a well-executed feature. Great work on your first contribution!

</script>

<script lang="ts" setup>
import { computed, ref } from 'vue'
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.

high

To make the component reactive to prop changes, you'll need to import watch from vue.

import { computed, ref, watch } from 'vue'

Comment on lines +22 to +28
let initialValue = ''
if (props.modelValue instanceof Date) {
initialValue = props.datetime
? props.modelValue.toISOString().slice(0, 16)
: props.modelValue.toISOString().slice(0, 10)
}
const inputValue = ref(initialValue)
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.

high

The component's internal inputValue is initialized from props.modelValue only once during setup. This means if the modelValue or datetime props are updated by the parent component after the initial render, the change will not be reflected in the input field, leading to a UI state that is out of sync with the component's props.

To fix this, you should use a watch effect to react to changes in these props and update inputValue accordingly. This ensures the component remains synchronized with its props throughout its lifecycle.

const inputValue = ref('')

watch([() => props.modelValue, () => props.datetime], ([newDate, datetime]) => {
  let value = ''
  if (newDate instanceof Date) {
    value = datetime
      ? newDate.toISOString().slice(0, 16)
      : newDate.toISOString().slice(0, 10)
  }

  if (value !== inputValue.value) {
    inputValue.value = value
  }
}, { immediate: true })

const input = wrapper.find('input')
expect(input.element.value).toBe('')
})
})
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.

medium

The test suite is quite comprehensive, which is great! However, it's missing a test case for reactivity. The component should update its displayed value when the modelValue prop is changed externally after the initial mount. Adding a test for this scenario would have caught a reactivity bug in the component and will help prevent future regressions.

You can add a test like this inside the 'modelValue initialization' describe block:

it('updates input value when modelValue prop changes', async () => {
  const wrapper = mount(HstDate, {
    props: {
      modelValue: new Date('2024-12-25'),
    },
  })

  const input = wrapper.find('input')
  expect(input.element.value).toBe('2024-12-25')

  await wrapper.setProps({ modelValue: new Date('2025-01-01') })

  expect(input.element.value).toBe('2025-01-01')
})

Comment on lines +47 to +50
<HstText
v-model="state.dateText"
title="Text"
/>
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.

medium

In the story controls, you have an HstText input bound to state.dateText. This allows editing the string representation of the date, but it doesn't update the HstDate component's value (state.date). This can be confusing as it seems like a two-way binding, but it only works one way (from HstDate to dateText).

To avoid this confusion, you could either:

  1. Make the HstText input readonly to just display the emitted string value.
  2. Implement a watch in the story's setup to parse state.dateText and update state.date, effectively creating a two-way sync for demonstration purposes.

Given the component's design focuses on the Date model, making the text display read-only might be the clearer option.

@Kapcash Kapcash changed the title Implement HstDate input feat: implement HstDate input Dec 26, 2025
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Dec 27, 2025

Open in StackBlitz

histoire

npm i https://pkg.pr.new/histoire-dev/histoire@822

@histoire/app

npm i https://pkg.pr.new/histoire-dev/histoire/@histoire/app@822

@histoire/controls

npm i https://pkg.pr.new/histoire-dev/histoire/@histoire/controls@822

@histoire/plugin-nuxt

npm i https://pkg.pr.new/histoire-dev/histoire/@histoire/plugin-nuxt@822

@histoire/plugin-percy

npm i https://pkg.pr.new/histoire-dev/histoire/@histoire/plugin-percy@822

@histoire/plugin-screenshot

npm i https://pkg.pr.new/histoire-dev/histoire/@histoire/plugin-screenshot@822

@histoire/plugin-svelte

npm i https://pkg.pr.new/histoire-dev/histoire/@histoire/plugin-svelte@822

@histoire/plugin-vue

npm i https://pkg.pr.new/histoire-dev/histoire/@histoire/plugin-vue@822

@histoire/shared

npm i https://pkg.pr.new/histoire-dev/histoire/@histoire/shared@822

@histoire/vendors

npm i https://pkg.pr.new/histoire-dev/histoire/@histoire/vendors@822

commit: bef3840

Copy link
Copy Markdown
Collaborator

@hugoattal hugoattal left a comment

Choose a reason for hiding this comment

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

A few ideas on the component implementation 🤔 (Thanks a lot for contributing ❤️)

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