Skip to content

chore(web_common): add more shared components#5243

Merged
mykalmax merged 6 commits intomainfrom
mykalmax/web_common-components
Aug 29, 2025
Merged

chore(web_common): add more shared components#5243
mykalmax merged 6 commits intomainfrom
mykalmax/web_common-components

Conversation

@mykalmax
Copy link
Contributor

No description provided.

Copy link
Contributor

@benfdking benfdking left a comment

Choose a reason for hiding this comment

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

I think this is fine, see my comments.

This does make me nervous, though. Looking at this, I would, for example, be nervous about including this in the vscode extension, it feels like pulling this in, signs me up to a lot of complexity and eventual tech debt that I have spent unnecessary hours fighting in the past.

Comment on lines +13 to +18
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
type?: ButtonType
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I have been looking at this Button and I worry that the structure of it makes it quite difficult to figure out how it works. I think we can do better to make these components easier to consume for each other.

Here is my thought process. When you use a component, the way you want to understand it is:

  1. What are the props?
  2. How does it function?

This is why in past lives I have always structured a component file like.

// Imports
import type { ButtonType } from './help'

// Prop of component, named Props so you know it's the props for that component
export interface Props {}

// Component
export const Component = () => {}

// Anything else that makes up the Component
const InternalComponent = () => {}

It's not a thing but figuring out how this Button component works requires quite a bit of jumping around files and while this is small, I think the complexity is pretty signficant to figure out for something so small.

Comment on lines +5 to +9
export const EnumButtonType = {
Button: 'button',
Submit: 'submit',
Reset: 'reset',
} as const
Copy link
Contributor

Choose a reason for hiding this comment

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

I am going to keep slowly pushing against enums 👅

https://bluepnume.medium.com/nine-terrible-ways-to-use-typescript-enums-and-one-good-way-f9c7ec68bf15 or even subtypes.

type ButtonType = "button" | "submit" | "reset"

verifying switches are exhaustive

and the usage with just to me is a nicer experience.

Comment on lines +14 to +28
variant: {
control: { type: 'select' },
options: Object.values(EnumButtonVariant),
},
size: {
control: { type: 'select' },
options: Object.values(EnumSize),
},
type: {
control: { type: 'select' },
options: ['button', 'submit', 'reset'],
},
disabled: {
control: 'boolean',
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have to write these? We should be able to set it up so an enum can be inferred?

Comment on lines +26 to +36
},
size: {
control: { type: 'select' },
options: Object.values(EnumSize),
},
disabled: {
control: 'boolean',
},
title: {
control: 'text',
},
Copy link
Contributor

Choose a reason for hiding this comment

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

This should all be inferred with a default?

Comment on lines +9 to +17
export interface ClipboardCopyProps extends Omit<ButtonProps, 'children'> {
text: string
delay?: number
children: (copied: boolean) => React.ReactNode
}

export const ClipboardCopy = React.forwardRef<
HTMLButtonElement,
ClipboardCopyProps
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Would a shared hook not be a more flexible option for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so we dont have a use case other than having button , (and i renamed component to be CopyButton) . once we have need to copy text from other interaction i can move to custom hook

Comment on lines +15 to +31
export function isString(value: unknown): value is string {
return typeof value === 'string'
}
export function notString(value: unknown): value is typeof value {
return !isString(value)
}
export function isEmptyString(value: unknown): value is EmptyString {
return isString(value) && value.length === 0
}
export function isNilOrEmptyString(
value: unknown,
): value is Maybe<EmptyString> {
return isNil(value) || isEmptyString(value)
}
export function nonEmptyString(value: unknown): value is string {
return isString(value) && value.length > 0
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This scares me a little because it implies:

  1. that we pass around quite a lot of known.
  2. It ties code together which doesn't need to be tied together, to me this is an unnecessary, it means that for the most simple things like testing a string is empty s.length === 0 we know have tied our code to this very far reaching utils part of the codebase.

An example of this is that if I want to move code around which previously had no tie to anything else because it's just checking whether a string is empty, I now need to think about this very big utils package which I really wouldn't want to do.

@mykalmax mykalmax merged commit 614a85d into main Aug 29, 2025
35 of 36 checks passed
@mykalmax mykalmax deleted the mykalmax/web_common-components branch August 29, 2025 15:43
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