a11y_agent 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,42 +0,0 @@
1
- {
2
- "name": "todomvc-react",
3
- "version": "1.0.0",
4
- "description": "A TodoMVC written in React.",
5
- "private": true,
6
- "engines": {
7
- "node": ">=18.13.0",
8
- "npm": ">=8.19.3"
9
- },
10
- "scripts": {
11
- "build": "webpack --config webpack.prod.js",
12
- "dev": "webpack serve --open --config webpack.dev.js",
13
- "serve": "http-server ./dist -p 7002 -c-1 --cors",
14
- "test": "jest"
15
- },
16
- "devDependencies": {
17
- "@babel/core": "^7.21.0",
18
- "@babel/preset-env": "^7.20.2",
19
- "@babel/preset-react": "^7.18.6",
20
- "babel-loader": "^9.1.2",
21
- "copy-webpack-plugin": "^12.0.2",
22
- "css-loader": "^6.7.3",
23
- "css-minimizer-webpack-plugin": "^4.2.2",
24
- "eslint-plugin-react": "^7.32.2",
25
- "html-webpack-plugin": "^5.5.0",
26
- "http-server": "^14.1.1",
27
- "mini-css-extract-plugin": "^2.7.2",
28
- "style-loader": "^3.3.1",
29
- "webpack": "^5.75.0",
30
- "webpack-cli": "^5.0.1",
31
- "webpack-dev-server": "^4.11.1",
32
- "webpack-merge": "^5.8.0"
33
- },
34
- "dependencies": {
35
- "classnames": "^2.2.5",
36
- "react": "^17.0.2",
37
- "react-dom": "^17.0.2",
38
- "react-router-dom": "^6.8.2",
39
- "todomvc-app-css": "^2.4.2",
40
- "todomvc-common": "^1.0.5"
41
- }
42
- }
@@ -1,19 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en" data-framework="react">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="description" content="A TodoMVC written in React." />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <meta http-equiv="X-UA-Compatible" content="ie=edge" />
8
- <title>TodoMVC: React</title>
9
- </head>
10
- <body>
11
- <section class="todoapp" id="root"></section>
12
- <footer class="info">
13
- <p>Double-click to edit a todo</p>
14
- <p>Created by the TodoMVC Team</p>
15
- <p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
16
- </footer>
17
- <script src="./base.js"></script>
18
- </body>
19
- </html>
@@ -1,42 +0,0 @@
1
- # TodoMVC: React
2
-
3
- ## Description
4
-
5
- This application uses React 17.0.2 to implement a todo application.
6
-
7
- - [React](https://reactjs.org/) is a JavaScript library for creating user interfaces.
8
-
9
- ## Implementation details
10
-
11
- React focuses mainly on providing composable user interfaces to enable developers to build an appealing website or web app. React does not force the user to utilize a particular design pattern, but it does provide useful hooks to implement an MVC pattern, if desired.
12
-
13
- React:\
14
- Model: Todo reducer (reducer.js)\
15
- View: React ui components\
16
- Controller: App component + useReducer hook
17
-
18
- MVC:\
19
- Model: Maintains the data and behavior of an application\
20
- View: Displays the model in the ui\
21
- Controller: Serves as an interface between view & model components
22
-
23
- ## Build steps
24
-
25
- To build the static files, this application utilizes webpack. It minifies and optimizes output files and copies all necessary files to a `dist` folder.
26
-
27
- ## Requirements
28
-
29
- The only requirement is an installation of Node, to be able to install dependencies and run scripts to serve a local server.
30
-
31
- ```
32
- * Node (min version: 18.13.0)
33
- * NPM (min version: 8.19.3)
34
- ```
35
-
36
- ## Local preview
37
-
38
- ```
39
- terminal:
40
- 1. npm install
41
- 2. npm run serve
42
- ```
@@ -1,16 +0,0 @@
1
- import React from "react";
2
- import { render } from "react-dom";
3
- import { HashRouter, Route, Routes } from "react-router-dom";
4
-
5
- import { App } from "./todo/app";
6
- import "todomvc-app-css/index.css";
7
- import "todomvc-common/base.css";
8
-
9
- render(
10
- <HashRouter>
11
- <Routes>
12
- <Route path="*" element={<App />} />
13
- </Routes>
14
- </HashRouter>,
15
- document.getElementById("root")
16
- );
@@ -1,87 +0,0 @@
1
- .toggle-all {
2
- width: 40px !important;
3
- height: 60px !important;
4
- right: auto !important;
5
- }
6
-
7
- .toggle-all-label {
8
- pointer-events: none;
9
- }
10
-
11
- .todo-list {
12
- margin: 0;
13
- padding: 0;
14
- }
15
-
16
- .todo-item {
17
- border-bottom: 1px solid #ededed;
18
- font-size: 24px;
19
- position: relative;
20
- }
21
-
22
- .header-title {
23
- color: #b83f45;
24
- font-size: 80px;
25
- font-weight: 200;
26
- position: absolute;
27
- text-align: center;
28
- -webkit-text-rendering: optimizeLegibility;
29
- -moz-text-rendering: optimizeLegibility;
30
- text-rendering: optimizeLegibility;
31
- top: -100px;
32
- width: 100%;
33
- }
34
-
35
- .filter-item {
36
- display: inline-block;
37
- margin: 0 5px;
38
- }
39
-
40
- .filter-link {
41
- border: 1px solid transparent;
42
- border-radius: 3px;
43
- color: inherit;
44
- margin: 3px;
45
- padding: 3px 7px;
46
- cursor: pointer;
47
- }
48
-
49
- .filter-link:hover {
50
- border-color: #db7676;
51
- }
52
-
53
- .filter-link.selected {
54
- border-color: #ce4646;
55
- }
56
-
57
- .checkbox-wrapper {
58
- position: relative;
59
- width: 40px;
60
- height: 40px;
61
- display: inline-block;
62
- }
63
-
64
- .checkbox {
65
- width: 100%;
66
- height: 100%;
67
- margin: 10px 0 0 15px;
68
- cursor: pointer;
69
- background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23949494%22%20stroke-width%3D%223%22/%3E%3C/svg%3E");
70
- }
71
-
72
- .checkbox.checked {
73
- background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%2359A193%22%20stroke-width%3D%223%22%2F%3E%3Cpath%20fill%3D%22%233EA390%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22%2F%3E%3C%2Fsvg%3E");
74
- }
75
-
76
- .todo-text {
77
- display: inline-block;
78
- padding: 15px 15px 15px 60px;
79
- line-height: 1.2;
80
- transition: color .4s;
81
- color: #484848;
82
- }
83
-
84
- .clear-completed.disabled {
85
- opacity: 0.5;
86
- cursor: not-allowed;
87
- }
@@ -1,20 +0,0 @@
1
- import { useReducer } from "react";
2
- import { Header } from "./components/header";
3
- import { Main } from "./components/main";
4
- import { Footer } from "./components/footer";
5
-
6
- import { todoReducer } from "./reducer";
7
-
8
- import "./app.css";
9
-
10
- export function App() {
11
- const [todos, dispatch] = useReducer(todoReducer, []);
12
-
13
- return (
14
- <>
15
- <Header dispatch={dispatch} />
16
- <Main todos={todos} dispatch={dispatch} />
17
- <Footer todos={todos} dispatch={dispatch} />
18
- </>
19
- );
20
- }
@@ -1,46 +0,0 @@
1
- import { useCallback, useMemo } from "react";
2
- import { useLocation } from "react-router-dom";
3
- import classnames from "classnames";
4
-
5
- import { REMOVE_COMPLETED_ITEMS } from "../constants";
6
-
7
- export function Footer({ todos, dispatch }) {
8
- const { pathname: route } = useLocation();
9
-
10
- const activeTodos = useMemo(() => todos.filter((todo) => !todo.completed), [todos]);
11
-
12
- const removeCompleted = useCallback(() => dispatch({ type: REMOVE_COMPLETED_ITEMS }), [dispatch]);
13
-
14
- // prettier-ignore
15
- if (todos.length === 0)
16
- return null;
17
-
18
- return (
19
- <div className="footer" data-testid="footer">
20
- <div className="todo-count">{`${activeTodos.length} ${activeTodos.length === 1 ? "item" : "items"} left!`}</div>
21
- <div className="filters" data-testid="footer-navigation">
22
- <div className="filter-item">
23
- <div className={classnames("filter-link", { selected: route === "/" })} onClick={() => window.location.hash = "/"}>
24
- All
25
- </div>
26
- </div>
27
- <div className="filter-item">
28
- <div className={classnames("filter-link", { selected: route === "/active" })} onClick={() => window.location.hash = "/active"}>
29
- Active
30
- </div>
31
- </div>
32
- <div className="filter-item">
33
- <div className={classnames("filter-link", { selected: route === "/completed" })} onClick={() => window.location.hash = "/completed"}>
34
- Completed
35
- </div>
36
- </div>
37
- </div>
38
- <div
39
- className={classnames("clear-completed", { disabled: activeTodos.length === todos.length })}
40
- onClick={activeTodos.length === todos.length ? null : removeCompleted}
41
- >
42
- Clear completed
43
- </div>
44
- </div>
45
- );
46
- }
@@ -1,15 +0,0 @@
1
- import { useCallback } from "react";
2
- import { Input } from "./input";
3
-
4
- import { ADD_ITEM } from "../constants";
5
-
6
- export function Header({ dispatch }) {
7
- const addItem = useCallback((title) => dispatch({ type: ADD_ITEM, payload: { title } }), [dispatch]);
8
-
9
- return (
10
- <div className="header" data-testid="header">
11
- <div className="header-title">todos</div>
12
- <Input onSubmit={addItem} label="New Todo Input" placeholder="What needs to be done?" />
13
- </div>
14
- );
15
- }
@@ -1,46 +0,0 @@
1
- import { useCallback } from "react";
2
-
3
- const sanitize = (string) => {
4
- const map = {
5
- "&": "&amp;",
6
- "<": "&lt;",
7
- ">": "&gt;",
8
- '"': "&quot;",
9
- "'": "&#x27;",
10
- "/": "&#x2F;",
11
- };
12
- const reg = /[&<>"'/]/gi;
13
- return string.replace(reg, (match) => map[match]);
14
- };
15
-
16
- const hasValidMin = (value, min) => {
17
- return value.length >= min;
18
- };
19
-
20
- export function Input({ onSubmit, placeholder, label, defaultValue, onBlur }) {
21
- const handleBlur = useCallback(() => {
22
- if (onBlur)
23
- onBlur();
24
- }, [onBlur]);
25
-
26
- const handleKeyDown = useCallback(
27
- (e) => {
28
- if (e.key === "Enter") {
29
- const value = e.target.value.trim();
30
-
31
- if (!hasValidMin(value, 2))
32
- return;
33
-
34
- onSubmit(sanitize(value));
35
- e.target.value = "";
36
- }
37
- },
38
- [onSubmit]
39
- );
40
-
41
- return (
42
- <div className="input-container">
43
- <input className="new-todo" id="todo-input" type="text" data-testid="text-input" autoFocus placeholder={placeholder} defaultValue={defaultValue} onBlur={handleBlur} onKeyDown={handleKeyDown} />
44
- </div>
45
- );
46
- }
@@ -1,55 +0,0 @@
1
- import { memo, useState, useCallback } from "react";
2
- import classnames from "classnames";
3
-
4
- import { Input } from "./input";
5
-
6
- import { TOGGLE_ITEM, REMOVE_ITEM, UPDATE_ITEM } from "../constants";
7
-
8
- export const Item = memo(function Item({ todo, dispatch, index }) {
9
- const [isWritable, setIsWritable] = useState(false);
10
- const { title, completed, id } = todo;
11
-
12
- const toggleItem = useCallback(() => dispatch({ type: TOGGLE_ITEM, payload: { id } }), [dispatch]);
13
- const removeItem = useCallback(() => dispatch({ type: REMOVE_ITEM, payload: { id } }), [dispatch]);
14
- const updateItem = useCallback((id, title) => dispatch({ type: UPDATE_ITEM, payload: { id, title } }), [dispatch]);
15
-
16
- const handleDoubleClick = useCallback(() => {
17
- setIsWritable(true);
18
- }, []);
19
-
20
- const handleBlur = useCallback(() => {
21
- setIsWritable(false);
22
- }, []);
23
-
24
- const handleUpdate = useCallback(
25
- (title) => {
26
- if (title.length === 0)
27
- removeItem(id);
28
- else
29
- updateItem(id, title);
30
-
31
- setIsWritable(false);
32
- },
33
- [id, removeItem, updateItem]
34
- );
35
-
36
- return (
37
- <div className={classnames("todo-item", { completed: todo.completed })} data-testid="todo-item">
38
- <div className="view">
39
- {isWritable ? (
40
- <Input onSubmit={handleUpdate} label="Edit Todo Input" defaultValue={title} onBlur={handleBlur} />
41
- ) : (
42
- <>
43
- <div className="toggle checkbox-wrapper" data-testid="todo-item-toggle">
44
- <div className={classnames("checkbox", { checked: completed })} onClick={toggleItem}></div>
45
- </div>
46
- <div className="todo-text" data-testid="todo-item-label" onDoubleClick={handleDoubleClick}>
47
- {title}
48
- </div>
49
- <div className="destroy" data-testid="todo-item-button" onClick={removeItem} role="button"></div>
50
- </>
51
- )}
52
- </div>
53
- </div>
54
- );
55
- });
@@ -1,45 +0,0 @@
1
- import { useMemo, useCallback } from "react";
2
- import { useLocation } from "react-router-dom";
3
-
4
- import { Item } from "./item";
5
- import classnames from "classnames";
6
-
7
- import { TOGGLE_ALL } from "../constants";
8
-
9
- export function Main({ todos, dispatch }) {
10
- const { pathname: route } = useLocation();
11
-
12
- const visibleTodos = useMemo(
13
- () =>
14
- todos.filter((todo) => {
15
- if (route === "/active")
16
- return !todo.completed;
17
-
18
- if (route === "/completed")
19
- return todo.completed;
20
-
21
- return todo;
22
- }),
23
- [todos, route]
24
- );
25
-
26
- const toggleAll = useCallback((e) => dispatch({ type: TOGGLE_ALL, payload: { completed: e.target.checked } }), [dispatch]);
27
-
28
- return (
29
- <main className="main" data-testid="main">
30
- {visibleTodos.length > 0 ? (
31
- <div className="toggle-all-container">
32
- <input className="toggle-all" type="checkbox" id="toggle-all" data-testid="toggle-all" checked={visibleTodos.every((todo) => todo.completed)} onChange={toggleAll} />
33
- <label className="toggle-all-label" htmlFor="toggle-all">
34
- Toggle All Input
35
- </label>
36
- </div>
37
- ) : null}
38
- <div className={classnames("todo-list")} data-testid="todo-list">
39
- {visibleTodos.map((todo, index) => (
40
- <Item todo={todo} key={todo.id} dispatch={dispatch} index={index} />
41
- ))}
42
- </div>
43
- </main>
44
- );
45
- }
@@ -1,7 +0,0 @@
1
- export const ADD_ITEM = "ADD_ITEM";
2
- export const UPDATE_ITEM = "UPDATE_ITEM";
3
- export const REMOVE_ITEM = "REMOVE_ITEM";
4
- export const TOGGLE_ITEM = "TOGGLE_ITEM";
5
- export const REMOVE_ALL_ITEMS = "REMOVE_ALL_ITEMS";
6
- export const TOGGLE_ALL = "TOGGLE_ALL";
7
- export const REMOVE_COMPLETED_ITEMS = "REMOVE_COMPLETED_ITEMS";
@@ -1,64 +0,0 @@
1
- import { ADD_ITEM, UPDATE_ITEM, REMOVE_ITEM, TOGGLE_ITEM, REMOVE_ALL_ITEMS, TOGGLE_ALL, REMOVE_COMPLETED_ITEMS } from "./constants";
2
-
3
- /* Borrowed from https://github.com/ai/nanoid/blob/3.0.2/non-secure/index.js
4
-
5
- The MIT License (MIT)
6
-
7
- Copyright 2017 Andrey Sitnik <andrey@sitnik.ru>
8
-
9
- Permission is hereby granted, free of charge, to any person obtaining a copy of
10
- this software and associated documentation files (the "Software"), to deal in
11
- the Software without restriction, including without limitation the rights to
12
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13
- the Software, and to permit persons to whom the Software is furnished to do so,
14
- subject to the following conditions:
15
-
16
- The above copyright notice and this permission notice shall be included in all
17
- copies or substantial portions of the Software.
18
-
19
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
21
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
25
-
26
- // This alphabet uses `A-Za-z0-9_-` symbols.
27
- // The order of characters is optimized for better gzip and brotli compression.
28
- // References to the same file (works both for gzip and brotli):
29
- // `'use`, `andom`, and `rict'`
30
- // References to the brotli default dictionary:
31
- // `-26T`, `1983`, `40px`, `75px`, `bush`, `jack`, `mind`, `very`, and `wolf`
32
- let urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
33
-
34
- function nanoid(size = 21) {
35
- let id = "";
36
- // A compact alternative for `for (var i = 0; i < step; i++)`.
37
- let i = size;
38
- while (i--) {
39
- // `| 0` is more compact and faster than `Math.floor()`.
40
- id += urlAlphabet[(Math.random() * 64) | 0];
41
- }
42
- return id;
43
- }
44
-
45
- export const todoReducer = (state, action) => {
46
- switch (action.type) {
47
- case ADD_ITEM:
48
- return state.concat({ id: nanoid(), title: action.payload.title, completed: false });
49
- case UPDATE_ITEM:
50
- return state.map((todo) => (todo.id === action.payload.id ? { ...todo, title: action.payload.title } : todo));
51
- case REMOVE_ITEM:
52
- return state.filter((todo) => todo.id !== action.payload.id);
53
- case TOGGLE_ITEM:
54
- return state.map((todo) => (todo.id === action.payload.id ? { ...todo, completed: !todo.completed } : todo));
55
- case REMOVE_ALL_ITEMS:
56
- return [];
57
- case TOGGLE_ALL:
58
- return state.map((todo) => (todo.completed !== action.payload.completed ? { ...todo, completed: action.payload.completed } : todo));
59
- case REMOVE_COMPLETED_ITEMS:
60
- return state.filter((todo) => !todo.completed);
61
- }
62
-
63
- throw Error(`Unknown action: ${action.type}`);
64
- };
@@ -1,43 +0,0 @@
1
- const HtmlWebpackPlugin = require("html-webpack-plugin");
2
- const path = require("path");
3
-
4
- module.exports = {
5
- entry: {
6
- app: path.resolve(__dirname, "src", "index.js"),
7
- },
8
- plugins: [
9
- new HtmlWebpackPlugin({
10
- title: "TodoMVC: React",
11
- template: path.resolve(__dirname, "public", "index.html"),
12
- }),
13
- ],
14
- output: {
15
- filename: "[name].bundle.js",
16
- path: path.resolve(__dirname, "dist"),
17
- clean: true,
18
- },
19
- resolve: {
20
- extensions: [".js", ".jsx"],
21
- },
22
- module: {
23
- rules: [
24
- {
25
- test: /\.(js|jsx)$/,
26
- exclude: /node_modules/,
27
- use: {
28
- loader: "babel-loader",
29
- options: {
30
- presets: [
31
- ["@babel/preset-env", { targets: "defaults" }],
32
- ["@babel/preset-react", { runtime: "automatic" }],
33
- ],
34
- },
35
- },
36
- },
37
- {
38
- test: /\.(png|svg|jpg|jpeg|gif)$/i,
39
- type: "asset/resource",
40
- },
41
- ],
42
- },
43
- };
@@ -1,18 +0,0 @@
1
- const { merge } = require("webpack-merge");
2
- const common = require("./webpack.common.js");
3
-
4
- module.exports = merge(common, {
5
- mode: "development",
6
- devtool: "inline-source-map",
7
- devServer: {
8
- static: "./dist",
9
- },
10
- module: {
11
- rules: [
12
- {
13
- test: /\.css$/i,
14
- use: ["style-loader", "css-loader"],
15
- },
16
- ],
17
- },
18
- });
@@ -1,35 +0,0 @@
1
- const { merge } = require("webpack-merge");
2
- const common = require("./webpack.common.js");
3
-
4
- const MiniCssExtractPlugin = require("mini-css-extract-plugin");
5
- const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
6
- const TerserPlugin = require("terser-webpack-plugin");
7
- const CopyPlugin = require("copy-webpack-plugin");
8
-
9
- module.exports = merge(common, {
10
- mode: "production",
11
- devtool: "source-map",
12
- plugins: [
13
- new MiniCssExtractPlugin({
14
- filename: "[name].css",
15
- chunkFilename: "[id].css",
16
- }),
17
- new CopyPlugin({
18
- patterns: [
19
- { from: "./node_modules/todomvc-common/base.js", to: "base.js" },
20
- ],
21
- }),
22
- ],
23
- module: {
24
- rules: [
25
- {
26
- test: /\.css$/,
27
- use: [MiniCssExtractPlugin.loader, "css-loader"],
28
- },
29
- ],
30
- },
31
- optimization: {
32
- minimize: true,
33
- minimizer: [new CssMinimizerPlugin(), new TerserPlugin()],
34
- },
35
- });