Skip to content

Commit

Permalink
Sort Array (#89)
Browse files Browse the repository at this point in the history
* [TASK] add array sort

* Update

* Update to expose on UI

---------

Co-authored-by: SorsOps <[email protected]>
  • Loading branch information
mck and SorsOps authored Sep 19, 2023
1 parent 4e19200 commit ed80a0b
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/loud-schools-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tokens-studio/graph-engine": minor
---

Add a sort array node
1 change: 1 addition & 0 deletions packages/documentation/pages/nodes/array-nodes/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"index-array": "Index array",
"reverse-array": "Reverse array",
"slice-array": "Slice array",
"sort-array": "Sort array",
"join-array": "Join array"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
ArrowDownIcon,
BlendingModeIcon,
ButtonIcon,
ColorWheelIcon,
Expand Down Expand Up @@ -259,6 +260,11 @@ export const items = {
icon: '[a,b]',
text: 'Slice Array',
},
{
type: NodeTypes.SORT,
icon: <ArrowDownIcon />,
text: 'Sort Array',
},
{
type: NodeTypes.JOIN,
icon: '[,]',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import {
Button,
Checkbox,
DropdownMenu,
Label,
Stack,
Text,
} from '@tokens-studio/ui';
import { Button, DropdownMenu, Label, Stack, Text } from '@tokens-studio/ui';
import {
ColorBlindnessTypes,
node,
Expand All @@ -17,7 +10,6 @@ import {
import { PreviewColor } from '../../preview/color.tsx';
import { WrapNode, useNode } from '../../wrapper/nodeV2.tsx';
import { sentenceCase } from 'sentence-case';
import PreviewNumber from '../../preview/number.tsx';
import React, { useCallback } from 'react';

const keys = Object.values(ColorBlindnessTypes);
Expand Down
107 changes: 107 additions & 0 deletions packages/graph-editor/src/components/flow/nodes/array/sort.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Handle, HandleContainer } from '../../handles.tsx';
import { PreviewAny } from '../../preview/any.tsx';
import { PreviewArray } from '../../preview/array.tsx';
import {
Button,
DropdownMenu,
Stack,
Text,
TextInput,
} from '@tokens-studio/ui';
import { WrapNode, useNode } from '../../wrapper/nodeV2.tsx';
import {
node,
OrderMap,
} from '@tokens-studio/graph-engine/nodes/array/sort.js';
import React, { useCallback } from 'react';
import { LabelNoWrap } from '#/components/label.tsx';
import { sentenceCase } from 'sentence-case';

const keys: string[] = Object.values(OrderMap);

const SortArrayNode = () => {
const { input, state, output, setState } = useNode();
const setValue = useCallback((ev) => {
const value = ev.target.value;
const key = ev.currentTarget.dataset.key;
setState((state) => ({
...state,
[key]: value,
}));
}, []);

const setDropdownValue = useCallback((ev) => {
const value = ev.currentTarget.dataset.value;
const key = ev.currentTarget.dataset.key;
setState((state) => ({
...state,
[key]: value,
}));
}, []);

return (
<Stack direction="row" gap={4}>
<HandleContainer type="target">
<Handle id="array">
<LabelNoWrap>Array</LabelNoWrap>
<PreviewAny value={input.array} />
</Handle>
<Handle id="sortBy">
<LabelNoWrap>Sort By</LabelNoWrap>

{input.sortBy !== undefined ? (
<PreviewAny value={input.sortBy} />
) : (
<TextInput
onChange={setValue}
value={state.sortBy}
data-key="sortBy"
/>
)}
</Handle>
<Stack direction="row" justify="between" align="center" gap={3}>
<LabelNoWrap>Order</LabelNoWrap>
<DropdownMenu>
<DropdownMenu.Trigger asChild>
<Button variant="secondary" asDropdown size="small">
{sentenceCase(state.order || '')}
</Button>
</DropdownMenu.Trigger>

<DropdownMenu.Portal>
<DropdownMenu.Content>
{keys.map((key, i) => {
if (!key) {
return <DropdownMenu.Separator key={i} />;
}

return (
<DropdownMenu.Item
key={key}
onClick={setDropdownValue}
data-key="order"
data-value={key}
>
{sentenceCase(key || '')}
</DropdownMenu.Item>
);
})}
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu>
</Stack>
</HandleContainer>
<HandleContainer type="source">
<Handle id="output">
<LabelNoWrap>Output</LabelNoWrap>
<PreviewArray value={output?.output} />
</Handle>
</HandleContainer>
</Stack>
);
};

export default WrapNode(SortArrayNode, {
...node,
title: 'Sort array',
});
2 changes: 2 additions & 0 deletions packages/graph-editor/src/components/flow/nodes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import RegexNode from './string/regexNode.tsx';
import RemapNode from './sets/remapNode.tsx';
import ResolveAliasesNode from './sets/resolveAliases.tsx';
import ReverseArrayNode from './array/reverse.tsx';
import SortArrayNode from './array/sort.tsx';
import ScaleNode from './color/scaleNode.tsx';
import SinNode from './math/sinNode.tsx';
import SliceNode from './array/slice.tsx';
Expand Down Expand Up @@ -112,6 +113,7 @@ export const { nodeTypes, stateInitializer } = processTypes([
SinNode,
CosNode,
ReverseArrayNode,
SortArrayNode,
TanNode,
jsonNode,
ClampNode,
Expand Down
4 changes: 3 additions & 1 deletion packages/graph-editor/src/components/label.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Label } from '@tokens-studio/ui';
import React from 'react';

export const LabelNoWrap = ({ children, ...rest }: typeof Label) => {
export interface ILabelNoWrap extends React.ComponentProps<typeof Label> {}

export const LabelNoWrap = ({ children, ...rest }: ILabelNoWrap) => {
return (
<Label {...rest}>
<span style={{ whiteSpace: 'nowrap' }}>{children}</span>
Expand Down
2 changes: 2 additions & 0 deletions packages/graph-engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"extract-colors": "^3.0.0",
"get-pixels": "^3.3.3",
"is-promise": "^4.0.0",
"lodash.orderby": "^4.6.0",
"postcss-value-parser": "^4.2.0",
"reactflow": "11.7.0",
"token-transformer": "^0.0.32"
Expand All @@ -62,6 +63,7 @@
"@types/chroma-js": "^2.4.0",
"@types/culori": "^2.0.0",
"@types/jest": "28.1.0",
"@types/lodash.orderby": "^4.6.7",
"@types/node": "^18.15.11",
"@types/react": "^18.2.6",
"husky": "^8.0.3",
Expand Down
2 changes: 2 additions & 0 deletions packages/graph-engine/src/nodes/array/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { node as indexArray } from "./indexArray.js";
import { node as join } from "./join.js";
import { node as reverse } from "./reverse.js";
import { node as slice } from "./slice.js";
import { node as sort } from "./sort.js";

export const nodes = [
arrify,
Expand All @@ -14,4 +15,5 @@ export const nodes = [
reverse,
slice,
join,
sort,
];
37 changes: 37 additions & 0 deletions packages/graph-engine/src/nodes/array/sort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Sort a given array without mutating the original
*
* @packageDocumentation
*/

import { NodeDefinition, NodeTypes } from "../../types.js";
import orderBy from "lodash.orderby";

const type = NodeTypes.SORT;

export enum OrderMap {
ASC = "asc",
DESC = "desc",
}

export type NamedInput = {
array: any[];
order?: OrderMap.ASC | OrderMap.DESC; // Optional parameter to specify the sort order
sortBy?: string; // Optional parameter to specify the property to sort by
};

export const defaults = {
order: OrderMap.ASC,
};

export const process = (input: NamedInput, state: NamedInput) => {
const { array, order, sortBy } = { ...state, ...input };

return orderBy(array, [sortBy], order);
};

export const node: NodeDefinition<NamedInput, NamedInput> = {
type,
defaults,
process,
};
1 change: 1 addition & 0 deletions packages/graph-engine/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export enum NodeTypes {
ARRIFY = "studio.tokens.array.arrify",
REVERSE = "studio.tokens.array.reverse",
SLICE = "studio.tokens.array.slice",
SORT = "studio.tokens.array.sort",
JOIN = "studio.tokens.array.join",
CONCAT = "studio.tokens.array.concat",
DOT_PROP = "studio.tokens.array.dotProp",
Expand Down
37 changes: 37 additions & 0 deletions packages/graph-engine/tests/suites/nodes/array/sort.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { executeNode } from "#/core.js";
import { node } from "#/nodes/array/sort.js";

describe("array/sort", () => {
it("sorts the values as expected", async () => {
const output = await executeNode({
input: {
array: [1, 2, 3, 4],
order: "desc",
},
node,
state: {},
nodeId: "",
});

expect(output).toStrictEqual({
output: [4, 3, 2, 1],
});
});

it("sorts the values as expected", async () => {
const output = await executeNode({
input: {
array: [{ a: 3 }, { a: 2 }, { a: 4 }],
order: "asc",
sortBy: "a",
},
node,
state: {},
nodeId: "",
});

expect(output).toStrictEqual({
output: [{ a: 2 }, { a: 3 }, { a: 4 }],
});
});
});
29 changes: 23 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4596,6 +4596,18 @@
resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.16.0.tgz#0e640df3647fe237212be863e1f5111eb9754f93"
integrity sha512-hz+S3nV6Mym5xPbT9fnO8dDhBFQguMYpY0Ipxv06JMi1ORgnEM4M1ymWDUhUNer3ElLmT583opRo4RzxKmh9jw==

"@types/lodash.orderby@^4.6.7":
version "4.6.7"
resolved "https://registry.yarnpkg.com/@types/lodash.orderby/-/lodash.orderby-4.6.7.tgz#3484098c0633f45aa0d3a57c5a8fc8a031cebb43"
integrity sha512-GaaUBTS4RTjL8gz1ZXkwAB/defpGMOWwCG9C4HL9g81i4wghIoVVESQCUa1xRsyUBqAb5JwLbSwvL0q36rK0sA==
dependencies:
"@types/lodash" "*"

"@types/lodash@*":
version "4.14.198"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.198.tgz#4d27465257011aedc741a809f1269941fa2c5d4c"
integrity sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg==

"@types/mdast@^3.0.0":
version "3.0.11"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.11.tgz#dc130f7e7d9306124286f6d6cee40cf4d14a3dc0"
Expand Down Expand Up @@ -5500,9 +5512,9 @@ caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001503:
integrity sha512-6XNEcpygZMCKaufIcgpQNZNf00GEqc7VQON+9Rd0K1bMYo8xhMZRAo5zpbnbMNizi4YNgIDAFrdykWsvY3H4Hw==

caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001520:
version "1.0.30001535"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001535.tgz#908a5b7ef11172f51f0b88f3d850aef1c6a3cf7b"
integrity sha512-48jLyUkiWFfhm/afF7cQPqPjaUmSraEhK4j+FCTJpgnGGEZHqyLe3hmWH7lIooZdSzXL0ReMvHz0vKDoTBsrwg==
version "1.0.30001538"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz#9dbc6b9af1ff06b5eb12350c2012b3af56744f3f"
integrity sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==

capital-case@^1.0.4:
version "1.0.4"
Expand Down Expand Up @@ -9909,6 +9921,11 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==

lodash.orderby@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.orderby/-/lodash.orderby-4.6.0.tgz#e697f04ce5d78522f54d9338b32b81a3393e4eb3"
integrity sha512-T0rZxKmghOOf5YPnn8EY5iLYeWCpZq8G41FfqoVHH5QDTAFaghJRmAdLiadEDq+ztgM2q5PjA+Z1fOwGrLgmtg==

lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
Expand Down Expand Up @@ -11674,9 +11691,9 @@ postcss@^8.3.7, postcss@^8.4.23:
source-map-js "^1.0.2"

postcss@^8.4.28:
version "8.4.29"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd"
integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==
version "8.4.30"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7"
integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
Expand Down

0 comments on commit ed80a0b

Please sign in to comment.