Skip to content

Commit

Permalink
Develop FileInput Component (#20)
Browse files Browse the repository at this point in the history
* Carve out initial implementation
* Include file list and preview feedback
* Decrease feedback and hint size on input
* Display file input feedback types
* Extract global styles to index
* Create full test coverage for FileInput
* Update readme documentation, cleanup model
* Add playwright test for fileInput
* 0.5.0
  • Loading branch information
PsiKai authored Oct 5, 2024
1 parent 1753d75 commit 58209b0
Show file tree
Hide file tree
Showing 16 changed files with 563 additions and 37 deletions.
2 changes: 1 addition & 1 deletion e2e/smoke-test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ test("Renders main header", async ({ page }) => {
test("Renders component sections", async ({ page }) => {
await page.goto("/")

for (const component of ["Button", "LoadingSpinner", "Input"]) {
for (const component of ["Button", "LoadingSpinner", "Input", "FileInput"]) {
await expect(page.getByRole("heading", { name: component, exact: true })).toBeVisible()
}
})
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"component",
"library"
],
"version": "0.4.0",
"version": "0.5.0",
"type": "module",
"scripts": {
"dev": "vite --open --port 3001",
Expand Down
49 changes: 32 additions & 17 deletions src/dev/AppDev.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
import React from "react"
import { LoadingSpinner } from "../lib/components/LoadingSpinner"
import { InputSection } from "./demos/Inputs"
import { ButtonSection } from "./demos/Buttons"
import { FileInputSection } from "./demos/FileInputs"
import "./index.css"
import { InputSection } from "./demos/Inputs"

export const AppDev = () => {
return (
<>
<h1>PK Component Library</h1>
<h2 id="Button">
<code>Button</code>
</h2>
<ButtonSection />
<h2 id="LoadingSpinner">
<code>LoadingSpinner</code>
</h2>
<section>
<LoadingSpinner />
</section>
<h2 id="Input">
<code>Input</code>
</h2>
<section>
<InputSection />
</section>
<div className="section-wrapper">
<h2 id="Button" className="section-header">
<code>Button</code>
</h2>
<ButtonSection />
</div>
<div className="section-wrapper">
<h2 id="LoadingSpinner" className="section-header">
<code>LoadingSpinner</code>
</h2>
<section>
<LoadingSpinner />
</section>
</div>
<div className="section-wrapper">
<h2 id="Input" className="section-header">
<code>Input</code>
</h2>
<section>
<InputSection />
</section>
</div>
<div className="section-wrapper">
<h2 id="FileInput" className="section-header">
<code>FileInput</code>
</h2>
<section>
<FileInputSection />
</section>
</div>
</>
)
}
38 changes: 38 additions & 0 deletions src/dev/demos/FileInputs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react"
import { FileInput } from "../../lib/components/FileInput"

export function FileInputSection() {
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
for (const file of e.target.files || []) {
console.log(file.name)
}
}

return (
<>
<div className="sub-section">
<h3>With label, hint, and file list</h3>
<FileInput
id="file-input-list"
onChange={onChange}
multiple
label="Upload your résumé"
fileDisplay="list"
accept=".jpg,.jpeg,.png,.pdf"
/>
</div>
<div className="sub-section">
<h3>With label hint and file preview</h3>
<FileInput
id="file-input-preview"
onChange={onChange}
fileDisplay="preview"
label="Upload your photos"
accept="image/*"
multiple
required
/>
</div>
</>
)
}
9 changes: 9 additions & 0 deletions src/dev/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
--background-color: #242424;

font-synthesis: none;
text-rendering: optimizeLegibility;
Expand Down Expand Up @@ -47,6 +48,13 @@ hr {
width: 100%;
}

.section-header {
position: sticky;
top: 0;
z-index: 1;
background-color: var(--background-color);
}

section {
display: flex;
flex-wrap: wrap;
Expand All @@ -71,6 +79,7 @@ section {
:root {
color: #213547;
background-color: #ffffff;
--background-color: #ffffff;
}
}

Expand Down
12 changes: 4 additions & 8 deletions src/lib/components/Button/Button.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,14 @@
--color-lightness: 100%;
--color-saturation: 100%;
cursor: pointer;
transition:
background-color 100ms,
border-color 100ms,
color 100ms,
transform 50ms;
transition: var(--pk-hover-transition);
border: 1px solid currentColor;
border-radius: 0.375rem;
border-radius: var(--pk-btn-border-radius);
font: inherit;
letter-spacing: 0.05em;
color: hsl(0, var(--color-saturation), var(--color-lightness));
background-color: hsl(var(--hue), var(--saturation), var(--lightness));
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3);
box-shadow: var(--pk-box-shadow);
position: relative;
}

Expand Down Expand Up @@ -77,7 +73,7 @@

.pk-button-large,
.pk-button-block {
padding: 0.75rem 1.25rem;
padding: var(--pk-padding-lg);
text-transform: uppercase;
font-weight: 700;
border-width: 2px;
Expand Down
122 changes: 122 additions & 0 deletions src/lib/components/FileInput/FileInput.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
@import "../index.css";

.pk-file-input-wrapper {
position: relative;
display: flex;
flex-direction: column;
gap: 0.5rem;
}

.pk-file-input-label {
--lightness: 50%;
--saturation: 0%;
display: inline-block;
padding: var(--pk-padding-lg);
border: 2px solid hsl(var(--pk-hue-secondary), var(--saturation), var(--lightness));
border-radius: var(--pk-btn-border-radius);
box-shadow: var(--pk-box-shadow);
color: hsl(var(--pk-hue-secondary), var(--saturation), var(--lightness));
background-color: transparent;
cursor: pointer;
display: flex;
gap: 0.5rem;
align-items: center;
justify-content: center;
transition: var(--pk-hover-transition);
text-transform: uppercase;
font-weight: 700;
letter-spacing: 0.05em;
}

.pk-file-input-label:hover {
--lightness: 40%;
}

.pk-file-input-label:active {
transform: translate3d(0px, 1px, 5px);
}

.pk-file-input:focus-visible + .pk-file-input-label {
outline-color: hsl(var(--pk-hue-secondary), var(--saturation), var(--lightness));
outline-width: 2px;
outline-offset: 2px;
outline-style: solid;
}

.folder-upload-icon {
display: inline-block;
width: 1.5rem;
height: 1.5rem;
fill: hsl(var(--pk-hue-secondary), var(--saturation), var(--lightness));
}

.pk-file-input {
width: 0.0001px;
height: 0.0001px;
position: absolute;
-webkit-appearance: none;
appearance: none;
opacity: 0;
}

.pk-file-input:focus {
outline: none;
}

.pk-file-input-description {
font-weight: bold;
}

.pk-file-input-accept {
font-size: 0.875rem;
font-weight: thin;
}

.pk-file-list {
margin: 0;
padding: 0;
list-style: none;
font-size: 0.875rem;
font-style: italic;
}

.pk-file-list-item {
position: relative;
}

.pk-file-list-remove {
padding: 0 0.25rem;
}

.pk-file-preview-wrapper {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}

.pk-file-preview {
height: 200px;
position: relative;
}

.pk-file-preview-image {
max-width: 100%;
height: 100%;
object-fit: cover;
}

.pk-file-preview-remove {
position: absolute;
top: 0.25rem;
right: 0.25rem;
padding: 0 0.25rem;
}

.pk-file-list-remove > svg,
.pk-file-preview-remove > svg {
width: 1rem;
height: 1rem;
vertical-align: middle;
margin-top: calc(1ex - 1cap);
fill: currentColor;
}
7 changes: 7 additions & 0 deletions src/lib/components/FileInput/FileInput.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AllHtmlAttributes } from "../../core-types"

export type TFileInputProps = AllHtmlAttributes & {
id: string
onChange: React.ChangeEventHandler<HTMLInputElement>
fileDisplay?: "list" | "preview"
}
Loading

0 comments on commit 58209b0

Please sign in to comment.