create documentation for this web app ```html <!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chemical Supplies</title>
    <link rel="stylesheet" href="/style.css">
</head>

<body>
    <header class="show-add-new show-refresh show-save">
        <div class="container">
            <div class="header-inner-wrap">
                <h1>Chemical Supplies</h1>
                <div class="actions-container">
                    <button class="btn-mid transparent-overlay" data-action="add-new"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M256 48C141.125 48 48 141.125 48 256s93.125 208 208 208 208-93.125 208-208S370.875 48 256 48zm107 229h-86v86h-42v-86h-86v-42h86v-86h42v86h86v42z"></path></svg></button>
                    <button class="btn-mid transparent-overlay" data-action="edit"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a.996.996 0 0 0 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path></svg></button>
                    <button class="btn-mid transparent-overlay" data-action="movedown"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="m20 12-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"></path></svg></button>
                    <button class="btn-mid transparent-overlay" data-action="moveup"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="m4 12 1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"></path></svg></button>
                    <button class="btn-mid btn-danger transparent-overlay" data-action="delete"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></svg></button>
                    <button class="btn-mid btn-danger transparent-overlay" data-action="refresh"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M17.65 6.35A7.958 7.958 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0 1 12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"></path></svg></button>
                    <button class="btn-mid transparent-overlay" data-action="save"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M17 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"></path></svg></button>
                </div>

                <div class="form-wrap">
                    <div class="form-inner-wrap">
                        <h2>Add New Entry</h2>
                        <form id="form" class="form">
                            <label for="chemical_name">Chemical Name:</label>
                            <input type="text" id="chemical_name" name="chemical_name" required>
                    
                            <label for="vendor">Vendor:</label>
                            <input type="text" id="vendor" name="vendor" required>
                    
                            <label for="density">Density (g/cm³):</label>
                            <input type="text" id="density" name="density" required>
                    
                            <label for="viscosity">Viscosity:</label>
                            <input type="text" id="viscosity" name="viscosity" required>
                    
                            <label for="packaging">Packaging:</label>
                            <select id="packaging" name="packaging" required>
                                <option value="Bottle">Bottle</option>
                                <option value="Bag">Bag</option>
                                <option value="Drum">Drum</option>
                                <option value="Barrel">Barrel</option>
                                <option value="Tank">Tank</option>
                                <option value="Box">Box</option>
                                <option value="Sack">Sack</option>
                                <option value="Can">Can</option>
                                <option value="Bulk">Bulk</option>
                            </select>
                    
                            <label for="pack_size">Pack Size:</label>
                            <input type="number" id="pack_size" name="pack_size" min="1" required>
                    
                            <label for="unit">Unit:</label>
                            <select id="unit" name="unit" required>
                                <option value="mL">mL</option>
                                <option value="L">L</option>
                                <option value="g">g</option>
                                <option value="kg">kg</option>
                            </select>
                    
                            <label for="quantity">Quantity:</label>
                            <input type="number" id="quantity" name="quantity" min="1" required>
                            <div>
                                <button type="submit">Add</button>&nbsp;<button type="reset" onclick="toggleForm();">Cancel</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </header>
    <main>
        <div class="container">
            <div class="table-wrap">
                <table id="table">
                    <thead>
                        <tr>
                            <th class="select-box-all">&#10004;</th>
                            <th></th>
                            <th>
                                <div class="th-content-wrap">
                                    <div class="th-content-top">
                                        <span>Chemical Name</span><button class="btn-small transparent-overlay" data-sort-type="string" data-sort-direction="asc" data-sort-property="chemical_name"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l128 128c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H32c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9l128-128zm0 429.3l-128-128c-9.2-9.2-11.9-22.9-6.9-34.9s16.6-19.8 29.6-19.8H288c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9l-128 128c-12.5 12.5-32.8 12.5-45.3 0z"></path></svg></button>
                                    </div>
                                </div>
                            </th>
                            <th>
                                <div class="th-content-wrap">
                                    <div class="th-content-top">
                                        <span>Vendor</span><button class="btn-small transparent-overlay" data-sort-type="string" data-sort-direction="asc" data-sort-property="vendor"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l128 128c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H32c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9l128-128zm0 429.3l-128-128c-9.2-9.2-11.9-22.9-6.9-34.9s16.6-19.8 29.6-19.8H288c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9l-128 128c-12.5 12.5-32.8 12.5-45.3 0z"></path></svg></button>
                                    </div>
                                </div>
                            </th>
                            <th>
                                <div class="th-content-wrap">
                                    <div class="th-content-top">
                                        <span>Density</span><button class="btn-small transparent-overlay" data-sort-type="number" data-sort-direction="asc" data-sort-property="density"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l128 128c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H32c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9l128-128zm0 429.3l-128-128c-9.2-9.2-11.9-22.9-6.9-34.9s16.6-19.8 29.6-19.8H288c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9l-128 128c-12.5 12.5-32.8 12.5-45.3 0z"></path></svg></button>
                                    </div>
                                    <div class="th-content-bottom">
                                        <span class="unit">g&sol;m<sup>3</sup></span>
                                    </div>
                                </div>
                            </th>
                            <th>
                                <div class="th-content-wrap">
                                    <div class="th-content-top">
                                        <span>Viscosity</span><button class="btn-small transparent-overlay" data-sort-type="number" data-sort-direction="asc" data-sort-property="viscosity"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l128 128c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H32c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9l128-128zm0 429.3l-128-128c-9.2-9.2-11.9-22.9-6.9-34.9s16.6-19.8 29.6-19.8H288c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9l-128 128c-12.5 12.5-32.8 12.5-45.3 0z"></path></svg></button>
                                    </div>
                                    <div class="th-content-bottom">
                                        <span class="unit">m<sup>2</sup>&sol;s</span>
                                    </div>
                                </div>
                            </th>
                            <th>
                                <div class="th-content-wrap">
                                    <div class="th-content-top">
                                        <span>Packaging</span><button class="btn-small transparent-overlay" data-sort-type="string" data-sort-direction="asc" data-sort-property="packaging"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l128 128c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H32c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9l128-128zm0 429.3l-128-128c-9.2-9.2-11.9-22.9-6.9-34.9s16.6-19.8 29.6-19.8H288c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9l-128 128c-12.5 12.5-32.8 12.5-45.3 0z"></path></svg></button>
                                    </div>
                                </div>
                            </th>
                            <th>
                                <div class="th-content-wrap">
                                    <div class="th-content-top">
                                        <span>Pack Size</span><button class="btn-small transparent-overlay" data-sort-type="number" data-sort-direction="asc" data-sort-property="pack_size"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l128 128c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H32c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9l128-128zm0 429.3l-128-128c-9.2-9.2-11.9-22.9-6.9-34.9s16.6-19.8 29.6-19.8H288c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9l-128 128c-12.5 12.5-32.8 12.5-45.3 0z"></path></svg></button>
                                    </div>
                                </div>
                            </th>
                            <th>
                                <div class="th-content-wrap">
                                    <div class="th-content-top">
                                        <span>Unit</span><button class="btn-small transparent-overlay" data-sort-type="string" data-sort-direction="asc" data-sort-property="unit"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l128 128c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H32c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9l128-128zm0 429.3l-128-128c-9.2-9.2-11.9-22.9-6.9-34.9s16.6-19.8 29.6-19.8H288c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9l-128 128c-12.5 12.5-32.8 12.5-45.3 0z"></path></svg></button>
                                    </div>
                                </div>
                            </th>
                            <th>
                                <div class="th-content-wrap">
                                    <div class="th-content-top">
                                        <span>Quantity</span><button class="btn-small transparent-overlay" data-sort-type="number" data-sort-direction="asc" data-sort-property="quantity"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l128 128c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H32c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9l128-128zm0 429.3l-128-128c-9.2-9.2-11.9-22.9-6.9-34.9s16.6-19.8 29.6-19.8H288c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9l-128 128c-12.5 12.5-32.8 12.5-45.3 0z"></path></svg></button>
                                    </div>
                                </div>
                            </th>
                        </tr>
                    </thead>
                </table>
            </div>
            
        </div>
    </main>
    <script src="/script.js"></script>
</body>

</html>``` ```css :root{
    --blue:#0032C8;
    --blue-hover:#0039e6;
    --red:#CB4113;
    --white:#ffffff;
    --gray-light:#DBDBD1;
    --gray-mid:#B9B9B4;
    --spacing-small:4px;
    --spacing-medium:8px;
    --spacing-large:12px;
    --spacing-xlarge:16px;
    --spacing-xxlarge:24px
}

/* Reset */
a,a:focus,button:focus,img{outline:0}
*{margin:0;padding:0;box-sizing:border-box;word-wrap:break-word;word-break:break-word}
:after,:before{box-sizing:border-box}
a{text-decoration:none;color:inherit}
a:hover{cursor:pointer}
a:focus{box-shadow:none}
img{border:0;vertical-align:middle}
ul{list-style:none}
b,h1,h2,h3,h4,h5,h6,strong{font-weight:700}
button{all:unset;cursor:pointer;display:inline-block}
input:focus,input:required,textarea:focus,textarea:required{outline:0;box-shadow:none}
input,select,textarea{border:0;border-radius:0}
input,textarea{appearance:none;word-break:break-all;font-family:'Red Hat Display'}
input[type=button],input[type=submit]{appearance:none}
select::-ms-expand{display:none}
textarea{resize:vertical}
input[placeholder]{text-overflow:ellipsis}
::-moz-placeholder{text-overflow:ellipsis}
input:-moz-placeholder{text-overflow:ellipsis}
footer,header,nav{display:block}
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
body{font-family:monospace;background-color:#fafafa;min-height:100svh}

/* Utility Class */
.container{margin-right:auto;margin-left:auto;padding-left:var(--spacing-large);padding-right:var(--spacing-large);max-width:1280px}
.transparent-overlay{position:relative}
.transparent-overlay::before{content:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAAtJREFUGFdjYAACAAAFAAGq1chRAAAAAElFTkSuQmCC);width:100%;height:100%;position:absolute;top:0;left:0;right:0;bottom:0}
button svg{width:100%;height:100%;display:block}
button:active{transform: scale(0.9);}
.btn-mid{width:24px;height:24px}
.btn-small{width:12px;height:12px}

/* Header */
.header-inner-wrap{display:flex;align-items:center;justify-content:space-between;gap:var(--spacing-medium);position:relative;padding:var(--spacing-xlarge) 0}
.actions-container{display:flex;align-items:center;justify-content:center;gap:var(--spacing-small)}
.actions-container button{display:none}
.show-edit button[data-action=edit]{display:initial}
.show-form button[data-action=add-new][data-action=add-new]{transform:rotate(45deg)}
.show-add-new button[data-action=add-new]{display:initial}
.show-movedown button[data-action=movedown]{display:initial}
.show-moveup button[data-action=moveup]{display:initial}
.show-delete button[data-action=delete]{display:initial}
.show-refresh button[data-action=refresh]{display:initial}
.show-save button[data-action=save]{display:initial}

/* Table */
.table-wrap{width:100%;overflow-x:auto;border:1px solid var(--gray-light);background-color:var(--white);margin-bottom:var(--spacing-xlarge)}
table{width:100%;overflow:hidden;min-width:1000px}
td,th{border:1px solid #eee;padding:var(--spacing-small);cursor:default;border-color:transparent}
th{font-weight:400;text-align:left;vertical-align:top}
td{font-weight:500}
thead{position:relative;background-color:#fafaf5}
tr{position:relative}
tr.active{background-color:#e6e8ff}
td:focus,td:focus-visible{border-color:var(--blue);background-color:var(--white);outline:0}
.th-content-top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-small);margin-bottom:var(--spacing-medium)}
.th-content-wrap .unit{color:var(--gray-mid)}
.select-box,.select-box-all{color:#adada8}
.select-box{cursor:pointer}
.active .select-box,.select-box:hover{color:var(--blue)}

/* Form */
.form-wrap{display:none;position:absolute;top:100%;width:100%;right:0;z-index:1}
.show-form .form-wrap{display:block}
.form-inner-wrap{margin-bottom:var(--spacing-large);background-color:var(--white);padding:var(--spacing-large);border:1px solid var(--gray-light)}

.form label{display:block}
.form label,form button{margin:var(--spacing-small) 0 var(--spacing-large)}
.form input,.form select{width:100%;font-family:inherit;padding:var(--spacing-small);margin-bottom:var(--spacing-small);border:1px solid var(--gray-light)}
.form button{background:var(--gray-mid);color:#fff;padding:var(--spacing-small) var(--spacing-xlarge);cursor:pointer;margin:var(--spacing-large) 0 0;}
.form button[type=submit]{background-color:var(--blue)}
.form input:focus{border-color:var(--gray-mid)}
@media screen and (max-width:766px){
    .header-inner-wrap{flex-direction:column;align-items:flex-start;padding:var(--spacing-large) 0}
}

/* Hover and active effects */
@media screen and (pointer:fine){
    button:hover svg path{fill:var(--blue)}
    .btn-danger:hover svg path{fill:var(--red)}
    .form button[type=submit]:hover{background-color:var(--blue-hover)}
}
@media screen and (pointer:coarse){
    button:active svg path{fill:var(--blue)}
    .btn-danger:active svg path{fill:var(--red)}
    .form button[type=submit]:active{background-color:var(--blue-hover)}
}``` ```js const API_URL = '/data.json'
const HEADER = document.querySelector('header')
const ACTIONS_CONTAINER = document.querySelector('.actions-container')
const FORM = document.querySelector('#form')
const TABLE = document.querySelector('#table')
let LAST_SAVED_DATA = []
let UI_DATA = []
let IS_UNSAVED_CHANGES = false
const SELECTED_ROW = { data: null, html: null }

// Changes Observer
const OBSERVER = new MutationObserver(function () {
    IS_UNSAVED_CHANGES = true
})
const OBSERVER_CONFIG = { attributes: false, childList: true, subtree: true }

// Data Functions
async function fetchData(url) {
    try {
        const res = await fetch(url)
        const json = await res.json()
        return json
    } catch (e) {
        console.log(e)
        return []
    }
}

function getUIDataItemIndex(id) {
    return UI_DATA.findIndex(el => el.id === id)
}

function swapArrayItems(arr, index1, index2) {
    const temp = arr[index1]
    arr[index1] = arr[index2]
    arr[index2] = temp
}

function saveData() {
    LAST_SAVED_DATA = JSON.parse(JSON.stringify(UI_DATA))
}

function save() {
    saveData()
    IS_UNSAVED_CHANGES = false
}

function resetSelectionData() {
    SELECTED_ROW.data = null
    SELECTED_ROW.html = null
}

function refreshUIData() {
    UI_DATA = JSON.parse(JSON.stringify(LAST_SAVED_DATA))
}

function sortUIData(property, dir, type) {
    UI_DATA.sort((a, b) => {
        if (type === 'string') {
            if (dir === 'asc') {
                return a[property].localeCompare(b[property], undefined, { numeric: true })
            } else {
                return b[property].localeCompare(a[property], undefined, { numeric: true })
            }
        } else if (type === 'number') {
            if (dir === 'asc') {
                return a[property] - b[property]
            } else {
                return b[property] - a[property]
            }
        } else {
            console.log(`Unsupported type: ${type}`)
            return 0
        }
    })
}

// UI Functions
function createCell(text) {
    const cell = document.createElement('td')
    cell.textContent = text
    return cell
}

function createRow(obj, index) {
    const row = document.createElement('tr')

    const selectBox = createCell(`\u2714`)
    selectBox.classList.add('select-box')
    row.appendChild(selectBox)

    row.dataset.id = obj['id']
    const rowIndexCell = createCell(index)
    row.appendChild(rowIndexCell)

    for (const key in obj) {
        if (key === 'id') {
            continue
        }

        const cell = createCell(obj[key])
        cell.dataset.property = key
        row.appendChild(cell)
    }

    return row
}

function createTableBody(arrayOfObjs) {
    const fragment = document.createDocumentFragment()

    const tbody = document.createElement('tbody')
    fragment.appendChild(tbody)

    arrayOfObjs.forEach((obj, index) => {
        const row = createRow(obj, index + 1)
        tbody.appendChild(row)
    })
    return fragment
}

function selectRow(row) {
    const clickedRow = row

    removeAllModes()

    if (clickedRow.classList.contains('active')) {
        clickedRow.classList.remove('active')

        resetSelectionData()
        idealMode()
    } else {
        const allRows = TABLE.lastElementChild.children
        for (let i = 0; i < allRows.length; i++) {
            allRows[i].classList.remove('active')
        }
        clickedRow.classList.add('active')
        SELECTED_ROW.data = UI_DATA[getUIDataItemIndex(clickedRow.dataset.id)]

        SELECTED_ROW.html = clickedRow
        selectedMode()
    }
}

function deleteRow() {
    if (SELECTED_ROW.data === null || SELECTED_ROW.html === null) {
        return
    }

    let currentRow = SELECTED_ROW.html
    let currentRowIndex = parseInt(currentRow.children[1].textContent)
    while (currentRow) {
        currentRow.children[1].textContent = currentRowIndex - 1
        currentRowIndex++
        currentRow = currentRow.nextElementSibling
    }

    SELECTED_ROW.html.remove()

    const deletedItemDataIndex = getUIDataItemIndex(SELECTED_ROW.data.id)
    UI_DATA.splice(deletedItemDataIndex, 1)

    resetSelectionData()
    removeAllModes()
    idealMode()
}

function moveRowUp() {
    if (SELECTED_ROW.data === null || SELECTED_ROW.html === null) {
        return
    }

    const currentRow = SELECTED_ROW.html
    const previousRow = currentRow.previousElementSibling

    if (previousRow) {
        const previousRowDataId = getUIDataItemIndex(previousRow.dataset.id)
        currentRow.parentNode.insertBefore(currentRow, previousRow)
        swapRowIndex(previousRow, currentRow)
        swapArrayItems(UI_DATA, previousRowDataId, previousRowDataId + 1)
    }
}

function moveRowDown() {
    if (SELECTED_ROW.data === null || SELECTED_ROW.html === null) {
        return
    }

    const currentRow = SELECTED_ROW.html
    const nextRow = currentRow.nextElementSibling

    if (nextRow) {
        const nextItemDataIndex = getUIDataItemIndex(nextRow.dataset.id)
        currentRow.parentNode.insertBefore(nextRow, currentRow)
        swapRowIndex(nextRow, currentRow)
        swapArrayItems(UI_DATA, nextItemDataIndex, nextItemDataIndex - 1)
    }
}

function renderTableUI(data) {
    const html = createTableBody(data)
    TABLE.lastElementChild.remove()
    TABLE.append(html)
}

function refresh() {
    if (IS_UNSAVED_CHANGES) {
        const userConfimation = window.confirm('Contains Unsaved Changes, Refresh?')

        if (!userConfimation) return
    }

    OBSERVER.disconnect()
    refreshUIData()
    renderTableUI(UI_DATA)
    removeAllModes()
    idealMode()
    IS_UNSAVED_CHANGES = false
    OBSERVER.observe(TABLE, OBSERVER_CONFIG)
}

function swapRowIndex(row1, row2) {
    const index1 = row1.children[1].textContent
    const index2 = row2.children[1].textContent

    row1.children[1].textContent = index2
    row2.children[1].textContent = index1
}

function populateForm(data) {
    FORM.chemical_name.value = data.chemical_name
    FORM.vendor.value = data.vendor
    FORM.density.value = data.density
    FORM.viscosity.value = data.viscosity
    FORM.packaging.value = data.packaging
    FORM.pack_size.value = data.pack_size
    FORM.unit.value = data.unit
    FORM.quantity.value = data.quantity
}

function toggleForm() {
    if(HEADER.classList.contains('show-form')){
        delete FORM.dataset.mode
        HEADER.classList.remove('show-form')
    } else {
        HEADER.classList.add('show-form')
    }
}

function edit() {
    FORM.dataset.mode = 'edit'
    toggleForm()
    populateForm(SELECTED_ROW.data)
}

function addNew(){
    FORM.dataset.mode = 'add'
    toggleForm()
}

function removeAllModes() {
    HEADER.classList.remove('show-add-new', 'show-edit', 'show-delete', 'show-moveup', 'show-movedown', 'show-refresh', 'show-save')
}

function idealMode() {
    HEADER.classList.add('show-add-new', 'show-refresh', 'show-save')
}

function selectedMode() {
    HEADER.classList.add('show-edit', 'show-delete', 'show-moveup', 'show-movedown', 'show-refresh', 'show-save')
}

function formMode() {
    HEADER.classList.add('show-add-new')
}

// Init
fetchData(API_URL)
    .then(res => {
        const resStr = JSON.stringify(res)
        LAST_SAVED_DATA = JSON.parse(resStr)
        UI_DATA = JSON.parse(resStr)

        const html = createTableBody(UI_DATA)
        TABLE.append(html)

        TABLE.addEventListener('click', function (e) {

            const clickedArea = e.target

            if (clickedArea.classList.contains('select-box')) {
                selectRow(clickedArea.parentElement)
            }

            if (clickedArea.dataset.sortProperty !== undefined) {
                const direction = clickedArea.dataset.sortDirection
                sortUIData(clickedArea.dataset.sortProperty, direction, clickedArea.dataset.sortType)
                clickedArea.dataset.sortDirection = direction === "asc" ? "dsc" : "asc"

                resetSelectionData()
                renderTableUI(UI_DATA)
            }
        })

        ACTIONS_CONTAINER.addEventListener('click', function (e) {
            const button = e.target.closest('button')
            if (!button) return

            const action = e.target.dataset.action

            switch (action) {
                case 'edit': edit()
                    break

                case 'add-new': addNew()
                    break

                case 'moveup': moveRowUp()
                    break

                case 'movedown': moveRowDown()
                    break

                case 'delete': deleteRow()
                    break

                case 'refresh': refresh()
                    break

                case 'save': save()
                    break

                default: return
            }
        })

        FORM.addEventListener('submit', function (e) {
            e.preventDefault()
            const formData = new FormData(e.target)
            const data = Object.fromEntries(formData.entries())

            if (FORM.dataset.mode === 'edit') {
                const id = SELECTED_ROW.data.id
                UI_DATA[getUIDataItemIndex(id)] = { id: id, ...data }
                FORM.dataset.mode = 'add'
            } else {
                const id = `${new Date().getTime()}`
                UI_DATA.push({ id: id, ...data })
            }

            FORM.reset()
            toggleForm()

            renderTableUI(UI_DATA)
            resetSelectionData()
            removeAllModes()
            idealMode()
        })

        OBSERVER.observe(TABLE, OBSERVER_CONFIG)

    }).catch(function (e) {
        console.log(e)
    })```  ```json [
    {
        "id": "1",
        "chemical_name": "Acetic Acid",
        "vendor": "Chemical Inc.",
        "density": "1.05",
        "viscosity": "0.89",
        "packaging": "Bottle",
        "pack_size": "500",
        "unit": "mL",
        "quantity": "100"
    },
    {
        "id": "2",
        "chemical_name": "Sodium Chloride",
        "vendor": "Salt Co.",
        "density": "2.16",
        "viscosity": "N/A",
        "packaging": "Bag",
        "pack_size": "1",
        "unit": "kg",
        "quantity": "50"
    },
    {
        "id": "3",
        "chemical_name": "Ethanol",
        "vendor": "Solvent Supplies",
        "density": "0.789",
        "viscosity": "1.2",
        "packaging": "Drum",
        "pack_size": "20",
        "unit": "L",
        "quantity": "5"
    },
    {
        "id": "4",
        "chemical_name": "Hydrochloric Acid",
        "vendor": "Acid Masters",
        "density": "1.19",
        "viscosity": "0.9",
        "packaging": "Barrel",
        "pack_size": "50",
        "unit": "L",
        "quantity": "10"
    },
    {
        "id": "5",
        "chemical_name": "Sulfuric Acid",
        "vendor": "Acid Solutions",
        "density": "1.84",
        "viscosity": "21.5",
        "packaging": "Tank",
        "pack_size": "200",
        "unit": "L",
        "quantity": "2"
    },
    {
        "id": "6",
        "chemical_name": "Sodium Bicarbonate",
        "vendor": "Baking Goods Ltd.",
        "density": "2.20",
        "viscosity": "N/A",
        "packaging": "Box",
        "pack_size": "500",
        "unit": "g",
        "quantity": "200"
    },
    {
        "id": "7",
        "chemical_name": "Calcium Carbonate",
        "vendor": "Minerals Group",
        "density": "2.71",
        "viscosity": "N/A",
        "packaging": "Sack",
        "pack_size": "25",
        "unit": "kg",
        "quantity": "10"
    },
    {
        "id": "8",
        "chemical_name": "Methanol",
        "vendor": "Pure Chemicals",
        "density": "0.791",
        "viscosity": "0.59",
        "packaging": "Bottle",
        "pack_size": "1",
        "unit": "L",
        "quantity": "30"
    },
    {
        "id": "9",
        "chemical_name": "Benzene",
        "vendor": "Industrial Solvents",
        "density": "0.876",
        "viscosity": "0.65",
        "packaging": "Drum",
        "pack_size": "20",
        "unit": "L",
        "quantity": "7"
    },
    {
        "id": "10",
        "chemical_name": "Hydrogen Peroxide",
        "vendor": "Oxidizers Ltd.",
        "density": "1.11",
        "viscosity": "1.4",
        "packaging": "Bulk",
        "pack_size": "100",
        "unit": "L",
        "quantity": "6"
    },
    {
        "id": "11",
        "chemical_name": "Ammonium Hydroxide",
        "vendor": "Clean Solutions",
        "density": "0.90",
        "viscosity": "0.91",
        "packaging": "Bottle",
        "pack_size": "2",
        "unit": "L",
        "quantity": "15"
    },
    {
        "id": "12",
        "chemical_name": "Acetone",
        "vendor": "Solvents R Us",
        "density": "0.784",
        "viscosity": "0.32",
        "packaging": "Can",
        "pack_size": "5",
        "unit": "L",
        "quantity": "20"
    },
    {
        "id": "13",
        "chemical_name": "Chloroform",
        "vendor": "Chemical Warehouse",
        "density": "1.48",
        "viscosity": "0.56",
        "packaging": "Drum",
        "pack_size": "10",
        "unit": "L",
        "quantity": "8"
    },
    {
        "id": "14",
        "chemical_name": "Glycerol",
        "vendor": "Biochemicals Ltd.",
        "density": "1.26",
        "viscosity": "1.5",
        "packaging": "Bottle",
        "pack_size": "1",
        "unit": "L",
        "quantity": "25"
    },
    {
        "id": "15",
        "chemical_name": "Citric Acid",
        "vendor": "Food Ingredients Co.",
        "density": "1.54",
        "viscosity": "0.8",
        "packaging": "Bag",
        "pack_size": "500",
        "unit": "g",
        "quantity": "100"
    }
]```