-
Notifications
You must be signed in to change notification settings - Fork 72
[LG-5504] feat(input-box): add InputSegment
#3293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[LG-5504] feat(input-box): add InputSegment
#3293
Conversation
…associated types and tests
…egment component references
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think i should break these out into smaller files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Not necessary, but wouldn't hurt
|
Size Change: +1.5 kB (+0.08%) Total Size: 1.79 MB
ℹ️ View Unchanged
|
| step?: number; | ||
|
|
||
| /** | ||
| * Whether the segment should wrap at min/max boundaries |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to update this: should only be at the max boundary
…se object parameter format for improved clarity and consistency
…ity by destructuring context values
…utBoxTypes and remove deprecated InputSegment types
| import { InputBoxProvider } from '../InputBoxContext/InputBoxContext'; | ||
| import { InputBoxProviderProps } from '../InputBoxContext/InputBoxContext.types'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| import { InputBoxProvider } from '../InputBoxContext/InputBoxContext'; | |
| import { InputBoxProviderProps } from '../InputBoxContext/InputBoxContext.types'; | |
| import { InputBoxProvider, type InputBoxProviderProps } from '../InputBoxContext/InputBoxContext'; |
| import { InputSegment } from '../InputSegment/InputSegment'; | ||
| import { InputSegmentProps } from '../InputSegment/InputSegment.types'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| import { InputSegment } from '../InputSegment/InputSegment'; | |
| import { InputSegmentProps } from '../InputSegment/InputSegment.types'; | |
| import { InputSegment, type InputSegmentProps } from '../InputSegment/InputSegment'; |
| /** | ||
| * Which segment this input represents | ||
| * | ||
| * @example |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this include time segment examples?
| export interface InputSegmentProps<Segment extends string> | ||
| extends Omit< | ||
| React.ComponentPropsWithRef<'input'>, | ||
| 'size' | 'step' | 'value' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we omit 'size' and 'value'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These values are read from the context, not from the prop
| * | ||
| * @default false | ||
| */ | ||
| shouldSkipValidation?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth refactoring out this double negative at this point? i.e. shouldValidate w/ default of true vs shouldSkipValidation w/ default of false? shouldValidate nicely maintains parallel structure with the shouldWrap boolean prop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to have a parallel structure. I'll update!
| min, | ||
| max, | ||
| step, | ||
| shouldWrap: shouldWrap, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| shouldWrap: shouldWrap, | |
| shouldWrap, |
| onBlur?.(e); | ||
| onBlurProp?.(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks a little strange to me. I like that onBlurProp has the explicit *Prop suffix. Anything we can add to onBlur to make it clear that is from whatever is specified by the onBlur in InputBox?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe onBlurContextProp?
| } | ||
| `; | ||
|
|
||
| export const segmentThemeStyles: Record<Theme, string> = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opportunity to refactor to tokens and rm palette dep
|
|
||
| import { InputSegment, InputSegmentChangeEventHandler } from '.'; | ||
|
|
||
| describe('packages/input-segment', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
worth adding a jest-axe test block?
…reen-ui into LG-5504/input-box-segment
…ared types for better organization
…maxSegmentValue for consistency
… violations when tooltip is closed
| } as InputBoxProviderProps<SegmentObjMock>; | ||
|
|
||
| const utils = render( | ||
| <InputBoxProvider {...mergedProviderProps}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the InputSegment tests need to depend on the InputBoxProvider?
I'd rather test the segment in isolation if possible
| const { input } = renderSegment({ | ||
| providerProps: { | ||
| segments: { day: '26', month: '', year: '' }, | ||
| onChange: onChangeHandler, | ||
| }, | ||
| }); | ||
|
|
||
| userEvent.type(input, '4'); | ||
| expect(onChangeHandler).toHaveBeenCalledWith( | ||
| expect.objectContaining({ value: '4' }), | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not really clear here in the tests why typing 4 into a segment that has 26 would just render 4 instead of 264. There's logic baked in somewhere that isn't entirely clear based on this test (I'm assuming there's a default min/max value?)
| charsPerSegment: charsPerSegmentMock['day'], | ||
| allowZero: defaultMinMock['day'] === 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Imo we can remove the charsPerSegment mock, and just hard code values for the tests
| charsPerSegment: charsPerSegmentMock['day'], | |
| allowZero: defaultMinMock['day'] === 0, | |
| charsPerSegment: 2, | |
| allowZero: true, |
| const { | ||
| onChange: onChangeContextProp, | ||
| onBlur: onBlurContextProp, | ||
| charsPerSegment: charsPerSegmentContext, | ||
| segmentEnum, | ||
| segmentRefs, | ||
| segments, | ||
| labelledBy, | ||
| size, | ||
| disabled, | ||
| } = useInputBoxContext<Segment>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like it might be simpler if these were just props to the segment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Not necessary, but wouldn't hurt
| decorator: (StoryFn, context) => ( | ||
| <LeafyGreenProvider darkMode={context?.args.darkMode}> | ||
| <InputBoxProvider | ||
| charsPerSegment={charsPerSegmentMock} | ||
| segmentEnum={SegmentObjMock} | ||
| onChange={() => {}} | ||
| onBlur={() => {}} | ||
| segmentRefs={segmentRefsMock} | ||
| segments={context?.args.segments} | ||
| size={context?.args.size} | ||
| disabled={false} | ||
| > | ||
| <StoryFn | ||
| placeholder={ | ||
| defaultPlaceholderMock[context?.args.segment as SegmentObjMock] | ||
| } | ||
| /> | ||
| </InputBoxProvider> | ||
| </LeafyGreenProvider> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, having half the props come from the InputBoxProvider and the other as real props is probably overly complex for this component
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chatted in person, and I'm going to remove the context and pass the props directly to the Segment component in InputBox
…nce type definitions for better clarity
…d onBlur event handlers with detailed documentation
…nd include additional props for improved functionality
…amline input box functionality
…neric and updating related components for improved clarity
…and remove unused segmentRefs and segments properties for improved clarity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was inherited from the first context PR that I closed. The tests were updated to wrap the props in an object and a new test was added to test the new allowZero prop
…/leafygreen-ui into LG-5504/input-box-segment
| const isIncomingValueNumber = !isNaN(Number(incomingValue)); | ||
| // macOS adds a period when pressing SPACE twice inside a text input. | ||
| const doesIncomingValueContainPeriod = /\./.test(incomingValue); | ||
| const shouldSkipValidation = !shouldValidate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think !shouldValidate is readable as-is. Feels more confusing to re-assign to this shouldSkipValidation variable
| * 'day' | ||
| * 'month' | ||
| * 'year' | ||
| * 'hours' | ||
| * 'minutes' | ||
| * 'seconds' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
date uses singular while time uses plural. can we make these consistent?
| /** | ||
| * Minimum value for the segment | ||
| * | ||
| * @example | ||
| * 1 | ||
| * 1 | ||
| * 1970 | ||
| * 0 | ||
| * 0 | ||
| * 0 | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: doesn't seem all that helpful to list numbers here in this format. maybe makes more sense to restrict to unique values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will remove these becuase I don't think they are that helpful
| /** | ||
| * Maximum value for the segment | ||
| * | ||
| * @example | ||
| * 31 | ||
| * 12 | ||
| * 2038 | ||
| * 23 | ||
| * 59 | ||
| * 59 | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: similar to above, these feel like arbitrary values when presented without the broader context
| /** | ||
| * The number of characters per segment | ||
| * | ||
| * @example | ||
| * 2 | ||
| * 2 | ||
| * 4 | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: similar to above, these feel like arbitrary values when presented without the broader context
| "access": "public" | ||
| }, | ||
| "dependencies": { | ||
| "@leafygreen-ui/a11y": "workspace:^", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be fine to drop the palette dependency altogether at this point
| }; | ||
| export default meta; | ||
|
|
||
| export const LiveExample: StoryFn<typeof InputSegment> = ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably can disable this snapshot since you have a generated story
…nt types for consistency
TheSonOfThomp
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some nits, but nothing blocking
| onChange: () => {}, | ||
| onBlur: () => {}, | ||
| value: '', | ||
| charsPerSegment: charsPerSegmentMock['day'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we probably don't need the charsPerSegmentMock and defaultMinMock, and could just pass the values directly
| /** | ||
| * The number of characters per segment | ||
| */ | ||
| charsPerSegment: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
charsPerSegment is a bit of a redundant name in the abstract context. Just a simple charsCount or something would be sufficient here
| minSegmentValue: number; | ||
|
|
||
| /** | ||
| * Maximum value for the segment | ||
| * | ||
| * @example | ||
| * 31 | ||
| * 12 | ||
| * 2038 | ||
| * 23 | ||
| * 59 | ||
| * 59 | ||
| */ | ||
| maxSegmentValue: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine for now, but we should note that it may be desirable to let this support alphanumeric chars in the future (and so min/max values don't make sense)
| * 'day' | ||
| * 'month' | ||
| * 'year' | ||
| * 'hour' | ||
| * 'minute' | ||
| * 'second' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
per stephen's other comment, we can rm this
| * '1' | ||
| * '2' | ||
| * '2025' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
| * | ||
| * These types are shared between the InputBox and the segmentComponent. | ||
| */ | ||
| export interface SharedInputBoxTypes<Segment extends string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this still needed here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I plan on using these types in InputBox as well
…ency across InputSegment components
|
Coverage after merging LG-5504/input-box-segment into shaneeza/time-picker-integration will be
Coverage Report
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4059f91
into
shaneeza/time-picker-integration
✍️ Proposed changes
This PR is the first PR in a series of three PRs that adds the new
InputBoxpackage and integrates it into the existingDatePickerpackage:InputBox#3285InputBoxcomponent #3286This PR adds the generic
InputSegmentcomponent to the new @leafygreen-ui/input-box package, which provides reusable input segment functionality for date and time components. The component extracts common logic and UI elements previously embedded in the date-picker package, making it available for use across DatePicker, TimeInput, and other similar components.🎟 Jira ticket: LG-5504
✅ Checklist
For new components
🧪 How to test changes
InputSegmentcomponent renders correctly in their respective stories