├── .babelrc ├── .eslintrc.cjs ├── .gitignore ├── .npmrc ├── .prettierrc ├── LICENSE.md ├── README.md ├── jest.config.ts ├── package-lock.json ├── package.json ├── package ├── .gitignore ├── Accordion.svelte ├── Accordion.svelte.d.ts ├── Accordion │ ├── AccordionButton.svelte │ ├── AccordionButton.svelte.d.ts │ ├── AccordionHeader.svelte │ ├── AccordionHeader.svelte.d.ts │ ├── AccordionItem.svelte │ ├── AccordionItem.svelte.d.ts │ ├── AccordionPanel.svelte │ ├── AccordionPanel.svelte.d.ts │ ├── AccordionTypes.d.ts │ └── AccordionTypes.js ├── Button.svelte ├── Button.svelte.d.ts ├── Checkbox.svelte ├── Checkbox.svelte.d.ts ├── Meter.svelte ├── Meter.svelte.d.ts ├── NavBar.svelte ├── NavBar.svelte.d.ts ├── NavBar │ ├── NavBarHeader.svelte │ ├── NavBarHeader.svelte.d.ts │ ├── NavBarLists.svelte │ ├── NavBarLists.svelte.d.ts │ ├── NavBarOptions.svelte │ ├── NavBarOptions.svelte.d.ts │ ├── NavBarTypes.d.ts │ └── NavBarTypes.js ├── README.md ├── Table.svelte ├── Table.svelte.d.ts ├── TextInput.svelte ├── TextInput.svelte.d.ts └── package.json ├── src ├── __tests__ │ ├── Accordion.spec.js │ ├── Button.spec.js │ ├── Checkbox.spec.js │ ├── Meter.spec.js │ ├── NavBar.spec.js │ ├── Radio.spec.js │ ├── Table.spec.js │ └── TextInput.spec.js ├── app.d.ts ├── app.html ├── app.scss ├── components │ ├── NavBar-website.svelte │ └── about-info.svelte ├── images │ ├── Github-logo-circle-purple.png │ ├── Github-logo-white.png │ ├── Github-logo.png │ ├── LinkedIn-logo-circle-purple.png │ ├── LinkedIn-logo-white-circle.png │ ├── LinkedIn-logo.png │ ├── bekFancy.png │ ├── paulFancy.png │ ├── simonFancy.png │ ├── svve11-logo-cropped-blue.png │ ├── svve11-logo-cropped-purple-transparent.png │ ├── svve11-logo-notext.png │ ├── svve11-logo-square-purple.jpg │ ├── svve11-logo-white-transparent-cropped.png │ ├── svve11-logo-white.png │ ├── tech-icons │ │ ├── Firefox_logo_2019.svg │ │ ├── JAWS-screenreader-logo.png │ │ ├── Microsoft_Edge_logo_(2019).svg │ │ ├── Safari_browser_logo.svg │ │ ├── chrome-logo.svg │ │ ├── jest-logo-F9901EBBF7-seeklogo.com.png │ │ ├── nvda_200x200.png │ │ └── voiceover_logo.png │ └── timFancy.png ├── lib │ ├── Accordion.svelte │ ├── Accordion │ │ ├── AccordionButton.svelte │ │ ├── AccordionHeader.svelte │ │ ├── AccordionItem.svelte │ │ ├── AccordionPanel.svelte │ │ └── AccordionTypes.ts │ ├── Button.svelte │ ├── Checkbox.svelte │ ├── Meter.svelte │ ├── NavBar.svelte │ ├── NavBar │ │ ├── NavBarHeader.svelte │ │ ├── NavBarLists.svelte │ │ ├── NavBarOptions.svelte │ │ └── NavBarTypes.ts │ ├── Table.svelte │ └── TextInput.svelte ├── pending │ ├── ImageLink.svelte │ └── RadioButton.svelte ├── routes │ ├── __layout.svelte │ ├── about.svelte │ ├── index.svelte │ └── pages │ │ ├── accordion.svelte │ │ ├── button.svelte │ │ ├── checkbox.svelte │ │ ├── meter.svelte │ │ ├── navbar.svelte │ │ ├── radiobutton.svelte │ │ ├── table.svelte │ │ ├── tableStyles.js │ │ └── textinput.svelte └── stylesheets │ └── variables.scss ├── static └── favicon.png ├── svelte.config.js └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@babel/preset-env", { "targets": { "node": "current" } }]] 3 | } -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | .env 6 | .env.* 7 | !.env.example 8 | /coverage -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true; 2 | global=false; 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Simon H Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | transform: { 3 | "^.+\\.js$": "babel-jest", 4 | "^.+\\.svelte$": ["svelte-jester", { preprocess: true }], 5 | "^.+\\.ts$": "ts-jest", 6 | }, 7 | moduleFileExtensions: [ 8 | "js", 9 | "ts", 10 | "svelte" 11 | ], 12 | verbose: true, 13 | moduleNameMapper: { 14 | "^\\$lib/(.*)": "./src/lib/$1", 15 | }, 16 | collectCoverage: true, 17 | coverageDirectory: "coverage", 18 | testEnvironment: "jsdom", 19 | }; 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svve11", 3 | "version": "1.1.0", 4 | "scripts": { 5 | "dev": "svelte-kit dev", 6 | "build": "svelte-kit build", 7 | "package": "svelte-kit package", 8 | "preview": "svelte-kit preview", 9 | "prepare": "svelte-kit sync", 10 | "check": "svelte-check --tsconfig ./tsconfig.json", 11 | "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", 12 | "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", 13 | "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. .", 14 | "test": "jest" 15 | }, 16 | "exports": { 17 | ".": "./src/lib" 18 | }, 19 | "devDependencies": { 20 | "@babel/preset-env": "^7.18.0", 21 | "@sveltejs/adapter-auto": "next", 22 | "@sveltejs/kit": "next", 23 | "@testing-library/jest-dom": "^5.16.4", 24 | "@testing-library/svelte": "^3.1.1", 25 | "@testing-library/user-event": "^14.2.0", 26 | "@typescript-eslint/eslint-plugin": "^5.10.1", 27 | "@typescript-eslint/parser": "^5.10.1", 28 | "babel-jest": "^28.1.0", 29 | "eslint": "^8.12.0", 30 | "eslint-config-prettier": "^8.3.0", 31 | "eslint-plugin-svelte3": "^4.0.0", 32 | "jest": "^28.1.0", 33 | "jest-environment-jsdom": "^28.1.0", 34 | "prettier": "^2.5.1", 35 | "prettier-plugin-svelte": "^2.5.0", 36 | "sass": "^1.52.1", 37 | "svelte": "^3.44.0", 38 | "svelte-check": "^2.2.6", 39 | "svelte-jester": "^2.3.2", 40 | "svelte-preprocess": "^4.10.6", 41 | "svelte2tsx": "^0.5.10", 42 | "ts-jest": "^28.0.2", 43 | "ts-node": "^10.8.0", 44 | "tslib": "^2.3.1", 45 | "typescript": "~4.6.2" 46 | }, 47 | "type": "module", 48 | "dependencies": { 49 | "svve11": "^0.0.1" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /package/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | .env 6 | .env.* 7 | !.env.example 8 | /coverage -------------------------------------------------------------------------------- /package/Accordion.svelte: -------------------------------------------------------------------------------- 1 | 65 | 66 | 83 | 84 | 86 |
91 | 97 | {#each options.panelInfo as info, i} 98 | 105 | {/each} 106 |
107 | 108 | 109 | 119 | -------------------------------------------------------------------------------- /package/Accordion.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | import type { optionsTypes } from './Accordion/AccordionTypes'; 3 | declare const __propDef: { 4 | props: { 5 | options?: optionsTypes | undefined; 6 | }; 7 | events: { 8 | [evt: string]: CustomEvent; 9 | }; 10 | slots: {}; 11 | }; 12 | export declare type AccordionProps = typeof __propDef.props; 13 | export declare type AccordionEvents = typeof __propDef.events; 14 | export declare type AccordionSlots = typeof __propDef.slots; 15 | /** 16 | * Props are passed in through the options object which contains the following properties: 17 | * ```tsx 18 | * panelInfo: array of objects (required) 19 | * Each object in the array contains: 20 | * - id: number (required) 21 | * - panelContent: string (required) 22 | * - headerTitle: string (required) 23 | * headerLevel: number (required) 24 | * styles: an object with (4) properties (optional) 25 | * - accordionHeaderStyle: string (optional) 26 | * - accordionPanelStyle: string (optional) 27 | * - accordionItemStyle: string (optional) 28 | * - overallAccordionStyle: string (optional) 29 | * multiselectable:boolean (optional) 30 | * ``` 31 | */ 32 | export default class Accordion extends SvelteComponentTyped { 33 | } 34 | export {}; 35 | -------------------------------------------------------------------------------- /package/Accordion/AccordionButton.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 25 | 37 | 38 | 50 | -------------------------------------------------------------------------------- /package/Accordion/AccordionButton.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | headerTitle: string; 5 | controls: string; 6 | id: string; 7 | customStyles: accordionStylesObject; 8 | textToRead: string; 9 | isOpen: boolean; 10 | }; 11 | events: { 12 | updatePanelStates: CustomEvent<{ 13 | target: string; 14 | }>; 15 | } & { 16 | [evt: string]: CustomEvent; 17 | }; 18 | slots: {}; 19 | }; 20 | export declare type AccordionButtonProps = typeof __propDef.props; 21 | export declare type AccordionButtonEvents = typeof __propDef.events; 22 | export declare type AccordionButtonSlots = typeof __propDef.slots; 23 | export default class AccordionButton extends SvelteComponentTyped { 24 | } 25 | export {}; 26 | -------------------------------------------------------------------------------- /package/Accordion/AccordionHeader.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 16 |
22 | 23 | 32 |
33 | 34 | 40 | -------------------------------------------------------------------------------- /package/Accordion/AccordionHeader.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | headerLevel?: number | undefined; 5 | headerTitle: string; 6 | controls?: string | undefined; 7 | customStyles: accordionStylesObject; 8 | textToRead?: string | undefined; 9 | id: string; 10 | isOpen: boolean; 11 | }; 12 | events: { 13 | updatePanelStates: CustomEvent<{ 14 | target: string; 15 | }>; 16 | } & { 17 | [evt: string]: CustomEvent; 18 | }; 19 | slots: {}; 20 | }; 21 | export declare type AccordionHeaderProps = typeof __propDef.props; 22 | export declare type AccordionHeaderEvents = typeof __propDef.events; 23 | export declare type AccordionHeaderSlots = typeof __propDef.slots; 24 | export default class AccordionHeader extends SvelteComponentTyped { 25 | } 26 | export {}; 27 | -------------------------------------------------------------------------------- /package/Accordion/AccordionItem.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 16 |
17 | 26 | 36 | 37 | 43 | 50 |
51 | 52 | 53 | 59 | -------------------------------------------------------------------------------- /package/Accordion/AccordionItem.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | import type { panelInfoTypes, accordionStylesObjectTypes } from './AccordionTypes'; 3 | declare const __propDef: { 4 | props: { 5 | options: panelInfoTypes; 6 | headerLevel?: number | undefined; 7 | customStyles: accordionStylesObjectTypes; 8 | isOpen: boolean; 9 | }; 10 | events: { 11 | updatePanelStates: CustomEvent<{ 12 | target: string; 13 | }>; 14 | } & { 15 | [evt: string]: CustomEvent; 16 | }; 17 | slots: {}; 18 | }; 19 | export declare type AccordionItemProps = typeof __propDef.props; 20 | export declare type AccordionItemEvents = typeof __propDef.events; 21 | export declare type AccordionItemSlots = typeof __propDef.slots; 22 | export default class AccordionItem extends SvelteComponentTyped { 23 | } 24 | export {}; 25 | -------------------------------------------------------------------------------- /package/Accordion/AccordionPanel.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 |
22 | 23 | {#if isOpen} 24 |

{panelContent}

25 | {/if} 26 |
27 | 28 | 29 | 43 | -------------------------------------------------------------------------------- /package/Accordion/AccordionPanel.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | panelContent?: string | undefined; 5 | isOpen: boolean; 6 | panelID: string; 7 | labeledBy: string; 8 | style?: string | undefined; 9 | }; 10 | events: { 11 | [evt: string]: CustomEvent; 12 | }; 13 | slots: {}; 14 | }; 15 | export declare type AccordionPanelProps = typeof __propDef.props; 16 | export declare type AccordionPanelEvents = typeof __propDef.events; 17 | export declare type AccordionPanelSlots = typeof __propDef.slots; 18 | export default class AccordionPanel extends SvelteComponentTyped { 19 | } 20 | export {}; 21 | -------------------------------------------------------------------------------- /package/Accordion/AccordionTypes.d.ts: -------------------------------------------------------------------------------- 1 | export declare type panelInfoTypes = { 2 | id: number | string; 3 | panelContent: string; 4 | headerTitle: string; 5 | }; 6 | export declare type optionsTypes = { 7 | multiselectable: boolean; 8 | headerLevel: (number | undefined); 9 | panelInfo: panelInfoTypes[]; 10 | styles?: accordionStylesObjectTypes; 11 | }; 12 | export declare type accordionStylesObjectTypes = { 13 | accordionHeaderStyle?: string; 14 | accordionPanelStyle?: string; 15 | accordionItemStyle?: string; 16 | overallAccordionStyle?: string; 17 | }; 18 | -------------------------------------------------------------------------------- /package/Accordion/AccordionTypes.js: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /package/Button.svelte: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 22 | 25 | 26 | 27 | 35 | -------------------------------------------------------------------------------- /package/Button.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | options?: { 5 | handleClick: () => void; 6 | content: string | null; 7 | label: string | null; 8 | id?: string | null | undefined; 9 | style?: string | null | undefined; 10 | } | undefined; 11 | }; 12 | events: { 13 | [evt: string]: CustomEvent; 14 | }; 15 | slots: {}; 16 | }; 17 | export declare type ButtonProps = typeof __propDef.props; 18 | export declare type ButtonEvents = typeof __propDef.events; 19 | export declare type ButtonSlots = typeof __propDef.slots; 20 | /** 21 | * Props are passed in through the options object which contains the following properties: 22 | * ```tsx 23 | * label: string (required) 24 | * content: string (required) 25 | * handleClick: function (required) 26 | * id: string (optional) 27 | * style: string (optional) 28 | * ``` 29 | */ 30 | export default class Button extends SvelteComponentTyped { 31 | } 32 | export {}; 33 | -------------------------------------------------------------------------------- /package/Checkbox.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 | 28 | 29 | 30 | 40 | 41 | 42 | 45 | 46 | 48 | -------------------------------------------------------------------------------- /package/Checkbox.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | options?: { 5 | checkBoxLabel: string | null; 6 | id: string | null; 7 | checked: boolean; 8 | checkBoxStyle?: string | null | undefined; 9 | checkBoxLabelStyle?: string | null | undefined; 10 | name?: string | null | undefined; 11 | value?: string | null | undefined; 12 | } | undefined; 13 | defaultStyle?: string | undefined; 14 | }; 15 | events: { 16 | [evt: string]: CustomEvent; 17 | }; 18 | slots: {}; 19 | }; 20 | export declare type CheckboxProps = typeof __propDef.props; 21 | export declare type CheckboxEvents = typeof __propDef.events; 22 | export declare type CheckboxSlots = typeof __propDef.slots; 23 | /** 24 | * Props are passed in through the options object which contains the following properties: 25 | * ```tsx 26 | * id: string (required) 27 | * checkBoxLabel: string (required) 28 | * 29 | * checkBoxStyle: number (string) 30 | * checked: boolean (optional) 31 | * checkBoxLabelStyle: string (optional) 32 | * name: string (optional) 33 | * value: string (optional) 34 | * ``` 35 | */ 36 | export default class Checkbox extends SvelteComponentTyped { 37 | } 38 | export {}; 39 | -------------------------------------------------------------------------------- /package/Meter.svelte: -------------------------------------------------------------------------------- 1 | 48 | 49 | 69 | 70 | 78 | 79 | 96 | 97 | 99 | -------------------------------------------------------------------------------- /package/Meter.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | options?: { 5 | maxValue: number; 6 | minValue: number; 7 | meterLabel: string | null; 8 | id: string | number | null; 9 | lowValue?: number | null | undefined; 10 | highValue?: number | null | undefined; 11 | optimumValue?: number | null | undefined; 12 | valueText?: string | null | undefined; 13 | displayDecimal?: boolean | undefined; 14 | units?: string | null | undefined; 15 | meterStyle?: string | null | undefined; 16 | labelStyle?: string | null | undefined; 17 | } | undefined; 18 | value: number; 19 | }; 20 | events: { 21 | [evt: string]: CustomEvent; 22 | }; 23 | slots: {}; 24 | }; 25 | export declare type MeterProps = typeof __propDef.props; 26 | export declare type MeterEvents = typeof __propDef.events; 27 | export declare type MeterSlots = typeof __propDef.slots; 28 | /** 29 | * Props are passed in through an options object, except for the value which is a separate attribute. 30 | * Options should be defined by an object containing the following properties 31 | * ```tsx 32 | * value: number (required) - Passed as separate attribute 33 | * maxValue: number (required) 34 | * minValue: number (required) 35 | * meterLabel: string (required) 36 | * id: number (required) 37 | * 38 | * lowValue: number (optional) 39 | * highValue : number (optional) 40 | * optimumValue : number (optional) 41 | * valueText : string (optional) 42 | * displayDecimal : boolean (optional) 43 | * units : string (optional) 44 | * meterStyle : string (optional) 45 | * labelStyle : string (optional) 46 | * ``` 47 | */ 48 | export default class Meter extends SvelteComponentTyped { 49 | } 50 | export {}; 51 | -------------------------------------------------------------------------------- /package/NavBar.svelte: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 27 | 28 | 29 | 30 | 34 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /package/NavBar.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | import type { optionsTypes } from './NavBar/NavBarTypes'; 3 | declare const __propDef: { 4 | props: { 5 | options?: optionsTypes | undefined; 6 | }; 7 | events: { 8 | [evt: string]: CustomEvent; 9 | }; 10 | slots: {}; 11 | }; 12 | export declare type NavBarProps = typeof __propDef.props; 13 | export declare type NavBarEvents = typeof __propDef.events; 14 | export declare type NavBarSlots = typeof __propDef.slots; 15 | /** 16 | * Props are passed in through the options object which contains the following properties: 17 | * ```tsx 18 | * contentInfo : array of objects (required) 19 | * Each object in the array contains: 20 | * - subheading: string (optional) 21 | * - option: an array of strings (required) 22 | * - links: array (required) 23 | * 24 | * id: string (optional) 25 | * header: string (optional) 26 | * imgSrc: string (optional) 27 | * imgClass: string (optional) 28 | * imgAlt: string (optional) 29 | * ``` 30 | */ 31 | export default class NavBar extends SvelteComponentTyped { 32 | } 33 | export {}; 34 | -------------------------------------------------------------------------------- /package/NavBar/NavBarHeader.svelte: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | {#if header} 16 |

{header}

17 | {/if} 18 | 19 | > 20 | {#if imgSrc} 21 | {imgAlt} 22 | {/if} 23 | 24 | 25 | 27 | -------------------------------------------------------------------------------- /package/NavBar/NavBarHeader.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | header: string; 5 | imgSrc: string; 6 | imgClass: string; 7 | imgAlt: string; 8 | }; 9 | events: { 10 | [evt: string]: CustomEvent; 11 | }; 12 | slots: {}; 13 | }; 14 | export declare type NavBarHeaderProps = typeof __propDef.props; 15 | export declare type NavBarHeaderEvents = typeof __propDef.events; 16 | export declare type NavBarHeaderSlots = typeof __propDef.slots; 17 | export default class NavBarHeader extends SvelteComponentTyped { 18 | } 19 | export {}; 20 | -------------------------------------------------------------------------------- /package/NavBar/NavBarLists.svelte: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | {#if subheading} 13 |

{subheading}

14 | {/if} 15 | 16 | 17 |
    18 | {#each options as option, i} 19 |
  • 20 | {option} 21 |
  • 22 | {/each} 23 |
24 | 25 | 26 | 28 | -------------------------------------------------------------------------------- /package/NavBar/NavBarLists.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | subheading: string; 5 | options?: string[] | undefined; 6 | links?: string[] | undefined; 7 | }; 8 | events: { 9 | [evt: string]: CustomEvent; 10 | }; 11 | slots: {}; 12 | }; 13 | export declare type NavBarListsProps = typeof __propDef.props; 14 | export declare type NavBarListsEvents = typeof __propDef.events; 15 | export declare type NavBarListsSlots = typeof __propDef.slots; 16 | export default class NavBarLists extends SvelteComponentTyped { 17 | } 18 | export {}; 19 | -------------------------------------------------------------------------------- /package/NavBar/NavBarOptions.svelte: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | {#each contentInfo as content, i} 12 | 13 | {/each} 14 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /package/NavBar/NavBarOptions.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | import type { sectionTypes } from './NavBarTypes'; 3 | declare const __propDef: { 4 | props: { 5 | contentInfo?: sectionTypes[] | undefined; 6 | }; 7 | events: { 8 | [evt: string]: CustomEvent; 9 | }; 10 | slots: {}; 11 | }; 12 | export declare type NavBarOptionsProps = typeof __propDef.props; 13 | export declare type NavBarOptionsEvents = typeof __propDef.events; 14 | export declare type NavBarOptionsSlots = typeof __propDef.slots; 15 | export default class NavBarOptions extends SvelteComponentTyped { 16 | } 17 | export {}; 18 | -------------------------------------------------------------------------------- /package/NavBar/NavBarTypes.d.ts: -------------------------------------------------------------------------------- 1 | export declare type optionsTypes = { 2 | id?: string; 3 | header?: string; 4 | imgSrc?: string; 5 | imgClass?: string; 6 | imgAlt?: string; 7 | contentInfo: sectionTypes[]; 8 | }; 9 | export declare type sectionTypes = { 10 | subheading?: string; 11 | options: string[]; 12 | links: string[]; 13 | }; 14 | -------------------------------------------------------------------------------- /package/NavBar/NavBarTypes.js: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /package/Table.svelte: -------------------------------------------------------------------------------- 1 | 2 | 29 | 30 | 31 | 50 |
51 | 58 | 59 | 66 | 67 | 68 | 69 | 70 | 71 | {#each columnNames as columnName} 72 | 73 | {/each} 74 | 75 | 76 | 77 | 78 | {#each rowsContent as rowContent, i} 79 | 80 | 81 | {#each rowContent as cellContent} 82 | 83 | 92 | {/each} 93 | 94 | {/each} 95 | 96 |
64 | {ariaDescription} 65 |
{columnName}
{cellContent}
97 |
98 | 99 | 100 | 111 | -------------------------------------------------------------------------------- /package/Table.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | options?: { 5 | id: string; 6 | ariaLabel: string; 7 | ariaDescription: string; 8 | columnNames: string[]; 9 | rowsContent: string[][]; 10 | styles?: { 11 | overallStyles?: string | undefined; 12 | titleStyles?: string | undefined; 13 | headersRowStyles?: string | undefined; 14 | generalRowStyles?: string | undefined; 15 | oddRowStyles?: string | undefined; 16 | evenRowStyles?: string | undefined; 17 | } | undefined; 18 | } | undefined; 19 | }; 20 | events: { 21 | [evt: string]: CustomEvent; 22 | }; 23 | slots: {}; 24 | }; 25 | export declare type TableProps = typeof __propDef.props; 26 | export declare type TableEvents = typeof __propDef.events; 27 | export declare type TableSlots = typeof __propDef.slots; 28 | /** 29 | * https://svve11.io/pages/table 30 | * 31 | * Props are passed in through the options object that contains the following properties: 32 | * ```tsx 33 | * id: string (required) 34 | * ariaLabel: string (required) 35 | * ariaDescription: string (required) 36 | * columnNames: array of string (required) 37 | * rowsContent: array of arrays of strings (required) 38 | * styles: object (optional) 39 | * - overallStyles:string (optional) 40 | * - titleStyles:string (optional) 41 | * - headersRowStyles:string (optional) 42 | * - generalRowStyles:string (optional) 43 | * - oddRowStyles:string (optional) 44 | * - evenRowStyles:string (optional) 45 | * ``` 46 | */ 47 | export default class Table extends SvelteComponentTyped { 48 | } 49 | export {}; 50 | -------------------------------------------------------------------------------- /package/TextInput.svelte: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 22 | 23 | 26 | 43 | 44 | 45 | 47 | -------------------------------------------------------------------------------- /package/TextInput.svelte.d.ts: -------------------------------------------------------------------------------- 1 | import { SvelteComponentTyped } from "svelte"; 2 | declare const __propDef: { 3 | props: { 4 | options?: { 5 | label: string | null; 6 | placeholder: string | null; 7 | id: string | null; 8 | type: ("" | "number" | "date" | "datetime-local" | "email" | "month" | "password" | "tel" | "text" | "time" | "url" | "week") | null; 9 | max?: number | null | undefined; 10 | min?: number | null | undefined; 11 | maxlength?: number | null | undefined; 12 | size?: number | null | undefined; 13 | step?: number | null | undefined; 14 | inputStyle?: string | null | undefined; 15 | labelStyle?: string | null | undefined; 16 | autocomplete?: boolean | undefined; 17 | disabled?: boolean | undefined; 18 | multiple?: boolean | undefined; 19 | readonly?: boolean | undefined; 20 | required?: boolean | undefined; 21 | } | undefined; 22 | }; 23 | events: { 24 | [evt: string]: CustomEvent; 25 | }; 26 | slots: {}; 27 | }; 28 | export declare type TextInputProps = typeof __propDef.props; 29 | export declare type TextInputEvents = typeof __propDef.events; 30 | export declare type TextInputSlots = typeof __propDef.slots; 31 | /** 32 | * Props are passed in through the options object which contains the following properties: 33 | * ```tsx 34 | * label: string (required) 35 | * placeholder: string (required) 36 | * id: string (required) 37 | * type: string (required) 38 | * inputStyle: string (optional) 39 | * labelStyle: string (optional) 40 | * ``` 41 | */ 42 | export default class TextInput extends SvelteComponentTyped { 43 | } 44 | export {}; 45 | -------------------------------------------------------------------------------- /package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svve11", 3 | "version": "1.2.0", 4 | "exports": { 5 | "./package.json": "./package.json", 6 | ".": "./src/lib", 7 | "./Accordion/AccordionButton.svelte": "./Accordion/AccordionButton.svelte", 8 | "./Accordion/AccordionHeader.svelte": "./Accordion/AccordionHeader.svelte", 9 | "./Accordion/AccordionItem.svelte": "./Accordion/AccordionItem.svelte", 10 | "./Accordion/AccordionPanel.svelte": "./Accordion/AccordionPanel.svelte", 11 | "./Accordion/AccordionTypes": "./Accordion/AccordionTypes.js", 12 | "./Accordion.svelte": "./Accordion.svelte", 13 | "./Button.svelte": "./Button.svelte", 14 | "./Checkbox.svelte": "./Checkbox.svelte", 15 | "./Meter.svelte": "./Meter.svelte", 16 | "./NavBar/NavBarHeader.svelte": "./NavBar/NavBarHeader.svelte", 17 | "./NavBar/NavBarLists.svelte": "./NavBar/NavBarLists.svelte", 18 | "./NavBar/NavBarOptions.svelte": "./NavBar/NavBarOptions.svelte", 19 | "./NavBar/NavBarTypes": "./NavBar/NavBarTypes.js", 20 | "./NavBar.svelte": "./NavBar.svelte", 21 | "./Table.svelte": "./Table.svelte", 22 | "./TextInput.svelte": "./TextInput.svelte" 23 | }, 24 | "devDependencies": { 25 | "@babel/preset-env": "^7.18.0", 26 | "@sveltejs/adapter-auto": "next", 27 | "@sveltejs/kit": "next", 28 | "@testing-library/jest-dom": "^5.16.4", 29 | "@testing-library/svelte": "^3.1.1", 30 | "@testing-library/user-event": "^14.2.0", 31 | "@typescript-eslint/eslint-plugin": "^5.10.1", 32 | "@typescript-eslint/parser": "^5.10.1", 33 | "babel-jest": "^28.1.0", 34 | "eslint": "^8.12.0", 35 | "eslint-config-prettier": "^8.3.0", 36 | "eslint-plugin-svelte3": "^4.0.0", 37 | "jest": "^28.1.0", 38 | "jest-environment-jsdom": "^28.1.0", 39 | "prettier": "^2.5.1", 40 | "prettier-plugin-svelte": "^2.5.0", 41 | "sass": "^1.52.1", 42 | "svelte": "^3.44.0", 43 | "svelte-check": "^2.2.6", 44 | "svelte-jester": "^2.3.2", 45 | "svelte-preprocess": "^4.10.6", 46 | "svelte2tsx": "^0.5.10", 47 | "ts-jest": "^28.0.2", 48 | "ts-node": "^10.8.0", 49 | "tslib": "^2.3.1", 50 | "typescript": "~4.6.2" 51 | }, 52 | "type": "module", 53 | "dependencies": { 54 | "svve11": "^0.0.1" 55 | }, 56 | "svelte": "./src/lib" 57 | } -------------------------------------------------------------------------------- /src/__tests__/Accordion.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import '@testing-library/jest-dom'; 3 | import { render } from '@testing-library/svelte'; 4 | import userEvent from '@testing-library/user-event'; 5 | 6 | import Accordion from '../lib/Accordion.svelte'; 7 | 8 | // List of Accordion Parts: 9 | // - Accordion: contains accordion item(s) 10 | // - Accordion Item: contains header and panel 11 | // - Accordion Header: contains button 12 | // - Accordion Button: labels header 13 | // - Accordion Panel: contains contents 14 | 15 | describe('Accessible Accordion Unit Tests', () => { 16 | const options = { 17 | multiselectable: true, 18 | headerLevel: 4, 19 | styles: { 20 | accordionHeaderStyle: 'Header styles string', 21 | accordionPanelStyle: 'Panel styles string;', 22 | accordionItemStyle: 'Item styles string', 23 | overallAccordionStyle: 'Accordion styles string' 24 | }, 25 | panelInfo: [ 26 | { 27 | id: 1, 28 | panelContent: 29 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lacus suspendisse faucibus interdum posuere lorem ipsum dolor sit amet. Cursus eget nunc scelerisque viverra mauris. Lacus laoreet non curabitur gravida arcu ac tortor dignissim. Proin fermentum leo vel orci porta non pulvinar neque laoreet. Nisl vel pretium lectus quam id. Ultrices eros in cursus turpis massa. Mauris pharetra et ultrices neque. Tristique senectus et netus et malesuada fames ac turpis. Turpis tincidunt id aliquet risus feugiat in ante metus. Pellentesque habitant morbi tristique senectus et netus et malesuada.', 30 | headerTitle: 'First Section' 31 | }, 32 | { 33 | id: 2, 34 | panelContent: 35 | 'Et sollicitudin ac orci phasellus egestas tellus rutrum tellus. Ut enim blandit volutpat maecenas volutpat blandit. Mi ipsum faucibus vitae aliquet nec. Dui ut ornare lectus sit amet est placerat in. Convallis convallis tellus id interdum. Vitae aliquet nec ullamcorper sit amet risus. Eu mi bibendum neque egestas congue quisque egestas diam in. Fermentum iaculis eu non diam phasellus vestibulum lorem sed risus. Ullamcorper a lacus vestibulum sed. Vitae purus faucibus ornare suspendisse. Curabitur gravida arcu ac tortor dignissim convallis. Viverra ipsum nunc aliquet bibendum enim facilisis gravida. Dolor magna eget est lorem ipsum dolor sit amet consectetur. Id leo in vitae turpis massa sed. Faucibus interdum posuere lorem ipsum dolor.', 36 | headerTitle: 'Second Section' 37 | } 38 | ] 39 | }; 40 | 41 | describe('Button Unit Tests', () => { 42 | let buttons, button, user; 43 | beforeEach(() => { 44 | const { getAllByRole, getByText } = render(Accordion, { options }); 45 | buttons = getAllByRole('button'); 46 | button = getByText('First Section'); 47 | user = userEvent.setup(); 48 | }); 49 | 50 | it('should have a role attribute set to button', () => { 51 | expect(buttons.length).toEqual(options.panelInfo.length); 52 | }); 53 | 54 | it('should have no siblings', () => { 55 | expect(button.nextElementSibling).toEqual(null); 56 | }); 57 | 58 | it('should have an attribute aria-expanded initialized to false', () => { 59 | expect(button.getAttribute('aria-expanded')).toEqual('false'); 60 | }); 61 | 62 | it('should toggle aria-expanded when clicked', async () => { 63 | expect(button.getAttribute('aria-expanded')).toEqual('false'); 64 | await user.click(button); 65 | expect(button.getAttribute('aria-expanded')).toEqual('true'); 66 | await user.click(button); 67 | expect(button.getAttribute('aria-expanded')).toEqual('false'); 68 | }); 69 | 70 | it('should have an attribute aria-label that toggles between an empty string and panel contents when clicked', async () => { 71 | expect(button.getAttribute('aria-label')).toEqual(''); 72 | await user.click(button); 73 | expect(button.getAttribute('aria-label')).toEqual(options.panelInfo[0].panelContent); 74 | await user.click(button); 75 | expect(button.getAttribute('aria-label')).toEqual(''); 76 | }); 77 | 78 | it('should have a class name set to header-button', () => { 79 | expect(button.getAttribute('class')).toContain('sv-accordion-button'); 80 | }); 81 | 82 | it('should habe an id attribute set to button and the id number', () => { 83 | expect(button.getAttribute('id')).toEqual(`button${options.panelInfo[0].id}`); 84 | }); 85 | 86 | it('should have an attribute aria-controls set to the panel it controls', () => { 87 | expect(button.getAttribute('aria-controls')).toEqual(`panel${options.panelInfo[0].id}`); 88 | }); 89 | 90 | it('should be passed the styles string in the accordionHeaderStyle of the styles property in options object', () => { 91 | expect(button.getAttribute('style')).toEqual(options.styles.accordionHeaderStyle); 92 | }); 93 | 94 | it('should be able to have focus', () => { 95 | user.tab(); 96 | expect(button).toHaveFocus(); 97 | }); 98 | 99 | it('should expand/collapse when space key is pressed', async () => { 100 | user.tab(); 101 | expect(button.getAttribute('aria-expanded')).toEqual('false'); 102 | expect(button).toHaveFocus(); 103 | expect(button.getAttribute('aria-label')).toEqual(''); 104 | await user.keyboard(' '); 105 | expect(button.getAttribute('aria-expanded')).toEqual('true'); 106 | expect(button.getAttribute('aria-label')).toEqual(options.panelInfo[0].panelContent); 107 | await user.keyboard('{enter}'); 108 | expect(button.getAttribute('aria-expanded')).toEqual('false'); 109 | expect(button.getAttribute('aria-label')).toEqual(''); 110 | }); 111 | 112 | it('should expand/collapse when enter key is pressed', async () => { 113 | user.tab(); 114 | expect(button.getAttribute('aria-expanded')).toEqual('false'); 115 | expect(button).toHaveFocus(); 116 | expect(button.getAttribute('aria-label')).toEqual(''); 117 | await user.keyboard('{enter}'); 118 | expect(button.getAttribute('aria-expanded')).toEqual('true'); 119 | expect(button.getAttribute('aria-label')).toEqual(options.panelInfo[0].panelContent); 120 | await user.keyboard('{enter}'); 121 | expect(button.getAttribute('aria-expanded')).toEqual('false'); 122 | expect(button.getAttribute('aria-label')).toEqual(''); 123 | }); 124 | }); 125 | 126 | describe('Header Unit Tests', () => { 127 | let headers, heading, button; 128 | beforeEach(() => { 129 | const { getAllByRole, getByText } = render(Accordion, { options }); 130 | headers = getAllByRole('heading'); 131 | heading = getAllByRole('heading')[0]; 132 | button = getByText('First Section'); 133 | }); 134 | 135 | it('should have a role attribute set to heading', () => { 136 | expect(headers.length).toEqual(options.panelInfo.length); 137 | }); 138 | 139 | it('should have a class attribute set to accordion-header', () => { 140 | expect(heading.getAttribute('class')).toContain('accordion-header'); 141 | }); 142 | 143 | it('should have a child that is a button', () => { 144 | expect(heading.firstChild).toBe(button); 145 | }); 146 | 147 | it('should have an aria-level attribute set to appropriate header level number', () => { 148 | expect(heading.getAttribute('aria-level')).toEqual(options.headerLevel.toString()); 149 | }); 150 | 151 | it('should be passed the styles string in the 0th index of the styles array', () => { 152 | expect(heading.getAttribute('style')).toEqual(options.styles.accordionHeaderStyle); 153 | }); 154 | }); 155 | 156 | describe('Panel Unit Tests', () => { 157 | let panels, panel; 158 | 159 | beforeEach(() => { 160 | const { getAllByRole } = render(Accordion, { options }); 161 | panels = getAllByRole('region'); 162 | panel = panels[0]; 163 | }); 164 | 165 | it('should have a role attribute set to region', () => { 166 | expect(panels.length).toEqual(options.panelInfo.length); 167 | }); 168 | 169 | it('should have an id attribute set to panel and the appropriate id number', () => { 170 | expect(panel.getAttribute('id')).toEqual(`panel${options.panelInfo[0].id}`); 171 | }); 172 | 173 | it('should have an aria-labelledby attribute set to the button labeling it', () => { 174 | expect(panel.getAttribute('aria-labelledby')).toEqual(`button${options.panelInfo[0].id}`); 175 | }); 176 | 177 | it('should have a class attribute set to accordion-panel', () => { 178 | expect(panel.getAttribute('class')).toContain('accordion-panel'); 179 | }); 180 | 181 | it('should be passed the appropriate styles', () => { 182 | expect(panel.getAttribute('style')).toEqual(options.styles.accordionPanelStyle); 183 | }); 184 | }); 185 | 186 | describe('Item Unit Tests', () => { 187 | let items, item, button, panel, header, user; 188 | beforeEach(() => { 189 | const { getByText, getAllByRole } = render(Accordion, { options }); 190 | items = document.getElementsByClassName('sv-accordion-item'); 191 | item = items[0]; 192 | button = document.querySelector('.sv-accordion-button'); 193 | panel = document.querySelector('.sv-accordion-panel'); 194 | header = document.querySelectorAll('.sv-accordion-header')[0]; 195 | user = userEvent.setup(); 196 | }); 197 | 198 | it('should render one item for each panelInfo in options object', () => { 199 | expect(items.length).toEqual(options.panelInfo.length); 200 | }); 201 | 202 | it('should have a data-state attribute set to collapsed initially, and should toggle to expanded when corresponding button is clicked', async () => { 203 | expect(item.getAttribute('data-state')).toBe('collapsed'); 204 | await user.click(button); 205 | expect(item.getAttribute('data-state')).toBe('expanded'); 206 | }); 207 | 208 | it('should have two children, the first being the button and the second the panel', () => { 209 | expect(item.firstChild).toBe(header); 210 | expect(item.firstChild.firstChild).toBe(button); 211 | expect(item.firstChild.nextElementSibling).toBe(panel); 212 | expect(item.firstChild.nextElementSibling.nextElementSibling).toEqual(null); 213 | }); 214 | }); 215 | 216 | describe('Accordion Unit Tests', () => { 217 | it('should have an aria-multiselectable attribute corresponding to that passed into the options object', () => { 218 | const {} = render(Accordion, { options }); 219 | const accordion = document.getElementsByClassName('sv-accordion-main')[0]; 220 | expect(accordion.getAttribute('aria-multiselectable')).toEqual(`${options.multiselectable}`); 221 | }); 222 | }); 223 | }); 224 | -------------------------------------------------------------------------------- /src/__tests__/Button.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | 3 | import '@testing-library/jest-dom'; 4 | import { render } from '@testing-library/svelte'; 5 | // import '@testing-library/svelte'; 6 | import userEvent from '@testing-library/user-event'; 7 | import Button from '../lib/Button.svelte'; 8 | 9 | let user; 10 | let button; 11 | const options = { 12 | content: 'test descriptive content', 13 | id: 'test-button', 14 | label: 'accessible-button', 15 | handleClick: (e) => (e.target.textContent = 'clicked') 16 | }; 17 | 18 | // before each test runs run, 19 | beforeEach(() => { 20 | // set up a user to dispatch events 21 | user = userEvent.setup(); 22 | 23 | // render a Button for testing 24 | const { getByText } = render(Button, { options }); 25 | button = getByText('test descriptive content'); 26 | }); 27 | 28 | describe('Running accessible Button tests', () => { 29 | describe('WAI-ARIA Roles, States, Properties tests', () => { 30 | test('It has an accessible label', () => { 31 | expect(button).toHaveAttribute('aria-label'); 32 | }); 33 | 34 | test('It has an accessible name', () => { 35 | expect(button).toHaveAccessibleName('accessible-button'); 36 | }); 37 | 38 | test('Its content is unique and descriptive', () => { 39 | expect(button).toHaveTextContent('test descriptive content'); 40 | }); 41 | 42 | test('It is not autofocused', () => { 43 | expect(document.activeElement).not.toBe(button); 44 | }); 45 | 46 | test('It can can be be activated with a click', async () => { 47 | await user.click(button); 48 | expect(button).toHaveTextContent('clicked'); 49 | }); 50 | 51 | test('It triggers an event or action', async () => { 52 | await user.click(button); 53 | expect(button).toHaveTextContent('clicked'); 54 | }); 55 | }); 56 | 57 | describe('Keyboard interaction tests', () => { 58 | test('It can be focused by pressing tab', async () => { 59 | await user.tab(); 60 | expect(document.activeElement).toBe(button); 61 | }); 62 | 63 | test('It can can be be activated by pressing space', async () => { 64 | // focus the button 65 | user.tab(); 66 | // press space 67 | await user.keyboard(' '); 68 | expect(button).toHaveTextContent('clicked'); 69 | }); 70 | 71 | test('It can can be be activated by pressing enter', async () => { 72 | // focus the button 73 | user.tab(); 74 | // press enter 75 | await user.keyboard('{enter}'); 76 | expect(button).toHaveTextContent('clicked'); 77 | }); 78 | 79 | test('Keys that are not space or enter do not activate the button', async () => { 80 | user.tab(); 81 | await user.keyboard('`1234567890qwertyuiopasdfghjklzxcvbnm'); 82 | expect(button).toHaveTextContent('test descriptive content'); 83 | }); 84 | }); 85 | }); 86 | 87 | /** 88 | * Tests: 89 | * ---------------------------------------------------------- 90 | * WAI-ARIA Roles, States, Properties: 91 | * ---------------------------------------------------------- 92 | * - has a role of button 93 | * - its content is unique and descriptive 94 | * - it cannot be autofocused 95 | * - has an accessible label 96 | * - default: computed from any text content inside btn elmt 97 | * - can also be provided by aria-labelledby or aria-label 98 | * - if it has a description 99 | * - aria-describedby is set to ID of elmt containing the description 100 | * - aria-disabled is set to true when action associated w/ btn is unavailable 101 | * - all of its descendants are presentational 102 | * 103 | * If Toggle button... 104 | * - it has an aria-pressed attribute 105 | * - aria-pressed is set to true when btn toggled on 106 | * - aria-pressed is set to false when btn toggled off 107 | * 108 | * If Menu button... 109 | * - it has an aria-haspopup attribute 110 | * - aria-haspopup is set to either menu OR true 111 | * - You should be able to focus the button 112 | * - and then it should activate 113 | * - on Click events 114 | * - on pressing Space 115 | * - on pressing Enter 116 | * - It should not be activated by any other events 117 | * 118 | * - Does it trigger the desired event or action? 119 | * e.g. submit a form, open a dialog, perform a delete operation 120 | * - it should either be... 121 | * - a button element 122 | * - a input element with type = "button" 123 | * - if anything else: 124 | * - should be focusable 125 | * - should have event handlers for click events 126 | * - should have event handlers for keydown events 127 | * 128 | * ---------------------------------------------------------- 129 | * Keyboard interaction tests: 130 | * ---------------------------------------------------------- 131 | * - after button activation, it focus should be set correctly depending on button action 132 | * - if activation does NOT dismiss current context: 133 | * focus typ. returns to button 134 | * - opens a dialog: 135 | * focus moves inside the dialog 136 | * - closes a dialog: 137 | * focus typ. returns to button that opened the dialog 138 | * - action indicates a context change 139 | * focus typ. moves to starting point for that action 140 | * - if btn activated w/ a shortcut key 141 | * typ. remains in context from which shortcut ky was activated 142 | * e.g. if Alt + U were assigned to an "Up" button that moves 143 | * the currently focused item in a list one position higher in the list, 144 | * pressing Alt + U when the focus is in the list 145 | * would not move the focus from the list. 146 | * 147 | * ---------------------------------------------------------- 148 | * Other: 149 | * ---------------------------------------------------------- 150 | * - its [text] content has minimum 4.5:1 contrast ratio to its background 151 | * - if it has a border 152 | * - its border color has minimum 3:1 contrast ratio to its surrounding context elmts 153 | * - if it doesn't have a border 154 | * - its background color has minimum 3:1 contrast ratio to its surrounding context elmts 155 | * - OR its background color is the same as its surrounding context 156 | * - it has a different style for when it's focused 157 | * - if btn can be disabled, aria-disabled set to true when disabled, false when active 158 | */ 159 | -------------------------------------------------------------------------------- /src/__tests__/Checkbox.spec.js: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | import { render } from '@testing-library/svelte'; 3 | import userEvent from '@testing-library/user-event'; 4 | import Checkbox from '../lib/Checkbox.svelte'; 5 | 6 | let user; 7 | let checkbox; 8 | const options = { 9 | checkBoxLabel: 'This is checkbox value', 10 | id: 'checkBoxOne', 11 | checked: false, 12 | defaultStyle: 'display: inline-block; user-select: none;' 13 | }; 14 | 15 | beforeEach(() => { 16 | user = userEvent.setup(); 17 | const { component } = render(Checkbox, { options }); 18 | checkbox = document.getElementById('checkBoxOne'); 19 | }); 20 | 21 | describe('Accessible Checkbox Testing Unit Tests', () => { 22 | test('checking for aria-label', () => { 23 | expect(checkbox).toHaveAttribute('aria-label'); 24 | }); 25 | 26 | test('checking for id', () => { 27 | expect(checkbox).toHaveAttribute('id'); 28 | }); 29 | 30 | test('checking for type', () => { 31 | expect(checkbox).toHaveAttribute('type'); 32 | }); 33 | 34 | test('testing if the checkbox is starting off as not checked', () => { 35 | expect(checkbox.getAttribute('checked')).toBeFalsy(); 36 | }); 37 | 38 | test('checking for type to equal checkbox', () => { 39 | expect(checkbox.getAttribute('type')).toEqual('checkbox'); 40 | }); 41 | 42 | test('checking if check box name is accessible', () => { 43 | // expect(checkbox.getAttribute('name')).toEqual('accessible-checkbox'); 44 | }); 45 | 46 | test('checking if check box name is accessible', () => { 47 | // expect(checkbox.getAttribute('value')).toEqual('box'); 48 | }); 49 | 50 | // test('checking for checkbox display styling', () => { 51 | // expect(checkbox.getAttribute('style')).toEqual(props.styles[0]); 52 | // }); 53 | 54 | // test('checking for checkbox user-select styling', () => { 55 | // expect(checkbox.getAttribute('style').toEqual(props.styles[1])); 56 | // }); 57 | }); 58 | 59 | // describe('Accessible button key press testing', () => { 60 | // test('checking it on/off when space press', async () => { 61 | // user.tab(); 62 | // await user.keyboard(' '); 63 | // expect(checkbox.getAttribute('checked')).toBeTruthy(); 64 | // }); 65 | // }); 66 | -------------------------------------------------------------------------------- /src/__tests__/Meter.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import '@testing-library/jest-dom'; 3 | import { render } from '@testing-library/svelte'; 4 | import { get } from 'svelte/store'; 5 | // import userEvent from '@testing-library/user-event'; 6 | 7 | import Meter from '../lib/Meter.svelte'; 8 | 9 | describe('Meter Unit Tests', () => { 10 | const options = { 11 | maxValue: 100, 12 | minValue: 0, 13 | meterLabel: "Test Meter", 14 | id: 1, 15 | optimumValue: 80, 16 | lowValue: 20, 17 | highValue: 85, 18 | } 19 | 20 | let meter, label, meters, meterDiv 21 | 22 | beforeEach(() => { 23 | const {getByTestId, getByText} = render(Meter, {options: options, value: 60}) 24 | meters = document.getElementsByTagName('meter') 25 | meter = getByTestId('meter-test') 26 | label = getByText('Test Meter: 60%') 27 | }) 28 | 29 | it('should have two children, a label and meter', () => { 30 | expect(label).toBeInTheDocument() 31 | expect(label.nextElementSibling).toBeInTheDocument() 32 | expect(label.nextElementSibling).toBe(meter) 33 | }) 34 | 35 | it('should have a role set to meter', () => { 36 | expect(meters.length).toEqual(1) 37 | }) 38 | 39 | it('should have a meter with accessible attributes', () => { 40 | expect(meter).toHaveAttribute('aria-valuenow') 41 | expect(meter.getAttribute('aria-valuenow')).toEqual('60') 42 | expect(meter).toHaveAttribute('aria-valuemax') 43 | expect(meter.getAttribute('aria-valuemax')).toEqual(options.maxValue.toString()) 44 | expect(meter).toHaveAttribute('aria-valuemin') 45 | expect(meter.getAttribute('aria-valuemin')).toEqual(options.minValue.toString()) 46 | expect(meter).toHaveAttribute('aria-labelledby') 47 | expect(meter.getAttribute('aria-labelledby')).toEqual('meter-label-1') 48 | expect(meter).toHaveAttribute('aria-valuetext') 49 | expect(meter.getAttribute('aria-valuetext')).toEqual('') 50 | }) 51 | 52 | it('should have a meter with attributes defined by props', () => { 53 | expect(meter).toHaveAttribute('id') 54 | expect(meter.getAttribute('id')).toEqual('meter-1') 55 | expect(meter).toHaveAttribute('min') 56 | expect(meter.getAttribute('min')).toEqual(options.minValue.toString()) 57 | expect(meter).toHaveAttribute('max') 58 | expect(meter.getAttribute('max')).toEqual(options.maxValue.toString()) 59 | expect(meter).toHaveAttribute('low') 60 | expect(meter.getAttribute('low')).toEqual(options.lowValue.toString()) 61 | expect(meter).toHaveAttribute('high') 62 | expect(meter.getAttribute('high')).toEqual(options.highValue.toString()) 63 | expect(meter).toHaveAttribute('optimum') 64 | expect(meter.getAttribute('optimum')).toEqual(options.optimumValue.toString()) 65 | expect(meter).toHaveAttribute('value') 66 | expect(meter.getAttribute('value')).toEqual('60') 67 | expect(meter).toHaveAttribute('style') 68 | expect(meter.getAttribute('style')).toEqual('') 69 | }) 70 | 71 | it('should have a label with accessible attributes', () => { 72 | expect(label).toHaveAttribute('for') 73 | expect(label.getAttribute('for')).toEqual('meter-1') 74 | expect(label).toHaveAttribute('id') 75 | expect(label.getAttribute('id')).toEqual('meter-label-1') 76 | expect(label).toHaveAttribute('style') 77 | expect(label.getAttribute('style')).toEqual('') 78 | }) 79 | 80 | }) -------------------------------------------------------------------------------- /src/__tests__/NavBar.spec.js: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | import { render } from '@testing-library/svelte'; 3 | import userEvent from '@testing-library/user-event'; 4 | import NavBar from '../lib/NavBar.svelte'; 5 | 6 | let user; 7 | let header; 8 | let subheading; 9 | let option1; 10 | let option2; 11 | 12 | const options = { 13 | id: 'testnav', 14 | header: 'Menu', 15 | contentInfo: [ 16 | { 17 | subheading: 'Components', 18 | options: ['Button', 'Accordion'], 19 | links: ['../routes/pages/button.svelte', '../routes/pages/accordion.svelte'] 20 | } 21 | ], 22 | imgSrc: '../images/svve11-logo-white-transparent-cropped.png', 23 | imgClass: 'navbar-logo', 24 | imgAlt: 'company logo' 25 | }; 26 | 27 | // before each test runs run, 28 | beforeEach(() => { 29 | // set up a user to dispatch events 30 | user = userEvent.setup(); 31 | 32 | // render a Button for testing 33 | const { getByText } = render(NavBar, { options }); 34 | //header = getByText('Menu'); 35 | console.log(document.body); 36 | subheading = getByText('Components'); 37 | option1 = getByText('Button'); 38 | option2 = getByText('Accordion'); 39 | }); 40 | 41 | describe('Running accessible NavBar tests', () => { 42 | describe('Keyboard interaction tests', () => { 43 | test('Can go down list of options using tab', async () => { 44 | await user.tab(); 45 | // console.log('current active element:', document.activeElement); 46 | expect(document.activeElement).toBe(option1); 47 | await user.tab(); 48 | expect(document.activeElement).toBe(option2); 49 | }); 50 | test('Each option is paired with the appropriate link', async () => { 51 | await user.tab(); 52 | const optionA = document.activeElement; 53 | expect(optionA).toHaveAttribute('href', '../routes/pages/button.svelte'); 54 | 55 | await user.tab(); 56 | const optionB = document.activeElement; 57 | expect(optionB).toHaveAttribute('href', '../routes/pages/accordion.svelte'); 58 | }); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /src/__tests__/Radio.spec.js: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | import { render } from '@testing-library/svelte'; 3 | import userEvent from '@testing-library/user-event'; 4 | import RadioButton from '../pending/RadioButton.svelte'; 5 | 6 | const options = { 7 | radioButtonLabel: 'Radio Button', 8 | id: 'first', 9 | checked: false, 10 | radioButtonStyle: 'styling for buton', 11 | radioButtonLabelStyle: 'styling for label', 12 | name: 'groupOne', 13 | value: 'group' 14 | }; 15 | 16 | let user; 17 | // beforeEach(() => { 18 | user = userEvent.setup(); 19 | const { component } = render(RadioButton, { options }); 20 | let radioButton = document.getElementById('first'); 21 | // }); 22 | 23 | describe('Accessible testing for radioButton', () => { 24 | test('checking if aria-label is being used', () => { 25 | expect(radioButton).toHaveAttribute('aria-label'); 26 | }); 27 | 28 | test('checking if id is being used', () => { 29 | expect(radioButton).toHaveAttribute('id'); 30 | }); 31 | 32 | test('checking if type is being defined', () => { 33 | expect(radioButton).toHaveAttribute('type'); 34 | }); 35 | 36 | test('checking if radio-button unselected by default', () => { 37 | expect(radioButton.getAttribute('checked')).toBeFalsy(); 38 | }); 39 | 40 | test('checking if the type is being defined as a radio button', () => { 41 | expect(radioButton.getAttribute('type')).toEqual('radio'); 42 | }); 43 | 44 | test('checking if name is being defined', () => { 45 | expect(radioButton).toHaveAttribute('name'); 46 | }); 47 | 48 | }); 49 | 50 | describe('Accessing by keyboard functionality', () => { 51 | test('It can be focused by pressing tab', async () => { 52 | await user.tab(); 53 | // expect(document.activeElement).toHaveValue('group'); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /src/__tests__/Table.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import '@testing-library/jest-dom'; 3 | import { render } from '@testing-library/svelte'; 4 | import userEvent from '@testing-library/user-event'; 5 | 6 | import Table from './../lib/Table.svelte'; 7 | 8 | let user; 9 | let table; 10 | 11 | const options = { 12 | id: 'test-table', 13 | ariaLabel: 'test', 14 | ariaDescription: 'Table Component for Testing', 15 | columnNames: ['Name', 'Age', 'Favorite Color'], 16 | rowsContent: [ 17 | ['Nurbek', '19', 'White'], 18 | ['Paul', '26', 'Red'], 19 | ['Tim', '29', 'Blue'], 20 | ['Simon', '26', 'Green'] 21 | ], 22 | styles: { 23 | overallStyles: 'background-color: powderblue', 24 | titleStyles: 'text-align: left;', 25 | headersRowStyles: 'background-color: grey', 26 | generalRowStyles: 'font-weight: lighter', 27 | oddRowStyles: 'background-color: white', 28 | evenRowStyles: 'background-color: lightgrey' 29 | } 30 | }; 31 | 32 | beforeEach(() => { 33 | // set up a user to dispatch events 34 | user = userEvent.setup(); 35 | 36 | // render a Table for testing 37 | const { component } = render(Table, { options }); 38 | table = document.getElementById('test-table'); 39 | }); 40 | 41 | describe('Running accessible Table tests', () => { 42 | describe('WAI-ARIA Roles, States, Properties tests', () => { 43 | test('It has a role table', () => { 44 | expect(table); 45 | }); 46 | 47 | test('It has an accessible label', () => { 48 | expect(table).toHaveAttribute('aria-label'); 49 | expect(table).toHaveAccessibleName('test'); 50 | }); 51 | 52 | test('It has an accessible description', () => { 53 | expect(table).toHaveAccessibleDescription('Table Component for Testing'); 54 | }); 55 | }); 56 | 57 | describe('a11y checklist tests', () => { 58 | test('The table should have a caption element', () => { 59 | const caption = document.getElementById('test_table_desc'); 60 | console.log('table caption:', caption); 61 | expect(table).toContainElement(caption); 62 | }); 63 | 64 | test('Its caption element should provide a title for the table', () => { 65 | const caption = document.getElementById('test_table_desc'); 66 | expect(caption.textContent).toBe('Table Component for Testing'); 67 | }); 68 | }); 69 | 70 | describe('Keyboard interaction tests', () => { 71 | test('It can be focused by pressing tab', async () => { 72 | // press tab 73 | await user.tab(); 74 | expect(document.activeElement).toHaveAccessibleName('test'); 75 | }); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /src/__tests__/TextInput.spec.js: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | import TextInput from "../lib/TextInput.svelte"; 3 | import { render } from "@testing-library/svelte"; 4 | import userEvent from '@testing-library/user-event'; 5 | 6 | let user; 7 | let input; 8 | let label; 9 | 10 | const options = { 11 | label: "This is a test", 12 | placeholder: "Test", 13 | id: "testInputText", 14 | type: "text" 15 | } 16 | 17 | beforeEach(() => { 18 | // // set up a user to dispatch events 19 | user = userEvent.setup(); 20 | 21 | // render a Button for testing 22 | const { component, getByText, getByLabelText } = render(TextInput, { options }); 23 | input = getByLabelText('This is a test'); 24 | label = getByText('This is a test'); 25 | }); 26 | 27 | describe('Running accessible TextInput tests', () => { 28 | describe('Check that all attributes have been passed down properly', () => { 29 | test(' has correct placeholder attribute', () => { 30 | expect(input).toHaveAttribute('placeholder', 'Test'); 31 | }); 32 | 33 | test(' has correct type attribute', () => { 34 | expect(input).toHaveAttribute('type', 'text'); 35 | }); 36 | 37 | test(' and