Giter Club home page Giter Club logo

ui-kit's People

Contributors

acossta avatar felipecadavid avatar github-actions[bot] avatar hasancolak avatar jonatassales avatar lifeofzero avatar markandrus avatar propeldata-ci avatar sashathor avatar ykdojo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ui-kit's Issues

Build issues with Parcel

The way we're using Parcel has allowed the following TypeScript issues to creep in without breaking the build. Ideally, Parcel (or whatever build tool we decide to use) fails the build when this happens, which will prevent us from merging to main.

  • We should fix these TypeScript issues.
  • We should make sure our build process fails on TypeScript issues.
@propeldata/react-counter:build: Building...
@propeldata/react-counter:build: 
@propeldata/react-counter:build: @parcel/transformer-typescript-types: 'response' is of type 'unknown'.
@propeldata/react-counter:build:   /Users/mark/src/propel/ui-kit/packages/react/counter/src/Counter.tsx:92:26
@propeldata/react-counter:build:     91 | 
@propeldata/react-counter:build:   > 92 |       const metricData = response.metricByName.counter
@propeldata/react-counter:build:   >    |                          ^^^^^^^^ 'response' is of type 'unknown'.
@propeldata/react-counter:build:     93 | 
@propeldata/react-counter:build:     94 |       setHasError(false)
@propeldata/react-counter:build: 
@propeldata/react-counter:build: 
@propeldata/react-counter:build: Bundling...
@propeldata/react-counter:build: Packaging & Optimizing...
@propeldata/react-counter:build: ✨ Built in 2.94s
@propeldata/react-counter:build: 
@propeldata/react-counter:build: dist/index.js           10.24 KB    65ms
@propeldata/react-counter:build: dist/index.module.js     9.59 KB    69ms
@propeldata/react-counter:build: dist/index.d.ts          1.57 KB    47ms
@propeldata/react-leaderboard:build: 
@propeldata/react-leaderboard:build: 
@propeldata/react-leaderboard:build: 
@propeldata/react-leaderboard:build: @parcel/transformer-typescript-types: 'response' is of type 'unknown'.
@propeldata/react-leaderboard:build:   /Users/mark/src/propel/ui-kit/packages/react/leaderboard/src/Leaderboard.tsx:229:26
@propeldata/react-leaderboard:build:     228 | 
@propeldata/react-leaderboard:build:   > 229 |       const metricData = response.metricByName.leaderboard
@propeldata/react-leaderboard:build:   >     |                          ^^^^^^^^ 'response' is of type 'unknown'.
@propeldata/react-leaderboard:build:     230 | 
@propeldata/react-leaderboard:build:     231 |       const headers = metricData.headers
@propeldata/react-leaderboard:build: Bundling...
@propeldata/react-leaderboard:build: Packaging & Optimizing...
@propeldata/react-leaderboard:build: ✨ Built in 3.22s
@propeldata/react-leaderboard:build: 
@propeldata/react-leaderboard:build: dist/index.js           34.77 KB    49ms
@propeldata/react-leaderboard:build: dist/index.module.js    33.17 KB    45ms
@propeldata/react-leaderboard:build: dist/index.d.ts          4.71 KB    19ms
@propeldata/react-time-series:build: 
@propeldata/react-time-series:build: 
@propeldata/react-time-series:build: @parcel/transformer-typescript-types: Type '_DeepPartialObject<{ [key: string]: { type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: 
@propeldata/react-time-series:build: number | undefined; grace?: string | ... 1 more ... | undefined; ticks: { ...; }; }; }> | _DeepPartialObject<...>' is not assignable to type 'Partial<{ [key: string]: ScaleOptionsByType<"linear" | 
@propeldata/react-time-series:build: "logarithmic">; }>'.
@propeldata/react-time-series:build:   Type '_DeepPartialObject<{ [key: string]: { type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | ...
@propeldata/react-time-series:build:  1 more ... | undefined; ticks: { ...; }; }; }>' is not assignable to type 'Partial<{ [key: string]: ScaleOptionsByType<"linear" | "logarithmic">; }>'.
@propeldata/react-time-series:build:     'string' index signatures are incompatible.
@propeldata/react-time-series:build:       Type '_DeepPartialObject<{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | number | 
@propeldata/react-time-series:build: undefined; ticks: { ...; }; }> | undefined' is not assignable to type 'ScaleOptionsByType<"linear" | "logarithmic"> | undefined'.
@propeldata/react-time-series:build:         Type '_DeepPartialObject<{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | number | 
@propeldata/react-time-series:build: undefined; ticks: { ...; }; }>' is not assignable to type 'ScaleOptionsByType<"linear" | "logarithmic"> | undefined'.
@propeldata/react-time-series:build:           Type '_DeepPartialObject<{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | number | 
@propeldata/react-time-series:build: undefined; ticks: { ...; }; }>' is not assignable to type '{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; 
@propeldata/react-time-series:build: grace?: string | number | undefined; ticks: { ...; }; }'.
@propeldata/react-time-series:build:             Type '_DeepPartialObject<{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | number | 
@propeldata/react-time-series:build: undefined; ticks: { ...; }; }>' is not assignable to type '{ type: "linear"; }'.
@propeldata/react-time-series:build:               Types of property 'type' are incompatible.
@propeldata/react-time-series:build:                 Type '"linear" | undefined' is not assignable to type '"linear"'.
@propeldata/react-time-series:build:                   Type 'undefined' is not assignable to type '"linear"'.
@propeldata/react-time-series:build: 
@propeldata/react-time-series:build:   /Users/mark/src/propel/ui-kit/packages/react/time-series/src/TimeSeries.tsx:189:11
@propeldata/react-time-series:build:     188 |           values,
@propeldata/react-time-series:build:   > 189 |           scales,
@propeldata/react-time-series:build:   >     |           ^^^^^^ Type '\_DeepPartialObject<{ [key: string]: { type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | ... 1 more ... | undefined; ticks: { ...; }; }; }> | \_DeepPartialObject<...>' is not assignable to type 'Partial<{ [key: string]: ScaleOptionsByType<"linear" | "logarithmic">; }>'.
@propeldata/react-time-series:build:     Type '\_DeepPartialObject<{ [key: string]: { type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | ... 1 more ... | undefined; ticks: { ...; }; }; }>' is not assignable to type 'Partial<{ [key: string]: ScaleOptionsByType<"linear" | "logarithmic">; }>'.
@propeldata/react-time-series:build:       'string' index signatures are incompatible.
@propeldata/react-time-series:build:         Type '\_DeepPartialObject<{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | number | undefined; ticks: { ...; }; }> | undefined' is not assignable to type 'ScaleOptionsByType<"linear" | "logarithmic"> | undefined'.
@propeldata/react-time-series:build:           Type '\_DeepPartialObject<{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | number | undefined; ticks: { ...; }; }>' is not assignable to type 'ScaleOptionsByType<"linear" | "logarithmic"> | undefined'.
@propeldata/react-time-series:build:             Type '\_DeepPartialObject<{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | number | undefined; ticks: { ...; }; }>' is not assignable to type '{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | number | undefined; ticks: { ...; }; }'.
@propeldata/react-time-series:build:               Type '\_DeepPartialObject<{ type: "linear"; } & CartesianScaleOptions & { beginAtZero: boolean; suggestedMin?: number | undefined; suggestedMax?: number | undefined; grace?: string | number | undefined; ticks: { ...; }; }>' is not assignable to type '{ type: "linear"; }'.
@propeldata/react-time-series:build:                 Types of property 'type' are incompatible.
@propeldata/react-time-series:build:                   Type '"linear" | undefined' is not assignable to type '"linear"'.
@propeldata/react-time-series:build:                     Type 'undefined' is not assignable to type '"linear"'.
@propeldata/react-time-series:build:     190 |           variant,
@propeldata/react-time-series:build:     191 |           customPlugins
@propeldata/react-time-series:build: 
@propeldata/react-time-series:build: @parcel/transformer-typescript-types: 'response' is of type 'unknown'.
@propeldata/react-time-series:build: 
@propeldata/react-time-series:build:   /Users/mark/src/propel/ui-kit/packages/react/time-series/src/TimeSeries.tsx:260:26
@propeldata/react-time-series:build:     259 | 
@propeldata/react-time-series:build:   > 260 |       const metricData = response.metricByName.timeSeries
@propeldata/react-time-series:build:   >     |                          ^^^^^^^^ 'response' is of type 'unknown'.
@propeldata/react-time-series:build:     261 | 
@propeldata/react-time-series:build:     262 |       const labels: string[] = [...metricData.labels]
@propeldata/react-time-series:build: 
@propeldata/react-time-series:build: Bundling...
@propeldata/react-time-series:build: Packaging & Optimizing...
@propeldata/react-time-series:build: ✨ Built in 3.67s
@propeldata/react-time-series:build: 
@propeldata/react-time-series:build: dist/index.js           34.02 KB    48ms
@propeldata/react-time-series:build: dist/index.module.js     32.9 KB    52ms
@propeldata/react-time-series:build: dist/index.d.ts          3.83 KB    27ms

[RFC] Pie chart support for Leaderboard

Summary

The UI Kit should provide a pie chart component.

What's the problem?

While developers can create pie charts using custom components and Query Hooks, there are still details they must work through:

  • What query or queries should be used to fetch the data?
  • How should the component be themed?

Pie charts are so common that we should offer a first-class implementation of them, so that developers don't have to set up custom components or make these decisions — they can just get to visualizing.

What are the requirements?

  • The pie chart will (at least initially) support a single dimension per segment.
  • The pie chart will allow visualizing N segments.
  • The pie chart will show an N+1-th segment with a configurable label for all other dimensions (for example, "Other").

Detailed design

How do we query the data?

The most important part of the design is "how do we query the data?" Propel's GraphQL API does not (yet) offer a pie chart API, but what would we expect from one? Probably it would look very similar to a Leaderboard query, but it would also support fetching a "total". By subtracting the N segments from the total, we can determine the N+1-th segment containing all other values.

For example, imagine we have a data set with

  • 100 values labeled "A".
  • 50 values labeled "B".
  • 50 values labeled "C", "D", or "E".

Then, the total is 200. If we run the queries below asking for two segments, we'd expect the following responses.

Note that we pass filters1 and filters2. filters2 must include all of filters1, but it must also exclude entries with dimension values matching the N segments. For example, if filters1 is empty, filters2 must be equivalent to

dimension != 'A' AND dimension != 'B'
GraphQL Queries JSON Response
query PieChart1(
  $metric: MetricInput!
  $timeRange: TimeRangeInput!
  $timeZone: String
  $dimension: String!
  $sort: Sort
  $segments: Int!
  $filters1: [FilterInput!]
) {
  leaderboard(input: {
    metric: $metric
    timeRange: $timeRange
    timeZone: $timeZone
    dimensions: [{
      columnName: $dimension
    }]
    sort: $sort
    rowLimit: $segments
    filters: $filters1
  }) {
    rows
  }
}
query PieChart2(
  $metric: MetricInput!
  $timeRange: TimeRangeInput!
  $timeZone: String
  $filters2: [FilterInput!]
) {
  counter(input: {
    metric: $metric
    timeRange: $timeRange
    timeZone: $timeZone
    filters: $filters2
  }) {
    value
  }
}
{
  "data": {
    "leaderboard": {
      "rows": [
        ["A", "100"],
        ["B", "50"]
      ]
    }
  }
}
{
  "data": {
    "counter": {
      "value": "200"
    }
  }
}

In the UI Kit, we could determine that the N+1-th segment should be proportional to 200 - 100 - 50 = 50 in the resulting pie chart.

Rejected query idea
GraphQL Query JSON Response
query PieChart(
  $metric: MetricInput!
  $timeRange: TimeRangeInput!
  $timeZone: String
  $dimension: String!
  $sort: Sort
  $segments: Int!
  $filters: [FilterInput!]
) {

  leaderboard(input: {
    metric: $metric
    timeRange: $timeRange
    timeZone: $timeZone
    dimensions: [{
      columnName: $dimension
    }]
    sort: $sort
    rowLimit: $segments
    filters: $filters
  }) {
    rows
  }

  counter(input: {
    metric: $metric
    timeRange: $timeRange
    timeZone: $timeZone
    filters: $filters
  }) {
    value
  }
}
{
  "data": {
    "leaderboard": {
      "rows": [
        ["A", "100"],
        ["B", "50"]
      ]
    },
    "counter": {
      "value": "200"
    }
  }
}

This seems to work for COUNT metrics. Does it work for SUM metrics? It seems like the "correct" way to handle SUM metrics is to actually issue a subsequent counter query that explicitly filters out the top N segments.

Theming and styling

Here is a screenshot from a recent Figma:

image

There should be props for

  • Switching between "pie" and "doughnut" styles (this is really about the diameter of the inner "hole", if any).
  • Whether to show a total in the middle of the chart, and whether to include a label.
  • Whether to show a total above the chart, and whether to include a label.
  • What style of table to show below the chart, if any.
  • Including/excluding the legend using existing Chart.js props.

Additionally, there should be callbacks for interactivity with the segments (for example, "onhover", etc.).

Drawbacks

  • The pie chart component would ideally use a dedicated pie chart API that Propel's GraphQL API offer. Because Propel's GraphQL API does not (yet) offer this, we instead simulate it in the frontend, which leads to more code. If Propel's GraphQL API gains a pie chart API, we can eventually delete the frontend code which simulates it.

Alternatives

Developers can continue to create pie charts using custom components and Query Hooks.

Adoption strategy

Pie charts will be a new component, and so they can be added in a minor version. They do not represent a breaking change.

Unresolved questions

  • Is the table below the pie chart just an embedded leaderboard?
  • Review the Figma. For example, what happens when you hover and/or select a segment?
  • Review the query. @markandrus thinks we may need to issue two queries, rather than one.
  • Should we allow including/excluding the "Other" dimension based on a prop? Or should we always include it?

Docs: Create a style guide

Problem

I noticed that there isn’t a style guide on how to maintain the Docs of your project. This makes it difficult for contributors who want to contribute to the docs understand what to do.

Possible Solution.

Create a style guide that has information on how to display code snippets and formatting headings, and the tone of voice you want for the docs. This would make it easier for contributors to see how they improve the Docs and increase productivity.

[RFC] Select component library

Problem statement

In order to implement upcoming features such as the Time Range Picker and the Filters we’ll require to use a Select component, we’ll need to decide whether implementing the Select component ourselves or using a third party library.

Requirements

The Select component should include the next set of features

  • It should be Accessibility rich
  • It should be usable by keyboard
  • It should be a lightweight library
  • It should be a well maintained library
  • It should be highly customizable
  • It should allow autocompletion
  • It should allow multi-select

Implementing component ourselves

Implementing the Select component by ourselves will require that we fulfill the requirements that would mostly be already fulfilled by a third party library, it provides the advantage that we would have fully control around the component and any related bug would be in our hands to fix.

This would imply implementing by ourselves at least

  • Customization
  • Accessibility
  • Autocompletion
  • Multi-select

Customization

Ideally we would expose our customers with an API to fully customize the Select component’s styles, using a third party library would make this process a lot easy since we can expose the library’s API to our customers similar to what we do with Chart.js, implementing this ourselves would require:

  • Defining a customization API for the component
  • Allow customizing every part of the component
    • Colors
    • Text and fonts
    • Focus indicators
    • Option selected state
  • Providing customers with a primitive version of the component so they can style from scratch
  • The component should respond to browser preferences
  • Upon customization the component will require to update ARIA attributes accordingly

Accessibility

The component will require providing with full accessibility support

  • The component should be readable by a screen reader
  • The component should be usable only with the keyboard
  • The component should be fully responsive and work on mobile devices
  • The component should include the correct ARIA attributes
  • The component should ensure customization does not affect accessibility

Autocompletion

The component will require support for autocompletion

  • The API should allow enabling/disabling autocompletion
  • Typing in the input should filter the available options

Multi-select

The component will require support for selecting multiple options

  • The API should allow enabling/disabling auto-select
  • Selection an option should include the option value in the input
  • The input view for multiple options should be customizable

Using a third-party library

Radix

Pros Cons
Radix is a popular library (13k stars on Github) Radix doesn’t support autocompletion, although they plan to implement a ComboBox which is similar to our use case
Radix provides a low-level customization by having a different component for each piece of the Select Radix primitives have not been maintained since 4 months ago, which makes more unlikely that we’ll get the ComboBox component shortly
Radix allows installing only its Select dependency which makes it more lightweight for our use case Even if we make our own autocomplete on top of Radix that would sacrifice part of the Accessibility
Radix contains other components that we could use for future use cases Radix’s learning curve is pronounced since it’s necessary to use all of the sub components together and style each of them

React-select

  • It should be Accessibility rich
  • It should be usable by keyboard ✅
  • It should be a lightweight library (723 kB)
  • It should be a well maintained library (⚠️ Last commit 2 months ago)
  • It should be highly customizable ✅
  • It should allow autocompletion ✅
  • It should allow multi-select ✅
Pros Cons
React-select is a popular library (26.9k stars on Github) React-select has 296 unresolved issues on GitHub
React-select provides built-in default autocompletion which is easy to disable React-select could be an overkill for our use case
React-select enables easy customization of each of the internal component’s CSS and enables to create a wrapper for each of the internal components React-select’s last commit was 2 months ago
React-select’s documentation is extensive React-select does not contain other components that we could use for future use cases

Material-UI

  • It should be Accessibility rich
  • It should be usable by keyboard ✅
  • It should be a lightweight library (10.3 MB) ❌
  • It should be a well maintained library (✅ Last commit less than a day ago)
  • It should be highly customizable ✅
  • It should allow autocompletion ✅
  • It should allow multi-select ✅

Note: Base-UI is a more modern and lightweight version of Material-UI that also allows better customization, it’s maintained by Material-UI and could be a better option to consider

Pros Cons
Material-UI is a popular library (90.3k stars on Github) It requires installing the entire library to use the Select component
Only 111 open issues related to Select on Github Material-UI is not a lightweight library
Material-UI provides a Base-UI library which provides a basic set of components that are more customizable and lightweight (2.94 MB) This library also doesn’t require to install emotion. Base-UI is currently in beta.
Material-UI contains other components that we could use for future use cases Material-UI requires installing emotion, which would add more weight to the bundle size

Comparison

Requirement Radix React-select MUI
Accessibility
Keyboard
Lightweight
Well maintained ⚠️ ⚠️
Customizable
Autocompletion ⚠️
Multi-select

Candidate stats

Lib GitHub starts Open issues Closed issues* Opened issues* Contributors
https://github.com/mantinedev/mantine 22.9k 46 48 13 475
https://github.com/shoelace-style/shoelace 10.8k 37 5 11 132
https://github.com/mui/material-ui 90.3k 1.5k 89 88 2887
https://github.com/radix-ui/primitives 13.1k 365 14 29 45

*- for the past month

Notes

  • January 2024: We decided to use Base-UI as it provides the best balance within our requirements, and the bundle size can be addressed with tree-shaking

Docs: Contributing File needs improvement

Problem

The Contributing section could use more detail. New contributors might need a more structured idea on how to how to do contribute to your project

Possible solution

I suggest creating a separate Contributing file with information on how to do a PR, raise an issue, and code reviews. It would give new contributors a clearer idea on how to work on your project & serve as refresher for people who have been contributing to your project for a while.

[RFC]: Syncing Design Tokens Between Figma and UI Kit

Summary

The Foundations in Figma include all the essential design tokens for our Design System, such as the color palette, spacing, shadows, typography, etc. We need to establish a reliable and efficient method to sync the Foundations with the UI Kit.

What's the problem?

The initial synchronization was completed manually, which proved to be unreliable, labor-intensive, and not very scalable. Fortunately, most of these tasks should be easy to automate.

What are the requirements?

  • Export Design Tokens from Figma.
  • Convert Design Tokens into UI Kit formats (CSS and TS).
  • Compare existing UI Kit tokens with Design Tokens from Figma. Flag any mismatches with an error.

Detailed design

The sync process involves two main steps:

  1. Exporting Design Tokens from Figma.
  2. Parsing the tokens into UI Kit's format.

The export step can be achieved by using a free plugin to export variables from Figma as JSON
We could implement the parsing step similarly to how we generated types. The script would parse the JSON, update the common design tokens SCSS, and refresh the type definitions.

Additionally, we could create a checker to scan all SCSS files in the codebase. This would detect any discrepancies between the token list from Figma and the current tokens in the codebase. For example, if --propel-border-color exists in the codebase but not in the JSON, it would throw an error.

Drawbacks

No response

Alternatives

The export step can also be achieved by using Figma's API, which requires a paid Enterprise subscription. For simplicity, I recommend starting with the JSON export and exploring a fully automated solution later.

Adoption strategy

No response

Unresolved questions

No response

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.