Utility Components
Author:
Fluent Commerce
Changed on:
19 July 2024
Overview
The UX framework provides some "component primitives" that can be used to build more complex components on top. The advantage of this is that these utility components:
- provide a consistent look and feel
- update according to theme options
- enable mobile responsiveness
Utility Components
Author:
Fluent Commerce
Changed on:
19 July 2024
Overview
The UX framework provides some "component primitives" that can be used to build more complex components on top.
Key points
- Card
- Children
- Dynamic Value
- Loading
- Drawers, Modals and Toasts
- DatePicker
- Quantity Selector
- Quantity List
Card
Standard content card that will take the full width of it's container. Can be used in conjunction with Columns (below) to render multiple cards side-by-side.
Name | Type | Required | Default | Description |
title |
| ❌ | The Title text of the card. | |
highlight |
| ❌ | Show a coloured highlight above the card to denote status in cases like dashboard cards. | |
width | CardWidth (
| ❌ | full | Define the width of this card on a 12-column grid. Can use the named widths for readability or numbers directly. |
On mobile devices all widths will automatically change to 12 for the best responsive experience.
Children
The Children component is what allows complete hierarchies of components to be configured in the manifest document without every component needing to "understand" how to interpret a manifest. It's effectively the same as rendering {children} in a typical React component, with a few additional features:
- Component props are taken from the manifest rather than the rendering component needing to provide them
- GraphQL data is passed in based on the configured on the child in the manifest
`dataSource`
- Role restrictions configured in the manifest are enforced here. If are configured and the user doesn't have them, the component will not be shown.
`roles`
- Exceptions are caught and handled here, so that a misbehaving child component won't break the parent
Sample usage
Any Component that accepts children can then be configured in the manifest like:
1{
2 "component": "ACME.MyFancyCard",
3 "descendents": [
4 { "component": "ACME.MyCustomContent", "dataSource":"orders", "props":{...} },
5 { "component": "ACME.MyCustomContent", "dataSource":"fulfilments", "props":{...} }
6 ]
7}
Language: json
Name: Example
Description:
[Warning: empty required content area]Where the component looks like:
1const MyFancyCard: FC<FancyCardProps> = ({title}) => {
2 return (
3 <FancyCardWrapper>
4 <FancyCardTitle>{title}</FancyCardTitle>
5 <Children />
6 </FancyCardWrapper>
7 );
8}
Language: javascript
Name: Example
Description:
[Warning: empty required content area]The UX framework will take care of rendering the descendants, passing in the props defined in the manifest, and setting the dataSource context so that the first tab is using the "orders" result and the second is using "fulfilments".
Index-based children
Some components will only want to render some of the descendants, for example
`fc.card.tabs`
The
`index`
1return (<Children index={selectedTabIndex} />)
Language: javascript
Name: Example
Description:
[Warning: empty required content area]Overriding the descendant tree
By default, Children will render the
`descendants`
In some cases it's beneficial to override this behavior and directly provide a
`MystiqueComponentInstance`
Example use cases include:
- where a single component can have many "sets" of descendants, for example the Wizard component which can render a different set of descendants for each condition.
- allowing customization of components that aren't directly configured in the manifest, like custom form fields. In such cases the manifest fragment that defines the children of a form field might be configured in an account setting.
1const step = determineCurrentWizardStep(props.steps, props.data);
2return (<Children descendantsOverride={step.descendants} />);
Language: javascript
Name: Example
Description:
[Warning: empty required content area]Overriding the data context
The data context represents the page query response, narrowed by the
`dataSource`
This can also be overridden with the Children component, allowing developers to decorate the page query response with extra information, or event run a second query and replace the data context entirely.
The value provided will be passed into each descendant (and their descendants, and so on) as the
`data`
`dataSource`
1const newData = { ...data, calculatedRefundAmount: 215.50 };
2return (<Children dataOverride={newData} />);
Language: javascript
Name: Example
Description:
[Warning: empty required content area]Dynamic Value
DynamicValue is the component responsible for mapping a single query response value to html and forms the basis of many other components, like cards and tables.
It's built to be easily configurable via the manifest and understands data mapping, i18n.
Name | Type | Required | Description |
attribute |
| ✅ | Information about the type, value, and optional link reference for this value. |
context |
| ✅ | Context data needed to render this value - typically this would be the injected "data" prop of the calling component. |
defaultValue |
| ❌ | Optional default value for cases when the rendered value would be empty (e.g. (-)) |
Full documentation of the DynamicAttribute type can be found in the configuration guide.
Loading
The loading component shows a loading animation over the top of the calling component, good for cases where an API call has been made but the response is not yet available.
Sample usage
1if(query.fetching) return (<Loading />)
Language: javascript
Name: Example
Description:
[Warning: empty required content area]Drawers, Modals and Toasts
Utility functions are provided to allow custom components to produce:
- Drawers - the side-pane overlay used to show context information above a page (typically used for user actions)
- Modals - the centered overlay used for dialogs requiring user interaction (used for post-submit confirmation messages)
- Toasts - temporary messages that appear at the top of the page (used ot indicate success or failure of a backend action)
Each function takes a React element as the content of the overlay, making it easy to customize to any use-case.
1pushDrawer({
2 title: 'My Custom Drawer',
3 body: <span>drawer content, can include other React components</span>,
4 actions: [{
5 label:'drawer action',
6 action:() => { /* do something */ }
7 }]
8});
Language: javascript
Name: Example
Description:
[Warning: empty required content area]The Drawer and Modal modules also provide
`clearDrawers`
`clearModals`
Date Picker
`fc.filter.daterange`
Properties
The date picker component can take up the following properties:
Name | Type | Required | Default | Description |
|
| No |
| To disable selection of future dates |
|
| No | Object defining
|
Value
Name | Type | Required | Default | Description |
|
| No | Define default
| |
|
| No | Define default
|
Quantity Selector
`fc.util.quantitySelector`
`fc.util.quantitySelector`
`onChange`
The
`onChange`
`fc.util.quantitySelector`
`quantitySelector`
Properties
The QuantitySelector is also a field, therefore all properties of a form field are available for configuration. Refer to the form field in the SDK documentation for the full list of properties that can be accessed.
Name | Type | Required | Default | Description |
|
| True | A function that takes in a quantity selector event (and optional options) and does something with it. Components using the quantity selector are expected to define this function to use the user input as they see fit. | |
|
| False | An optional feature where you define whether the data passed into the quantity selector is valid or not. With this feature, you can instead display a string instead of the component when the data is not valid for a quantity selector. | |
|
| False | An optional label that's shown below the quantity selector. This is a separate label from the general label passed into the FormField label. | |
|
| False | User Input Validation settings for the quantity selector | |
|
| False | An optional data source that lets the router select a specific part of the data to use. This has the same functionality as MystiqueComponentInstance's dataSource. |
QuantitySelectorEvent
Name | Type | Required | Default | Description |
|
| Yes | The value of the quantity selector. This will always be a number when passed back from onChange. However, we allow value to be a string so an i18n string can be used to extract an initial value from the data. | |
|
| Yes | The id of the quantity selector. This is intended to be used to identify which quantity selector this event came from. |
ItemValidationProps
Name | Type | Required | Default | Description |
|
| Yes | The condition to check whether the item is valid or not. This should be a templated string that resolves to a boolean. For example, if you want to check that the amount of quantity is greater than zero before showing the quantity selector you can use {{gt orderItem.quantity 0}}. | |
|
| No | "Invalid Item" | An optional label that's shown below the quantity selector. This is a separate label from the general label passed into the FormField label. |
UnderLabelProps
Name | Type | Required | Default | Description |
|
| Yes |
| The value of the label. This can be an i18n key. If not found, it defaults to of
|
|
| No | Options for configuring the label |
UnderLabelOptions
Name | Type | Required | Default | Description |
|
| Yes | The color for the label. These functions takes in a theme and lets you choose either a colour from the theme or just a hex code string |
UnderLabelColors
Name | Type | Required | Default | Description |
| string | Yes | The colour to show when all quantity has been selected. This can be a hex code or one of the following options: primary, secondary, error, info, warning, success | |
| string | Yes | The colour to show when only some but not all or none of the quantity has been selected. This can be a hex code or one of the following options: primary, secondary, error, info, warning, success | |
| string | Yes | The colour to show when none of the quantity has been selected. This can be a hex code or one of the following options: primary, secondary, error, info, warning, success |
Quantity Selector Component Validation
Name | Type | Required | Default | Description |
|
| No | The minimum value of the quantity selector. If specified, the value of the quantity selector cannot go below this value. A templated string may be used instead of a number to extract a value from the data context. | |
|
| No | The maximum value of the quantity selector. If specified, the value of the quantity selector cannot go above this value. A templated string may be used instead of a number to extract a value from the data context. |
Quantity List
`fc.quantity.list`
The Quantity List is a skeleton for a field that intends to use a list with a selectable quantity for the end user. Developers can utilize
`fc.quantity.list`
`fc.quantity.list`
Properties
The Quantity List accepts the same properties as the list component. Additionally, it also accepts
`quantitySelectorProps`
Name | Type | Description |
|
| The properties for the quantity selector. |
Sample usage
1import gql from 'graphql-tag';
2import { Loading } from 'mystique/components/Loading';
3import { QuantityList, QuantitySelectorProps, TranslatableAttribute } from 'mystique/components/QuantityList'
4import { useQuery } from 'mystique/hooks/useQuery';
5import { FC } from 'react';
6
7const query = gql`
8 query getOrders {
9 orders(first: 100) {
10 edges {
11 node {
12 id
13 ref
14 type
15 status
16 totalPrice
17 }
18 }
19 }
20 }
21`
22
23export const SimpleQuantityList : FC = () => {
24 const [data] = useQuery(query);
25
26 const quantitySelectorProps : QuantitySelectorProps = {
27 onChange : (event) => { console.log(event); },
28 name: 'Name',
29 label: ''
30 }
31
32 const attributes : TranslatableAttribute[] = [
33 {
34 label: 'ID',
35 value: '{{node.id}}'
36 },
37 {
38 label: 'Ref',
39 value: '{{node.ref}}'
40 },
41 {
42 label: 'type',
43 value: '{{node.type}}'
44 },
45 {
46 label: 'Status',
47 value: '{{node.status}}'
48 },
49 {
50 label: 'totalPrice',
51 value: '{{node.totalPrice}}'
52 }
53 ]
54 if (data.data) {
55 return <QuantityList quantitySelectorProps={quantitySelectorProps} attributes={attributes} defaultPageSize={100} data={data.data.orders} />
56 } else {
57 return <Loading />
58 }
59}
Language: javascript
Name: Sample Code
Description:
[Warning: empty required content area]Quantity Selector
`fc.util.quantitySelector`
`fc.util.quantitySelector`
`onChange`
`DataProvider `
- SDK and manifest
`DataProvider `
key:
`fc.provider.graphql`
Description: The component is utilized as a wrapper to furnish data to its children. Specificly, it facilitates looping on complex queries to fill to a specific maximum item count. It is handy for memory search, sorting, and filtering operations.
Properties:
Key | Type | Required | Default | Description |
query | string | yes | - | Query to execute. Expects a connection type. |
path | string | yes | - | Dot notation path to the connection. e.g. fulfilments.items |
variables | Record<string, any> | no | - | Key value pairs of variables to be passed to the query. Can use handlebar notation: {{ , some contents, followed by a }} . |
max | number | no | 1000 | The max item count before terminating the looping query. This cannot go beyond 1000. |
descendants | MystiqueComponentInstance[] | no | - | Mystique components to render. These will have their data prop injected with the value from the looped query. |
children | React Children | no | - | React children will also have the data prop injected onto them if this pattern is used. |
Product Card utilization examples
The Product Card component is a content component allowing the placement of various child components inside the card to extend basic functionality.
1export const ActionButtonsExample = (): JSX.Element => {
2 return (
3 <ProductCard {...requiredProps}>
4 <div
5 style={{ paddingTop: 16, display: "flex", justifyContent: "flex-end" }}
6 >
7 <MdOutlineCancel
8 style={{ cursor: "pointer", marginRight: 32 }}
9 size={30}
10 color={"#999"}
11 />
12 <MdOutlineAddTask
13 style={{ cursor: "pointer" }}
14 size={30}
15 color={"#00A9E0"}
16 />
17 </div>
18 </ProductCard>
19 );
20};
Language: plain_text
Name: Product Card configuration with child components inside
Description:
Custom component development availability
Visualization example:
The
`onClose`
1export const CloseButtonExample = (): JSX.Element => {
2 return (
3 <ProductCard
4 onClose={() => {
5 /* close handler function */
6 }}
7 cardImage={{
8 imageUrl:
9 "https://c.static-nike.com/a/images/f_auto,b_rgb:f5f5f5,w_440/skwgyqrbfzhu6uyeh0gg/air-max-270-shoe-nnTrqDGR.jpg",
10 width: 100,
11 height: 100,
12 }}
13 indent
14 title="Nike Air 270"
15 attributes={[
16 { value: "AH8050-001", label: "ref" } as any,
17 { value: "5901234123457", label: "gtin" } as any,
18 ]}
19 />
20 );
21};
Language: plain_text
Name: onClose property example
Description:
Custom component development availability
Visualization example: