Skip to content

Commit

Permalink
Merge pull request #2 from klown/feat/create-palette-from-json
Browse files Browse the repository at this point in the history
Feat: Create palette from JSON file (resolves #1)
  • Loading branch information
cindyli committed Dec 20, 2023
2 parents 2b0628f + 352ce6c commit 2132549
Show file tree
Hide file tree
Showing 24 changed files with 2,256 additions and 15 deletions.
Empty file added .gitmodules
Empty file.
19 changes: 19 additions & 0 deletions docs/DeveloperDoc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Developer Documentation

## How to render a palette

`Palette.ts` constructs a palette based on a JSON file that contains a list
of the cells in the palette. An example is found in
[`src/keyboards/bmw_palette.json`](../src/keyboards/bmw_palette.json). The
`cells` object is the list of all of the cells. Each cell has a `type` key and
an `options` key. The `type` value indicates which Preact component should be
used to render this cell. The `options` contains information to be passed to the
component.

## How to add a new cell type

When a new `type` value is introduced, developers need to:

1. Create a new component to render the new cell type;
2. In `GlobalData.ts`, update `cellTypeRegistry` to add the entry that maps the
new type value to the actual component.
23 changes: 14 additions & 9 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>Adaptive Palette</title>
</head>
<body>
<div id="app"></div>
</body>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>Adaptive Palette</title>
</head>
<body>
<h2>Palette Based on JSON</h1>
<div id="bmwKeyCodes">
<script type="module">
import "./src/index.js";
</script>
</div>
</body>
</html>
6 changes: 5 additions & 1 deletion jest.config.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
setupFiles: ["./setupFetchForJest.ts"],
verbose: true,
preset: "ts-jest",
testEnvironment: "jsdom",
Expand All @@ -10,5 +11,8 @@ module.exports = {
},
testPathIgnorePatterns: ["/node_modules/", "<rootDir>/dist/"],
transformIgnorePatterns: ["<rootDir>/dist/"],
moduleFileExtensions: ["mjs", "js", "jsx", "ts", "tsx", "json", "node"]
moduleFileExtensions: ["mjs", "js", "jsx", "ts", "tsx", "json", "node"],
moduleNameMapper: {
"^.+\\.(css|less|scss)$": "babel-jest"
},
};
18 changes: 15 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
"test": "jest"
},
"dependencies": {
"bliss-svg-builder": "^0.1.0-alpha.4",
"htm": "^3.1.1",
"preact": "^10.13.1",
"sass": "^1.65.1"
"sass": "^1.65.1",
"whatwg-fetch": "^3.6.19"
},
"devDependencies": {
"@babel/preset-env": "^7.22.14",
Expand Down
24 changes: 24 additions & 0 deletions setupFetchForJest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright 2023 Inclusive Design Research Centre, OCAD University
* All rights reserved.
*
* Licensed under the New BSD license. You may not use this file except in
* compliance with this License.
*
* You may obtain a copy of the License at
* https://github.com/inclusive-design/adaptive-palette/blob/main/LICENSE
*/

// There is an issue requesting the additions adding the fetch API to jest-dom
// for testing with node. Node.js Core has had an implementation of the fetch
// API since v17.5. However, jest-dom removes it. This comment in the issue
// suggests using whatwg's version of fetch() instead:
// https://github.com/jsdom/jsdom/issues/1724#issuecomment-720727999

import { fetch } from "whatwg-fetch";

module.exports = {
globals: {
fetch: fetch
}
};
24 changes: 24 additions & 0 deletions src/ActionBmwCodeCell.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2023 Inclusive Design Research Centre, OCAD University
* All rights reserved.
*
* Licensed under the New BSD license. You may not use this file except in
* compliance with this License.
*
* You may obtain a copy of the License at
* https://github.com/inclusive-design/adaptive-palette/blob/main/LICENSE
*/

.actionBmwCodeCell {
border: 2px solid blue;
background-color: gray;
border-radius: 5px;
padding: 1rem;
font-size: 1rem;
text-align: center;

&:hover, &:focus {
background-color: lightblue;
color: #0000aa;
}
}
65 changes: 65 additions & 0 deletions src/ActionBmwCodeCell.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2023 Inclusive Design Research Centre, OCAD University
* All rights reserved.
*
* Licensed under the New BSD license. You may not use this file except in
* compliance with this License.
*
* You may obtain a copy of the License at
* https://github.com/inclusive-design/adaptive-palette/blob/main/LICENSE
*/

import { render, screen } from "@testing-library/preact";
import "@testing-library/jest-dom";
import { html } from "htm/preact";

import { initAdaptivePaletteGlobals } from "./GlobalData";
import { ActionBmwCodeCell } from "./ActionBmwCodeCell";

describe("ActionBmwCodeDell render tests", () => {

const TEST_CELL_ID = "uuid-of-some-kind";
const testCell = {
options: {
"label": "Bliss Language",
"rowStart": "3",
"rowSpan": "2",
"columnStart": "2",
"columnSpan": "1",
"bciAvId": [ 12335, "/", 8499 ] // VERB+EN
}
};

beforeAll(async () => {
await initAdaptivePaletteGlobals();
});

test("Single ActionBmwCodeCell rendering", async () => {

render(html`
<${ActionBmwCodeCell}
id="${TEST_CELL_ID}"
options=${testCell.options}
/>`
);

// Check the rendered cell
const button = await screen.findByRole("button", {name: testCell.options.label});

// Check that the ActionBmwCodeCell/button is rendered and has the correct
// attributes and text.
expect(button).toBeVisible();
expect(button).toBeValid();
expect(button.id).toBe(TEST_CELL_ID);
expect(button.getAttribute("class")).toBe("actionBmwCodeCell");
expect(button.textContent).toBe(testCell.options.label);

// Check the grid cell styles.
expect(button.style["grid-column"]).toBe("2 / span 1");
expect(button.style["grid-row"]).toBe("3 / span 2");

// Check disabled state (should be enabled)
expect(button.getAttribute("disabled")).toBe(null);
});

});
42 changes: 42 additions & 0 deletions src/ActionBmwCodeCell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2023 Inclusive Design Research Centre, OCAD University
* All rights reserved.
*
* Licensed under the New BSD license. You may not use this file except in
* compliance with this License.
*
* You may obtain a copy of the License at
* https://github.com/inclusive-design/adaptive-palette/blob/main/LICENSE
*/

import { html } from "htm/preact";
import { OptionsType } from "./index.d";
import { BlissSymbol } from "./BlissSymbol";
import "./ActionBmwCodeCell.scss";


type ActionBmwCodeCellPropsType = {
id: string,
options: OptionsType
};

export function ActionBmwCodeCell (props: ActionBmwCodeCellPropsType) {
const {
columnStart, columnSpan, rowStart, rowSpan, bciAvId, label
} = props.options;

const gridStyles = `
grid-column: ${columnStart} / span ${columnSpan};
grid-row: ${rowStart} / span ${rowSpan};
`;

return html`
<button id="${props.id}" class="actionBmwCodeCell" style="${gridStyles}" >
<${BlissSymbol}
bciAvId=${bciAvId}
label=${label}
isPresentation=true
/>
</button>
`;
}
117 changes: 117 additions & 0 deletions src/BlissSymbol.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright 2023 Inclusive Design Research Centre, OCAD University
* All rights reserved.
*
* Licensed under the New BSD license. You may not use this file except in
* compliance with this License.
*
* You may obtain a copy of the License at
* https://github.com/inclusive-design/adaptive-palette/blob/main/LICENSE
*/

import { render, screen } from "@testing-library/preact";
import "@testing-library/jest-dom";
import { html } from "htm/preact";

import { initAdaptivePaletteGlobals } from "./GlobalData";
import { BlissSymbol, GRAPHIC_ROLE } from "./BlissSymbol";

describe("BlissSymbol render tests", () => {
const singleBciAvId = {
bciAvId: 12335,
label: "VERB"
};

const arrayBciAvId = {
bciAvId: [12335, "/", 8499],
label: "VERB+S"
};

const MOCK_LABEL_ID = "mockLabelId";
const UNKNOWN_BCI_AV_ID = -1;

beforeAll(async () => {
await initAdaptivePaletteGlobals();
});

test(`BlissSymbol defined by a single BCI_AV_ID (${singleBciAvId.label})`, async () => {
render(html`
<${BlissSymbol}
bciAvId="${singleBciAvId.bciAvId}"
label="${singleBciAvId.label}"
isPresentation=true
/>`
);
const blissSymbolLabelDiv = await screen.findByText(singleBciAvId.label);
expect(blissSymbolLabelDiv).toBeVisible();
expect(blissSymbolLabelDiv).toBeValid();

// Expect an <svg ...> element as the only sibling
const parentChildren = blissSymbolLabelDiv.parentNode.childNodes;
expect(parentChildren.length).toBe(2);
expect(parentChildren[0].nodeName).toBe("svg");
});

test("BlissSymbol when the SVG is unknown", async () => {
render(html`
<${BlissSymbol}
bciAvId="${UNKNOWN_BCI_AV_ID}"
label="${arrayBciAvId.label}"
isPresentation=true
/>`
);
const blissSymbolLabelDiv = await screen.findByText(arrayBciAvId.label);
const svgElement = blissSymbolLabelDiv.parentNode.querySelector("svg");
const parentChildren = blissSymbolLabelDiv.parentNode.childNodes;
expect(parentChildren.length).toBe(1);
expect(svgElement).toBe(null);
});

test(`BlissSymbol defined by an of BCI_AV_IDs (${arrayBciAvId.label})`, async () => {
render(html`
<${BlissSymbol}
bciAvId="${arrayBciAvId.bciAvId}"
label="${arrayBciAvId.label}"
isPresentation=true
/>`
);
const blissSymbolLabelDiv = await screen.findByText(arrayBciAvId.label);
expect(blissSymbolLabelDiv).toBeVisible();
expect(blissSymbolLabelDiv).toBeValid();
const parentChildren = blissSymbolLabelDiv.parentNode.childNodes;
expect(parentChildren.length).toBe(2);
expect(parentChildren[0].nodeName).toBe("svg");
});

test("BlissSymbol aria: when svg has no role)", async () => {
render(html`
<${BlissSymbol}
bciAvId="${arrayBciAvId.bciAvId}"
label="${arrayBciAvId.label}"
isPresentation=true
/>`
);
const blissSymbolLabelDiv = await screen.findByText(arrayBciAvId.label);
const svgElement = blissSymbolLabelDiv.parentNode.querySelector("svg");
expect(svgElement.getAttribute("aria-hidden")).toBe("true");
expect(svgElement.getAttribute("role")).toBe(null);
expect(svgElement.getAttribute("aria-labelledby")).toBe(null);
});

test("BlissSymbol aria: when svg has a graphic role)", async () => {
render(html`
<${BlissSymbol}
bciAvId="${arrayBciAvId.bciAvId}"
label="${arrayBciAvId.label}"
isPresentation=false
labelledBy=${MOCK_LABEL_ID}
/>`
);
const blissSymbolLabelDiv = await screen.findByText(arrayBciAvId.label);
const svgElement = blissSymbolLabelDiv.parentNode.querySelector("svg");
expect(svgElement.getAttribute("role")).toBe(GRAPHIC_ROLE);
expect(svgElement.getAttribute("aria-labelledby")).toBe(MOCK_LABEL_ID);
expect(svgElement.getAttribute("aria-hidden")).toBe(null);
});
});

0 comments on commit 2132549

Please sign in to comment.