A common need in apps is to have a button to let the user do things. Both Termbox and (copied from the first) Data Bridge have a dedicated button component, more or less in the look of OOUI. Tainted references is very likely going to need a button as well.
One or Two components?
We should have two components, one ActionLink component for (overloaded) links and one ActionButton component for pure (submit) buttons.
1: Different no-JS SSR Fallback
- Provide a link to a form that does the thing that would otherwise be handled by the vue app. For this to work the "button" needs to be a HTML <a> tag with the url as the href attribute
- Submit an HTML form to the server. For this to work the button needs to be a HTML <button> tag with the type attribute to be submit.
2: Separation of responsibilities
The current EventEmittingButton combines two responsibilities into one component. For a shared component library it makes sense to split it into two, one for each responsibility:
- the button is actually a link and only styled as button (e.g. the progressive button in the Termbox anon edit warning) or overloads a link with a vuejs app, e.g. the Termbox edit pens on an Item page. Both of these cases require a link target.
- the button is only rendered dynamically within the vuejs app and never needs fallback, e.g. the save button in the data-bridge app. These buttons never need a link target and are always handled purely in js. I.e. This is just a pure button.
These two button components need to share their look and feel, but differ in some of their behavior. Thus, the API regarding the design should be completely shared, whereas the API controlling behavior can only be partly shared.
specific behavior API for ActionLink component
- href, required, if there is no sensible href for this button, use an ActionButton
- callback, optional. If it is not there, the component acts as a pure link. If it is provided, then the default action of opening the link is suppressed and the callback executed instead.
specific behavior API for ActionButton component
- type, optional, can be submit, reset or button, button is the default
- callback, optional if type is submit or reset, otherwise required.
shared behavior API between ActionLink and ActionButton components
- disabled, optional, default is false
shared presentational API between ActionLink and ActionButton components
- purpose, optional, can be normal, progressive or destructive, default is normal
- progressive, optional, binary, default is false, can only be true if purpose is not normal
- frameless, optional, binary, default is false, whether to show a border or not
- icon, optional, name of an icon that is added to the button. The available icons and their names should be the same as for OOUI
- icononly, optional, binary, default is false, doesn't show the button label, needs the icon option to be set
Hopefully, this approach will provide use with a more SOLID, future ready implementation that scales to upcoming projects without becoming a convoluted mess or breaking existing implementations every other week when another piece of functionality is added. Distinguishing between these two button types should ideally be obvious by design.
We might not want to implement all the functionality outlined above right from the start, especially as the component library is for now only intended for internal use. However, we should ensure that we implement this component in a way that is strictly forward compatible. That means that adding more API functionality doesn't represent a breaking change for the existing usage of the button.