Giter VIP home page Giter VIP logo

ui's People

Contributors

coreymoore avatar hellolilyx avatar mcmanning avatar mkalvas avatar neilcoplin avatar semantic-release-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

ui's Issues

Uploader: RHF 7 integration issue

Uploader does not integrate well with RHF 7 - onBlur event doesn't trigger as expected.

Current workaround is to combine a controlled version with useState with RHF's setValue.

Something sort of like:

const [files, setFiles] = useState<UploadedFile[]>(...);
const { setValue } = useForm();

useEffect(() => {
  setValue(files);
}, [files]);

CheckboxField - inconsistent types

CheckboxField expects a string as the current value but the onChange handler resolves a boolean:

image

Make this consistent one way or the other.

Image: Safari renders large placeholder

Images that failed to load get a massive placeholder on Safari. Particularly apparent for all the diagram images that may or may not exist on every example.

Screen Shot 2023-01-10 at 9 27 48 AM

`FormErrors` errorMessages attribute type error in forms.stories.tsx

Type 'FieldErrors<{ textField: string; textAreaField: string; dateField: string; numberField: number; currencyField: number; checkboxField: boolean; yesNoField: boolean; switchField: boolean; selectField: string; comboBoxField: string; lookupField: string; checkboxSetField: string[]; radioSetField: string; }>' is not assignable to type '{ [field: string]: { message: string; }; } | undefined'.
Type 'FieldErrors<{ textField: string; textAreaField: string; dateField: string; numberField: number; currencyField: number; checkboxField: boolean; yesNoField: boolean; switchField: boolean; selectField: string; comboBoxField: string; lookupField: string; checkboxSetField: string[]; radioSetField: string; }>' is not assignable to type '{ [field: string]: { message: string; }; }'.
Property 'textField' is incompatible with index signature.
Type 'FieldError' is not assignable to type '{ message: string; }'.
Types of property 'message' are incompatible.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.ts(2322)
FormErrors.tsx(11, 3): The expected type comes from property 'errorMessages' which is declared here on type 'IntrinsicAttributes & StyleSystemProps & { errorMessages?: { [field: string]: { message: string; }; } | undefined; children?: ReactNode; } & RefAttributes<...>'

`ToggleField`-based components do not set input name or ID

A number of form components don't play well with FormData serialization, since I focused on typing and event handling for React Hook Forms.

Specifically, the YesNoField, RadioSetField, and CheckboxField aren't actually making their values available for FormData. I'm also noticing that programmatic changes to the underlying inputs (via my a11y tools) won't actually update component values. So there's a number of issues that need to be further investigated.

YesNoField - `value`/`onChange` need to be a boolean

Currently using string '1' and '0' but this isn't intended behaviour - it's just a workaround due to the inputs only allowing strings.

Really value, defaultValue, and onChange all need to work with boolean|undefined as a yes/no is essentially a 3 state boolean switch.

RFC: Modal API

UI 5 Modal API

Discussion of a new consistent modal API to cover:

  • a11y wiring
  • level of complexity for inexperienced developers
  • UX restrictions on what a developer can and can't do

Below are several options for APIs.

Modal is controlled by state

Each usage must define a state to link a modal to a trigger.

const [open, setOpen] = useState(false);

(
  // Your trigger
  <Button onPress={() => setOpen(true)}>Open modal</Button>

  // Your modal contents
  <Modal open={open} onClose={() => setOpen(false)}>
    <InformationDialog />
  </Modal>
)

Positives:

Negatives:

  • Developer is expected to be responsible for adding all aria tags and updates. A more realistic and compliant implementation will look like the below example.
    • Increases complexity of code reviews
    • Increases potential for mistakes by inexperienced developers
const [open, setOpen] = useState(false);

(
  // Your trigger
  <Button 
    onPress={() => setOpen(true)}
    aria-expanded={open}
    aria-controls={open ? 'my-unique-id' ? undefined}
  >Open modal</Button>

  // Your modal contents
  <Modal id="my-unique-id" open={open} onClose={() => setOpen(false)}>
    <InformationDialog aria-labeledby="my-unique-id" />
  </Modal>
)

Note: any implementation should still allow experienced developers to break out of common usage and have a controlled modal, as long as the requirements for compliance are very clear.

Modal is controlled by state + required ref

Alternative of the previous example where a ref is required to associate trigger to modal.

const [open, setOpen] = useState(false);
const ref = useRef<Button>(null);

(
  // Your trigger
  <Button 
    ref={ref}
    onPress={() => setOpen(true)}
  >Open modal</Button>

  // Your modal
  <Modal triggerRef={ref} open={open} onClose={() => setOpen(false)}>
    <InformationDialog />
  </Modal>
)

Positives:

  • Can auto-wire aria onto the trigger, developer does not need to know requirements in depth

Negatives:

  • Auto-wiring may work outside of the typical React render flow. I'm not sure if I can consistently ensure the button is still tagged appropriately if it re-renders while the modal is active.
  • Developer is now responsible for the ref and state.

Modal is a button

The modal trigger may only be a button of type ModalTriggerButton and the children of that button is the dialog content.

<ModalTriggerButton label="Open modal">
  {(close) => (
    <InformationDialog onClose={close} />
  )}
</ModalTriggerButton>

Positives:

Negatives:

  • Less flexibility, you can only use buttons
    • but that is a more consistent UX

Modal is a slot host

The modal is a host component for content slots.

<ModalHost>
  <Slot name="trigger">
    <Button>Open modal</Button>
  </Slot>
  <Slot name="dialog">
    <InformationDialog />
  </Slot>
</ModalHost>

// OR - the subcomponents-style API.
// Architecturally - they're the same:

<Modal>
  <Modal.Trigger>
    <Button>Open modal</Button>
  </Modal.Trigger>
  <Modal.Dialog name="dialog">
    <InformationDialog />
  </Modal.Dialog>
</Modal>

Positives:

Negatives:

  • Verbosity
  • Additional work on the host component to ensure colocation of children.
    • For example, if not carefully implemented the host trigger may end up several components deep within a host, or several sibling components could be between trigger and dialog.
    • Not a huge problem, we establish this as a design pattern already for components that only support with collection <Item> children, e.g. lists and checkbox sets.

Modal trigger is a render prop

Modal host acts as a functional linkage and the element to trigger the modal (button or whatever) is a render prop.

<ModalHost trigger={<Button>Open modal</Button>}>
  <InformationDialog />
</ModalHost>

Positives:

  • Flexible trigger element
  • Can automatically wire up required aria to the trigger element

Negatives:

  • ??

Modal is a render prop

Inverse of the prior example, the host wraps the trigger and the modal acts as the render prop:

<ModalHost modal={<InformationDialog />}>
  <Button>Open modal</Button>
</ModalHost>

Positives:

  • ??

Negatives:

  • Most content work will be done within the modal and not the trigger, so you'd either have an awkward inline component or you have to make a separate dialog component to write content in.
<ModalHost modal={
  <InformationDialog title="Terms of service">
    Long content would go here
  </InformationDialog>
}>
  <Button>Open modal</Button>
</ModalHost>

// vs

function TermsOfServiceDialog() {
  return (
    <InformationDialog title="Terms of service">
      Long content would go here
    </InformationDialog>
  )
}

<ModalHost modal={<TermsOfServiceDialog />}>
  <Button>Open modal</Button>
</ModalHost>

// vs the inverse example where trigger is the render prop:

<ModalHost trigger={<Button>Open modal</Button>}>
  <InformationDialog title="Terms of service">
    Long content would go here
  </InformationDialog>
</ModalHost>

RFC: HLSA for CSS variables

I love the way GraphiQL uses hlsa as the standard for their CSS variables - this lets them blend colors and control alpha a lot more easily, and possibly do some automatic-contrasting.

E.g.:

body:not(.graphql-light) .graphiql-container {
  --color-primary: 338, 100%, 67%;
  --color-secondary: 243, 100%, 77%;
}

.cm-s-graphiql {
  color: hsla(var(--color-neutral),var(--alpha-tertiary));
}

Think about whether or not we can benefit from a design choice like this earlier on. I think it'd honestly make it easier to generate secondary palette colors for sure.

Electron: useTheme's automatic `prefers-color-scheme` ignored

Wrapping an Electron app with <RUIProvider> does not load the user-preferred color scheme. Doing it manually does work, however:

export default function App() {
  const prefersColorScheme = window.matchMedia('(prefers-color-scheme: dark)');

  return (
    <RUIProvider theme={prefersColorScheme?.matches ? 'dark' : 'light'}>
      <ThemeProvider theme={{}}>
        <Router>
          <Routes>
            ...
          </Routes>
        </Router>
      </ThemeProvider>
    </RUIProvider>
  );
}

RHF is a dependency

RHF 7 should be a suggestion / peer for use with RHF-related hooks, not a hard dependency. This breaks integration with our legacy applications that use RHF 6 where I'd like to sideload RUI 5 for gradual upgrade alongside ORIS/ui 4.

Add error summary component

Standardize an accessible error summary component for form-heavy applications.

For example:

Screen Shot 2023-01-10 at 11 44 12 AM

Key features to touch on:

  • Aggregation of errors from either RHF 7 or custom sources
  • Links from errors to the fields in error
  • Guidance on error message formats

Add Admonition component

Add a component for admonitions that aren't alerts from an a11y point of view. Make alerts behave as actual alerts and direct developers to use admonitions for content that needs to be visually separated but not aggressive (e.g. hints and tips, additional help content, etc)

OhioStateNavbar - Support custom skip link targets

The navbar/heading component for OSU needs to be able to target a specific ID rather than a hardcoded value for the skip link.

Use case:

  • Integration with frameworks like Docusaurus that have their own explicit skip link target ID and cannot be changed to ours.

missing exports

4.x doesn't have a default export for the new hook useRESTFileUploader, and there's no default export for the new Upload component.

Add a typography provider component

Interesting idea I saw some other libraries that would make sense here as well:

A TypographyProvider (or TypographyScope, or similar) component could be used to apply type rules to standard DOM. So instead of having to use <Text> and <Heading> components for style, native <p> and <h1> will render using our typography rules within children of a provider.

Use cases:

  • Automatically styling user generated DOM within some scope. Think Richtext or Markdown editors
  • Reset + override of external styles (e.g. Docusaurus styles) to apply our own to some scope
  • Application of theme-aware styles to child DOM - giving dark mode support to applications that otherwise don't have it

Non-comprehensive list of native elements that would be styled with the provider:

h1-h5, p, em, strong, a, ul, ol, li, hr, table (and related)

Refactor out diff support

I'm stripping out the diff field support from the base UI framework and moving it into Ripple as a feature instead. While diffing is a pretty nice unique feature of RUI, I'm not seeing a case for anyone using it outside of what Ripple needs to do and it just overcomplicates this library. If there is such a case, I can backport what I do into here.

Ideally, diffing can be better implemented as a layer wrapping fields and showing two side by side to better handle cases like entire field types changing, or adding/removing options from radio sets - that's why it doesn't quite work well as a built-in feature of components.

Fix usage with incorrect sass dependency

sass is a dev dependency for v4 because we previously were specifying sass as a dependency for app templates themselves. This is causing some havoc with recent old app migrations due to node-sass -> sass upgrades needing to happen.

Throw sass as an actual dependency - because it is, we don't distribute compiled .css for v4 - along with anything else that needs to be more explicit.

ToggleButton - Incorrect prop types

Few issues with ToggleButton:

  1. The variant prop is currently required. Should be optional
  2. The onChange prop exposes both boolean and ChangeEvent args. This should only be boolean.
  3. value prop should be a boolean. Currently isSelected can be used, but I want to normalize this across stateful inputs.

image

Collection `<Item>` does not render outside UI 5 storybook

When trying to use any component that depends on the React Stately items as collection children (RadioSetField, SelectField, CheckboxSetField) nothing is rendered:

image

I've tested array mapping, items prop, and just setting explicit Item children as we have in the storybook docs:

<SelectField label="Select field">
  <Item key="dx11">DirectX 11</Item>
  <Item key="dx12">DirectX 12</Item>
  <Item key="ogles">OpenGL ES</Item>
  <Item key="ogl3">OpenGL 3.0</Item>
  <Item key="metal">Metal</Item>
  <Item key="vulkan">Vulkan</Item>
</SelectField>

Add progress component

Key features to touch on:

  • Announce intervals via an aria-live region at some fixed rate, e.g. every 5 seconds or at certain key percentages (10%, 50%, etc)
  • Support unbounded/indeterminate and determinate progress bar variants
  • Possibly a content ref so we can flag it as busy

React Aria already has a progress bar hook so drive it off of that.

I like Fluent UI's lightweight progress bar. Maybe something like that:

https://developer.microsoft.com/en-us/fluentui#/controls/web/progressindicator

Split icons off to their own package

Icons take up a huge chunk of RUI and won't be updated nearly as frequently. Let's split those off into @osuresearch/icons

See rollup report:

image

Conflicting CSS reset with existing products

Trying to integrate RUI 5 components with Docusaurus results in some interesting results due to our aggressive TailwindCSS reset.

How docs originally look (out of the box classic theme):

Screen Shot 2023-02-08 at 3 29 50 PM

With the RUI styles imported:

Screen Shot 2023-02-08 at 3 28 20 PM

I'm not against making a whole Docusaurus theme with RUI - but it'd be nice if we could also embed and have things play nicely together since this will be a future problem with other products.

I know some libraries (Mantine?) have a setting of some sort that allows you to specify whether or not resets are applied. Or we apply resets specifically to the RUIProvider scope and touch nothing outside of there.

GraphiQL uses the "just apply within the container" approach as well for resets. E.g.:

.graphiql-container * {
  box-sizing: border-box
}

LookupField - Submit item key not value

LookupField is submitting the value in the input field. This needs to instead associate the Item.key to the field on submit.

Use cases:

  • Feature parity with our v4 Lookup
  • Human-readable display values (person name) versus submitted data (employee ID)

For situations where someone wants the text value to equate the submitted value, they should use a ComboBoxField.

Iconography - add pencil icon

Want a pencil icon for editable fields that don't expose editor controls until clicked.

Use cases:

  • Compact UIs e.g. comment boxes
  • Optionally editable content e.g. titles on documents that have already been edited

Responsive styles do not update after SSR

Using Next.js for SSR causes the Grid component with responsive styles to not update accordingly after initial paint.

Anything that is resolving on / depending on layout responsiveness needs to update after mount from SSR.

OhioStateNavbar: compatibility issue with Next.js

Reloading an app on Next.js crashes on the navbar with:

`Error: Hydration failed because the initial UI does not match what was rendered on the server.

Warning: Expected server HTML to contain a matching text node for "BuckeyeLink" in <a>.

See more info here: https://nextjs.org/docs/messages/react-hydration-error

I'm using native a tags for the navbar instead of our links (like OhioStateFooter) so that'll most likely need to be migrated over so we have proper SSR support.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.