@kbgarcia8/react-dynamic-form
Version:
A form that can be nested with editable, expandable and flexible input-forms
663 lines (657 loc) • 19.6 kB
JavaScript
import { jsx as a, jsxs as g, Fragment as R } from "react/jsx-runtime";
import q, { forwardRef as J, createContext as K, useState as Q, useContext as V } from "react";
import r, { ThemeProvider as X } from "styled-components";
const e = {
fonts: {
secondary: "Raleway",
tertiary: "Lato",
fallback: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif"
},
fontWeight: {
light: 300,
medium: 500,
bold: 700,
bolder: 900
},
fontSize: {
xsmall: "0.75rem"
},
spacing: {
xxxsmall: "0.25rem",
xxsmall: "0.375rem",
xsmall: "0.5rem",
small: "0.75rem",
medium: "1.25rem"
},
borderRadius: {
xsmall: "0.125rem",
small: "0.25rem",
xlarge: "2rem"
},
borderThickness: {
thin: "0.0625rem",
light: "0.125rem"
}
}, Y = r.button`
display: flex;
align-items: center;
justify-content: center;
background-color: ${({ theme: t }) => t.colors.blue || "blue"};
color: ${({ theme: t }) => t.colors.bg || "white"};
border: ${e.borderThickness.light} solid ${({ theme: t }) => t.colors.text || "black"};
border-radius: ${e.borderRadius.xlarge};
padding: ${e.spacing.xxxsmall} ${e.spacing.small};
margin: 0.125rem;
width: auto;
cursor: pointer;
transition: background-color 0.2s ease, border-color 0.2s ease;
&:hover {
background-color: lightblue;
border: ${e.borderThickness.light} solid gray;
}
& .button-icon-text-space {
max-width: 100%;
}
& .button-icon-text-space svg {
max-width: 100%;
}
`, Z = r.div`
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
`, _ = r.img`
maxwidth: 100%;
`, ee = r.span`
font-size: ${e.fontSize.xsmall};
font-weight: ${e.fontWeight.medium};
font-family: ${e.fonts.tertiary}, ${e.fonts.fallback};
display: flex;
align-items: center;
justify-content: center;
`, x = ({
onClick: t,
id: o,
buttonType: i,
source: l,
svg: b,
alt: d = "alt-button-icon",
text: m = "",
className: c = "",
dataAttributes: f = {}
}) => /* @__PURE__ */ a(
Y,
{
onClick: t,
id: o,
type: i,
className: c,
...f,
children: /* @__PURE__ */ g(Z, { className: "button-icon-text-space", children: [
l ? /* @__PURE__ */ a(_, { src: l, alt: d }) : b || "",
m && /* @__PURE__ */ a(ee, { id: o, children: m })
] })
}
), te = r.div`
display: flex;
flex-direction: column;
align-items: left;
width: 100%;
margin-bottom: ${e.spacing.small};
`, ae = r.div`
display: flex;
gap: ${e.spacing.xsmall};
width: auto;
height: auto;
`, ne = r.label`
display: flex;
align-items: center;
justify-content:center;
height: auto;
flex-direction: ${(t) => t.$labelFlexDirection || "column"};
font-family: ${e.fonts.secondary}, ${e.fonts.fallback};
font-size: ${e.fontSize.xsmall};
font-weight: ${e.fontWeight.bold};
gap: ${e.spacing.xxsmall};
& .label-icon-container img,
& .label-icon-container svg {
max-width: 100%;
height: auto;
object-fit: contain;
}
`, oe = r.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: ${e.spacing.xxxsmall};
`, le = r.span`
font-weight: ${e.fontWeight.bolder};
`, ie = r.div`
max-width: 100%;
display: flex;
align-items: center;
`, se = r.span`
font-weight: ${e.fontWeight.light};
`, B = ({
htmlFor: t,
textLabel: o,
additionalInfo: i,
$labelFlexDirection: l,
source: b,
svg: d,
className: m,
children: c
}) => /* @__PURE__ */ g(ne, { htmlFor: t, className: m, $labelFlexDirection: l, children: [
(b || d) && /* @__PURE__ */ a(ie, { className: "label-icon-container", children: b ? /* @__PURE__ */ a("img", { src: b, alt: `${t}-label-icon` }) : d || "" }),
/* @__PURE__ */ g(oe, { className: "label-text-container", children: [
/* @__PURE__ */ a(le, { className: "main-label", children: o }),
i && /* @__PURE__ */ a(se, { className: "additional-info", children: i })
] }),
c
] }), W = r.input`
display: flex;
place-content: center;
font-family: ${e.fonts.secondary}, ${e.fonts.fallback};
font-size: ${e.fontSize.xsmall};
line-height: 1.75;
padding: ${e.spacing.xxxsmall} ${e.spacing.xsmall};
max-width: 100%;
height: auto;
background-color: #FFFFFF;
outline: none;
border: ${e.borderThickness.thin} solid #000000;
border-radius: ${e.borderRadius.xsmall};
&:focus{
border: ${e.borderThickness.thin} solid ${({ theme: t }) => t.colors.teal};
}
`, ce = r.textarea`
display: flex;
place-content: center;
border: ${e.borderThickness.light} solid ${({ theme: t }) => t.colors.text};
border-radius: ${e.borderRadius.small};
outline: none;
line-height: ${e.spacing.small};
padding: ${e.spacing.xxxsmall};
font-family: ${e.fonts.secondary}, ${e.fonts.fallback};
font-size: ${e.fontSize.xsmall};
max-width: 100%;
resize: none;
overflow-y: auto;
`, D = J((t, o) => {
const { type: i, id: l, onChange: b, isRequired: d, dataAttributes: m, disabled: c, className: f } = t;
if (i === "textarea") {
const { rows: y = 5, cols: F = 30, value: v, ...A } = t;
return /* @__PURE__ */ a(
ce,
{
id: l,
onChange: b,
value: v,
rows: y,
cols: F,
...m,
className: f,
ref: o,
disabled: c,
required: d
}
);
}
if (i === "radio" || i === "checkbox") {
const { checked: y, ...F } = t;
return /* @__PURE__ */ a(
W,
{
ref: o,
type: "checkbox",
id: l,
checked: y,
onChange: b,
disabled: c,
className: f,
...m
}
);
}
const $ = t, { value: N, pattern: p, placeholderText: C, ...w } = $;
return /* @__PURE__ */ a(
W,
{
id: l,
name: l,
placeholder: C,
onChange: b,
value: N,
type: i,
required: d,
...m,
className: f,
ref: o,
disabled: c,
pattern: p
}
);
}), E = (t) => {
const {
className: o,
type: i,
id: l,
textLabel: b,
additionalInfo: d,
$labelFlexDirection: m,
svg: c,
labelClass: f,
onChange: $,
isRequired: N,
dataAttributes: p,
inputClass: C,
ref: w,
disabled: y,
isEditable: F,
editIcon: v,
onClickEdit: A,
deleteIcon: S,
onClickDelete: z,
idx: T,
children: j
} = t;
return /* @__PURE__ */ g(te, { className: `${o} ${l.replace("#", "")}-label-input-container`, children: [
i !== "radio" && i !== "checkbox" && /* @__PURE__ */ a(B, { htmlFor: l, textLabel: b, additionalInfo: d, $labelFlexDirection: m, svg: c, className: f }),
i !== "radio" && i !== "checkbox" && i === "textarea" && (() => {
const { rows: n = 5, cols: u = 30, value: s, ...k } = t;
return /* @__PURE__ */ a(
D,
{
id: l,
name: l,
type: "textarea",
isRequired: N,
onChange: $,
value: s,
rows: n,
cols: u,
dataAttributes: p,
className: C,
ref: w,
disabled: y
}
);
})(),
i !== "radio" && i !== "checkbox" && i !== "textarea" && (() => {
const n = t, { value: u, pattern: s, placeholderText: k, ...L } = n;
return /* @__PURE__ */ a(
D,
{
id: l,
name: l,
placeholderText: k,
onChange: $,
value: u,
type: i,
isRequired: N,
dataAttributes: p,
className: C,
ref: w,
disabled: y,
pattern: s
}
);
})(),
(i === "radio" || i === "checkbox") && (() => {
const { checked: n, ...u } = t;
return /* @__PURE__ */ g(R, { children: [
/* @__PURE__ */ a(
D,
{
ref: w,
type: "checkbox",
name: l,
id: l,
isRequired: N,
checked: n,
onChange: $,
disabled: y,
className: C,
dataAttributes: p
}
),
/* @__PURE__ */ a(B, { htmlFor: l, textLabel: b, additionalInfo: d, $labelFlexDirection: m, svg: c, className: f })
] });
})(),
F && /* @__PURE__ */ g(ae, { className: "input-edit-buttons", children: [
/* @__PURE__ */ a(x, { id: `editable-${l}-edit-btn`, svg: v, buttonType: "button", onClick: A, className: `edit-radio-${T}`, dataAttributes: p }),
/* @__PURE__ */ a(x, { id: `editable-${l}-delete-btn`, svg: S, buttonType: "button", onClick: z, className: `delete-radio-${T}`, dataAttributes: p })
] }),
j
] });
}, re = r.fieldset`
padding: 0;
height: auto;
width: 100%;
`, de = r.legend`
font-size: ${e.spacing.medium};
font-weight: 500;
margin: 0 auto ${e.spacing.small} auto;
text-align: center;
font-family: ${e.fonts.secondary}, ${e.fonts.fallback};
`, me = r.div`
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
margin-bottom: ${e.spacing.small};
`, be = r.div`
display: flex;
justify-content: space-between;
width: 100%;
`, P = ({
legend: t,
idx: o,
editableInformation: i,
onChangeOfEditableOption: l,
onClickSaveEdit: b,
onClickCancelEdit: d,
onClickDeleteEntry: m
}) => /* @__PURE__ */ g(re, { className: "editable-option-fieldset", children: [
/* @__PURE__ */ a(de, { children: `${t} ${o + 1}` }),
i?.map((c, f) => /* @__PURE__ */ a(me, { className: "editable-option-container", children: /* @__PURE__ */ a(
D,
{
id: `editable-option-${f}`,
name: `editable-option-${f}`,
placeholderText: c.name.charAt(0).toUpperCase() + c.name.slice(1),
onChange: l,
value: c.info,
type: c.type,
isRequired: !0,
className: "editable-option",
dataAttributes: {
"data-index": f,
"data-key": c.info
}
}
) }, `${c.name}-${f}`)),
/* @__PURE__ */ g(be, { className: "editable-option-button-space", children: [
/* @__PURE__ */ a(x, { id: `editable-option-${o}-submit`, buttonType: "button", text: "Save", onClick: b, className: "editable-option-btn", dataAttributes: { "data-index": o } }),
/* @__PURE__ */ a(x, { id: `editable-option-${o}-cancel`, buttonType: "button", text: "Cancel", onClick: d, className: "editable-option-btn", dataAttributes: { "data-index": o } }),
/* @__PURE__ */ a(x, { id: `editable-option-${o}-delete`, buttonType: "button", text: "Delete", onClick: m, className: "editable-option-btn", dataAttributes: { "data-index": o } })
] })
] }), he = r.div`
display: flex;
justify-content: space-between;
max-width: 100%;
`, fe = ({
id: t,
hasSubmit: o,
submitText: i,
handleSubmit: l,
hasReset: b,
resetText: d,
handleReset: m,
hasCancel: c,
cancelText: f,
handleCancel: $
}) => /* @__PURE__ */ g(he, { className: "form-main-button-container", children: [
o && /* @__PURE__ */ a(x, { id: `form-${t}-submit`, buttonType: "submit", text: i ?? "Submit", onClick: l, className: "submit-form-btn" }),
b && /* @__PURE__ */ a(x, { id: `form-${t}-edit`, buttonType: "button", text: d ?? "Reset", onClick: m, className: "reset-form-btn" }),
c && /* @__PURE__ */ a(x, { id: `form-${t}-cancel`, buttonType: "button", text: f ?? "Cancel", onClick: $, className: "cancel-form-btn" })
] }), M = r.legend`
font-size: ${e.spacing.medium};
font-weight: 500;
margin-bottom: ${e.spacing.small};
width: auto;
text-align: center;
font-family: ${e.fonts.secondary}, ${e.fonts.fallback};
`, U = r.fieldset`
padding: 0;
height: auto;
width: 100%;
`, H = r.div`
padding: ${e.spacing.small};
height: auto;
width: 100%;
`, I = r.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: auto;
font-family: ${e.fonts.tertiary}, ${e.fonts.fallback};
font-size: ${e.fontSize.xsmall};
font-weight: ${e.fontWeight.bold};
`, ge = r.form`
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
`, O = r.div`
display: flex;
justify-content: space-between;
width: 100%;
`, ue = r.div`
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
`, Ce = ({
fieldsets: t = null,
legendText: o,
isExpandable: i,
id: l,
formInputs: b,
labelAndInputContainerClass: d,
labelClass: m,
inputClass: c,
onChangeOfEditableOption: f,
handleAddingInputEntry: $,
hasSubmit: N = !1,
submitText: p,
handleSubmit: C,
hasReset: w = !1,
resetText: y,
handleReset: F,
hasCancel: v = !1,
cancelText: A,
handleCancel: S,
handleSubmitForm: z,
className: T,
children: j
}) => /* @__PURE__ */ g(ge, { id: `${l}-form`, className: T, onSubmit: z, children: [
t ? t.map((n, u) => /* @__PURE__ */ g(H, { className: `${l}-fieldset-wrapper`, children: [
/* @__PURE__ */ g(U, { id: `${l}-form-fieldset-${u}`, className: `${n.legend}-fieldset`, children: [
n.legend && /* @__PURE__ */ a(M, { className: `${n.legend}-legend`, children: n.legend }),
n.inputs.length !== 0 ? n.inputs.map((s, k) => /* @__PURE__ */ g(q.Fragment, { children: [
s.type === "textarea" && /* @__PURE__ */ a(
E,
{
...s,
id: s.id ?? `${n.legend}-input`,
labelClass: m,
inputClass: c,
idx: k,
className: `${d} ${s?.uniqueClass}`
}
),
s.type !== "textarea" && s.type !== "radio" && s.type !== "checkbox" && /* @__PURE__ */ a(
E,
{
...s,
id: s.id ?? `${n.legend}-input`,
labelClass: m,
inputClass: c,
idx: k,
className: `${d} ${s?.uniqueClass}`
}
),
(s.type === "radio" || s.type === "checkbox") && /* @__PURE__ */ g(R, { children: [
/* @__PURE__ */ a(
E,
{
...s,
id: s.id ?? `${n.legend}-input`,
labelClass: m,
inputClass: c,
idx: k,
className: `${d} ${s?.uniqueClass}`
}
),
s.editing && s.isEditable && /* @__PURE__ */ a(
P,
{
legend: `${n.legend}`,
idx: k,
editableInformation: s?.editableInformation || [],
onChangeOfEditableOption: f,
onClickSaveEdit: s?.onClickSave || ((L) => {
}),
onClickCancelEdit: s?.onClickCancel || ((L) => {
}),
onClickDeleteEntry: s?.onClickDelete || ((L) => {
})
}
)
] })
] }, `form-${l}-${k}`)) : n.isExpandable ? /* @__PURE__ */ a(I, { children: `No entry yet on ${n.legend}. Click "+" button to add entry.` }) : ""
] }),
n.isExpandable && /* @__PURE__ */ a(O, { className: "add-input-button-space", children: /* @__PURE__ */ a(x, { id: `expand-${n.legend}-inputs`, buttonType: "button", text: "+", onClick: $, className: "add-input-entry" }) })
] }, `${n.legend}-${u}`)) : /* @__PURE__ */ g(H, { className: `${l}-fieldset-wrapper`, children: [
/* @__PURE__ */ g(U, { id: `${l}-form-fieldset`, className: `${o}-fieldset`, children: [
o && /* @__PURE__ */ a(M, { className: `${o}-legend`, children: o }),
!t && b && b.length !== 0 ? b.map((n, u) => /* @__PURE__ */ g(q.Fragment, { children: [
n.type === "textarea" && /* @__PURE__ */ a(
E,
{
...n,
id: n.id ?? `${o}-input`,
labelClass: m,
inputClass: c,
idx: u,
className: `${d} ${n?.uniqueClass}`
}
),
n.type !== "textarea" && n.type !== "radio" && n.type !== "checkbox" && /* @__PURE__ */ a(
E,
{
...n,
id: n.id ?? `${o}-input`,
labelClass: m,
inputClass: c,
idx: u,
className: `${d} ${n?.uniqueClass}`
}
),
(n.type === "radio" || n.type === "checkbox") && /* @__PURE__ */ g(R, { children: [
/* @__PURE__ */ a(
E,
{
...n,
id: n.id ?? `${o}-input`,
labelClass: m,
inputClass: c,
idx: u,
className: `${d} ${n?.uniqueClass}`
}
),
n.editing && n.isEditable && /* @__PURE__ */ a(
P,
{
legend: `${o}`,
idx: u,
editableInformation: n?.editableInformation,
onChangeOfEditableOption: f,
onClickSaveEdit: n?.onClickSave || ((s) => {
}),
onClickCancelEdit: n?.onClickCancel || ((s) => {
}),
onClickDeleteEntry: n?.onClickDelete || ((s) => {
})
}
)
] })
] }, `form-${l}-${u}`)) : i ? /* @__PURE__ */ a(I, { children: `No entry yet on ${o}. Please click "+" button to add` }) : ""
] }),
i && /* @__PURE__ */ a(O, { className: "add-input-button-space", children: /* @__PURE__ */ a(x, { id: `expand-${o}-inputs`, buttonType: "button", text: "+", onClick: $, className: "add-input-entry" }) })
] }),
/* @__PURE__ */ a(
fe,
{
id: l,
hasSubmit: N,
submitText: p,
handleSubmit: C,
hasReset: w,
resetText: y,
handleReset: F,
hasCancel: v,
cancelText: A,
handleCancel: S
}
),
/* @__PURE__ */ a(ue, { className: "children-container", children: j })
] }), $e = (t) => {
const o = /^#([0-9A-Fa-f]{3}){1,2}$/, i = /^rgb(a)?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}(?:\s*,\s*(0|1|0?\.\d+))?\s*\)$/;
return o.test(t) || i.test(t) || CSS.supports("color", t);
}, h = (t) => {
if (!$e(t)) throw new Error(`Invalid color: ${t}`);
return t;
}, we = {
mobile: "320px",
//Small iPhone SE & Medium: iPhone 12-15
tablet: "768px",
//iPad
desktop: "992px",
//Macbook 13" (1280x800)
largeDesktop: "1200px",
largerDesktop: "1400px"
}, xe = {
name: "light",
colors: {
text: h("#333446"),
bg: h("#EEEEEE"),
blue: h("#7F8CAA"),
blue2: h("#80A6FF"),
teal: h("#5b8280ff"),
teal2: h("#AEEAE7"),
gray: h("#AEAEAE"),
information: h("#202234"),
success: h("#123524"),
warning: h("#F2C265"),
error: h("#990000")
}
}, pe = {
name: "dark",
colors: {
bg: h("#333446"),
text: h("#EEEEEE"),
blue: h("#80A6FF"),
blue2: h("#7F8CAA"),
teal: h("#AEEAE7"),
teal2: h("#5b8280ff"),
gray: h("#D0D0DD"),
information: h("#C9E6F0"),
success: h("#9EDF9C"),
warning: h("#FCFFC1"),
error: h("#FAD4D4")
}
}, G = K({}), Fe = ({
children: t,
initialTheme: o = xe,
secondTheme: i = pe
}) => {
const [l, b] = Q(o), d = () => {
b((m) => m === o ? i : o);
};
return /* @__PURE__ */ a(G.Provider, { value: { currentTheme: l, toggleTheme: d }, children: /* @__PURE__ */ a(X, { theme: l, children: t }) });
}, Ee = () => V(G);
export {
Ce as DynamicForm,
G as ThemeContext,
Fe as ThemeContextProvider,
we as breakpoints,
pe as darkTheme,
xe as lightTheme,
Ee as useTheme
};