feat: docker compose maybe

This commit is contained in:
2023-11-13 16:10:04 -05:00
parent 180b261e40
commit b625ccd8d6
8031 changed files with 2182966 additions and 0 deletions

View File

@ -0,0 +1,87 @@
<script>import { createEventDispatcher } from "svelte";
import { tableA11y } from "./actions.js";
const dispatch = createEventDispatcher();
export let source;
export let interactive = false;
export let element = "table";
export let text = "";
export let color = "";
export let regionHead = "";
export let regionHeadCell = "";
export let regionBody = "";
export let regionCell = "";
export let regionFoot = "";
export let regionFootCell = "";
function onRowClick(event, rowIndex) {
if (!interactive)
return;
event.preventDefault();
event.stopPropagation();
const rowMetaData = source.meta ? source.meta[rowIndex] : source.body[rowIndex];
dispatch("selected", rowMetaData);
}
function onRowKeydown(event, rowIndex) {
if (["Enter", "Space"].includes(event.code))
onRowClick(event, rowIndex);
}
$:
classesBase = `${$$props.class || ""}`;
$:
classesTable = `${element} ${text} ${color}`;
</script>
<div class="table-container {classesBase}">
<!-- Table -->
<!-- prettier-ignore -->
<table
class="{classesTable}"
class:table-interactive={interactive}
role="grid"
use:tableA11y
>
<!-- on:keydown={(e) => onTableKeydown(elemTable, e)} -->
<!-- Head -->
<thead class="table-head {regionHead}">
<tr>
{#each source.head as heading }
<th class="{regionHeadCell}">{@html heading}</th>
{/each}
</tr>
</thead>
<!-- Body -->
<tbody class="table-body {regionBody}">
{#each source.body as row, rowIndex}
<!-- Row -->
<!-- prettier-ignore -->
<tr
on:click={(e) => { onRowClick(e, rowIndex); }}
on:keydown={(e) => { onRowKeydown(e, rowIndex); }}
aria-rowindex={rowIndex + 1}
>
{#each row as cell, cellIndex}
<!-- Cell -->
<!-- prettier-ignore -->
<td
class="{regionCell}"
role="gridcell"
aria-colindex={cellIndex + 1}
tabindex={cellIndex === 0 ? 0 : -1}
>
{@html Number(cell) === 0 ? cell : (cell ? cell : '-')}
</td>
{/each}
</tr>
{/each}
</tbody>
<!-- Foot -->
{#if source.foot}
<tfoot class="table-foot {regionFoot}">
<tr>
{#each source.foot as cell }
<td class="{regionFootCell}">{@html cell}</td>
{/each}
</tr>
</tfoot>
{/if}
</table>
</div>

View File

@ -0,0 +1,42 @@
import { SvelteComponentTyped } from "svelte";
import type { TableSource } from '../../index.js';
declare const __propDef: {
props: {
[x: string]: any;
/** Provide the full set of table source data.*/
source: TableSource;
/** Enables row hover style and `on:selected` event when rows are clicked.*/
interactive?: boolean | undefined;
/** Override the Tailwind Element class. Replace this for a headless UI.*/
element?: string | undefined;
/** Provide classes to set the table text size.*/
text?: string | undefined;
/** Provide classes to set the table text color.*/
color?: string | undefined;
/** Provide arbitrary classes for the table head.*/
regionHead?: string | undefined;
/** Provide arbitrary classes for the table head cells.*/
regionHeadCell?: string | undefined;
/** Provide arbitrary classes for the table body.*/
regionBody?: string | undefined;
/** Provide arbitrary classes for the table cells.*/
regionCell?: string | undefined;
/** Provide arbitrary classes for the table foot.*/
regionFoot?: string | undefined;
/** Provide arbitrary classes for the table foot cells.*/
regionFootCell?: string | undefined;
};
events: {
/** {rowMetaData} selected - Fires when a table row is clicked.*/
selected: CustomEvent<string[]>;
} & {
[evt: string]: CustomEvent<any>;
};
slots: {};
};
export type TableProps = typeof __propDef.props;
export type TableEvents = typeof __propDef.events;
export type TableSlots = typeof __propDef.slots;
export default class Table extends SvelteComponentTyped<TableProps, TableEvents, TableSlots> {
}
export {};

View File

@ -0,0 +1,8 @@
/** Svelte Action for applying sort asc/dsc classes. */
export declare function tableInteraction(node: HTMLElement): {
destroy(): void;
};
/** Svelte Action for handling table a11y keyboard interactions. */
export declare function tableA11y(node: HTMLElement): {
destroy(): void;
};

View File

@ -0,0 +1,114 @@
// Shared Data/Table Actions
// Data Table (only) ---
/** Svelte Action for applying sort asc/dsc classes. */
export function tableInteraction(node) {
const classAsc = 'table-sort-asc';
const classDsc = 'table-sort-dsc';
// Click Handler
const onClick = (e) => {
if (!(e.target instanceof Element))
return;
const sortTarget = e.target;
// Get target state before modification
const targetAscSorted = sortTarget.classList.contains(classAsc);
const sortTargetKey = sortTarget.getAttribute('data-sort');
// Clear asc class
const elemAsc = node.querySelector(`.${classAsc}`);
if (elemAsc)
elemAsc.classList.remove(classAsc);
// Clear dsc class
const elemDsc = node.querySelector(`.${classDsc}`);
if (elemDsc)
elemDsc.classList.remove(classDsc);
// Set new sort class
if (sortTargetKey) {
const classToApply = targetAscSorted ? classDsc : classAsc;
e.target.classList.add(classToApply);
}
};
// Events
node.addEventListener('click', onClick);
// Lifecycle
return {
destroy() {
node.removeEventListener('click', onClick);
}
};
}
// Shared ---
/** Svelte Action for handling table a11y keyboard interactions. */
export function tableA11y(node) {
const keyWhitelist = ['ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowDown', 'Home', 'End'];
// on:keydown
const onKeyDown = (event) => {
// console.log('keydown triggered');
if (keyWhitelist.includes(event.code)) {
event.preventDefault();
// prettier-ignore
switch (event.code) {
case 'ArrowUp':
a11ySetActiveCell(node, 0, -1);
break;
case 'ArrowDown':
a11ySetActiveCell(node, 0, 1);
break;
case 'ArrowLeft':
a11ySetActiveCell(node, -1, 0);
break;
case 'ArrowRight':
a11ySetActiveCell(node, 1, 0);
break;
case 'Home':
a11yJumpToOuterColumn(node, 'first');
break;
case 'End':
a11yJumpToOuterColumn(node, 'last');
break;
default: break;
}
}
};
// Event Listener
node.addEventListener('keydown', onKeyDown);
// Lifecycle
return {
destroy() {
node.removeEventListener('keydown', onKeyDown);
}
};
}
function a11ySetActiveCell(node, x, y) {
// Focused Element
const focusedElem = document.activeElement;
if (!focusedElem || !focusedElem.parentElement || !focusedElem.parentElement.ariaRowIndex || !focusedElem.ariaColIndex)
return;
const focusedElemRowIndex = parseInt(focusedElem.parentElement.ariaRowIndex);
const focusedElemColIndex = parseInt(focusedElem.ariaColIndex);
// Target Element
const targetRowElement = node.querySelector(`[aria-rowindex="${focusedElemRowIndex + y}"]`);
if (targetRowElement !== null) {
const targetColElement = targetRowElement.querySelector(`[aria-colindex="${focusedElemColIndex + x}"]`);
if (targetColElement !== null)
targetColElement.focus();
}
}
function a11yGetTargetElem(node) {
// Focused Element
const focusedElem = document.activeElement;
if (!focusedElem || !focusedElem.parentElement || !focusedElem.parentElement.ariaRowIndex)
return null;
const focusedElemRowIndex = parseInt(focusedElem.parentElement.ariaRowIndex);
// Return Target Element
return node.querySelector(`[aria-rowindex="${focusedElemRowIndex}"]`);
}
function a11yJumpToOuterColumn(node, type = 'first') {
const targetRowElement = a11yGetTargetElem(node);
if (targetRowElement === null)
return;
const lastIndex = targetRowElement.children.length;
const selected = type === 'first' ? 1 : lastIndex;
const targetColElement = targetRowElement.querySelector(`[aria-colindex="${selected}"]`);
if (targetColElement === null)
return;
targetColElement.focus();
}

View File

@ -0,0 +1,10 @@
export interface TableSource {
/** The formatted table heading values. */
head: string[];
/** The formatted table body values. */
body: string[][];
/** The data returned when an interactive row is clicked. */
meta?: string[][];
/** The formatted table footer values. */
foot?: string[];
}

View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,7 @@
/** Wrap object key value with an HTML tag. */
/** Map an object to a defined order. */
export declare function tableSourceMapper(source: any[], keys: string[]): any[];
/** Map an array of objects to an array of values. */
export declare function tableSourceValues(source: any[]): any[];
/** Sets object order and returns values. */
export declare function tableMapperValues(source: any[], keys: string[]): any[];

View File

@ -0,0 +1,33 @@
// Table Component Utilities
// Cell Formatters ---
// NOTE: this would require `onMount`, which is too slow, so may just nix this.
// REMINDER: if re-enabled, update `index.ts`!
/** Wrap object key value with an HTML tag. */
// export function tableCellFormatter(source: any[], key: string, tagName: string, classes?: string) {
// return source.map((row) => {
// if (row[key]) {
// const newElem: HTMLElement = document.createElement(tagName);
// newElem.innerHTML = row[key];
// if (classes) newElem.setAttribute('class', classes);
// row[key] = newElem.outerHTML;
// }
// return row;
// });
// }
// Source Formatters ---
/** Map an object to a defined order. */
export function tableSourceMapper(source, keys) {
return source.map((row) => {
const mappedRow = {};
keys.forEach((key) => (mappedRow[key] = row[key]));
return mappedRow;
});
}
/** Map an array of objects to an array of values. */
export function tableSourceValues(source) {
return source.map((row) => Object.values(row));
}
/** Sets object order and returns values. */
export function tableMapperValues(source, keys) {
return tableSourceValues(tableSourceMapper(source, keys));
}