├── .github
└── workflows
│ └── publish.yml
├── .gitignore
├── .npmrc
├── .prettierrc
├── .vscode
├── extensions.json
└── launch.json
├── README.md
├── package-lock.json
├── package.json
├── packages
├── astro-forms
│ ├── Form.astro
│ ├── README.md
│ ├── index.mjs
│ ├── package.json
│ ├── themes
│ │ ├── default
│ │ │ ├── ArrayInput.astro
│ │ │ ├── BooleanInput.astro
│ │ │ ├── DateInput.astro
│ │ │ ├── GenericInput.astro
│ │ │ ├── NumberInput.astro
│ │ │ ├── StringInput.astro
│ │ │ ├── Submit.astro
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ └── tailwind
│ │ │ ├── ArrayInput.astro
│ │ │ ├── BooleanInput.astro
│ │ │ ├── DateInput.astro
│ │ │ ├── GenericInput.astro
│ │ │ ├── InputLayout.astro
│ │ │ ├── NumberInput.astro
│ │ │ ├── README.md
│ │ │ ├── StringInput.astro
│ │ │ ├── Submit.astro
│ │ │ ├── index.ts
│ │ │ └── tailwind.config.cjs
│ ├── types.ts
│ └── util.ts
└── demo
│ ├── astro.config.mjs
│ ├── package.json
│ ├── public
│ └── favicon.ico
│ ├── src
│ ├── pages
│ │ └── index.astro
│ └── util
│ │ └── schema.ts
│ └── tailwind.config.cjs
├── tsconfig.json
└── yarn.lock
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish Package to npmjs
2 | on:
3 | release:
4 | types: [created]
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v3
10 | # Setup .npmrc file to publish to npm
11 | - uses: actions/setup-node@v3
12 | with:
13 | node-version: '16.x'
14 | registry-url: 'https://registry.npmjs.org'
15 | # Defaults to the user or organization that owns the workflow file
16 | scope: '@octocat'
17 | - run: yarn
18 | - run: yarn upload
19 | env:
20 | NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 |
4 | # dependencies
5 | node_modules/
6 |
7 | # logs
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 | pnpm-debug.log*
12 |
13 |
14 | # environment variables
15 | .env
16 | .env.production
17 |
18 | # macOS-specific files
19 | .DS_Store
20 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | # Expose Astro dependencies for `pnpm` users
2 | shamefully-hoist=true
3 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 2,
3 | "useTabs": false
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["astro-build.astro-vscode"],
3 | "unwantedRecommendations": []
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "command": "./node_modules/.bin/astro dev",
6 | "name": "Development server",
7 | "request": "launch",
8 | "type": "node-terminal"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 🚧 **Under Development** 🚧
2 |
3 | This component is under construction! It does work, however, bugs may be present.
4 |
5 | Pull requests are appreciated!
6 |
7 | # Astro Forms
8 |
9 | A Dynamic form component for Astro.
10 |
11 | Uses a JSON schema to generate a form.
12 |
13 | ## Themes
14 |
15 | There are currently two themes available:
16 |
17 | - `default`
18 | - `tailwind` [(View README)](/packages/astro-forms/themes/tailwind/README.md)
19 |
20 | ## Usage
21 |
22 | ### Installation
23 |
24 | ```bash
25 | yarn add astro-forms
26 | ```
27 |
28 | or
29 |
30 | ```bash
31 | npm install astro-forms
32 | ```
33 |
34 | ### Setup
35 |
36 | ```astro
37 | ---
38 | import { Form } from "astro-forms";
39 | const schema = {
40 | type: "object",
41 | properties: {
42 | name: {
43 | type: "string",
44 | title: "Name",
45 | },
46 | email: {
47 | type: "string",
48 | title: "Email",
49 | },
50 | password: {
51 | type: "string",
52 | title: "Password",
53 | },
54 | submit: {
55 | type: "submit",
56 | title: "Submit",
57 | },
58 | },
59 | }; // Or whatever you want it to be, must be an object.
60 | ---
61 |
62 |
63 | ```
64 |
65 | ## Schema
66 |
67 | The JSON schema for this form component has a single type that can repeat itself.
68 |
69 | ```ts
70 | export type InputType =
71 | | "string"
72 | | "email"
73 | | "password"
74 | | "search"
75 | | "url"
76 | | "number"
77 | | "boolean"
78 | | "array"
79 | | "object"
80 | | "date"
81 | | "submit";
82 |
83 | export interface FormSchema {
84 | type: InputType;
85 | title: string;
86 | subtitle?: string;
87 | properties: {
88 | [key: string]: FormSchema;
89 | };
90 | items?: FormSchema;
91 | }
92 | ```
93 |
94 | These types may be updated and will be marked as a breaking change if done so.
95 |
96 | Schema example:
97 |
98 | ```json
99 | {
100 | "type": "object",
101 | "title": "Form",
102 | "properties": {
103 | "name": {
104 | "type": "string",
105 | "title": "Name",
106 | "subtitle": "Alphanumeric characters only!!!!"
107 | },
108 | "email": {
109 | "type": "string",
110 | "title": "Email",
111 | "subtitle": "Don't worry, we'll spam you every day!"
112 | },
113 | "password": {
114 | "type": "password",
115 | "title": "Password",
116 | "subtitle": "We didn't invest much into security, choose wisely."
117 | },
118 | "personalInfo": {
119 | "type": "object",
120 | "title": "Personal Info",
121 | "properties": {
122 | "age": {
123 | "type": "number",
124 | "title": "Age",
125 | "subtitle": "How old are you?"
126 | },
127 | "birthday": {
128 | "type": "date",
129 | "title": "Birthday",
130 | "subtitle": "So we can send you a cake, duh."
131 | },
132 | "misc": {
133 | "type": "object",
134 | "title": "Misc. Stuff",
135 | "properties": {
136 | "isScary": {
137 | "type": "boolean",
138 | "title": "Sus?",
139 | "subtitle": "Are you known by the FBI, CIA, or any governmental body?"
140 | }
141 | }
142 | },
143 | "acceptsTerms": {
144 | "type": "boolean",
145 | "title": "Accept Terms of Service",
146 | "subtitle": "We're not responsible for your actions."
147 | }
148 | }
149 | },
150 | "submit": {
151 | "type": "submit",
152 | "title": "Submit"
153 | }
154 | }
155 | }
156 | ```
157 |
158 | Input names are tokenized and have a `.` delimiter, so they can be used with HTML forms with ease.
159 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "astro-forms-monorepo",
4 | "workspaces": [
5 | "packages/*"
6 | ],
7 | "scripts": {
8 | "dev": "yarn workspace demo dev",
9 | "upload": "yarn workspace astro-forms publish"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/astro-forms/Form.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { GenericTheme } from "./themes";
3 | import { Theme, FormSchema } from "./types";
4 | import { flatten } from "./util";
5 |
6 | const { schema, action, method, classes, theme, data, redirect } = Astro.props as {
7 | schema: FormSchema;
8 | action: string;
9 | method: "post" | "get";
10 | classes: string;
11 | theme: Theme;
12 | data: Record;
13 | redirect: string;
14 | };
15 |
16 | const components: Theme = {
17 | ...GenericTheme,
18 | ...theme,
19 | };
20 |
21 | if (schema.type !== "object") {
22 | throw new Error("Initial form schema must be an object");
23 | }
24 |
25 | const flattenedData = flatten(data);
26 | ---
27 |
28 |
34 |
--------------------------------------------------------------------------------
/packages/astro-forms/README.md:
--------------------------------------------------------------------------------
1 | 🚧 **Under Development** 🚧
2 |
3 | This component is under construction! It does work, however, bugs may be present.
4 |
5 | Pull requests are appreciated!
6 |
7 | # Astro Forms
8 |
9 | A Dynamic form component for Astro.
10 |
11 | Uses a JSON schema to generate a form.
12 |
13 | ## Themes
14 |
15 | There are currently two themes available:
16 |
17 | - `default`
18 | - `tailwind` [(View README)](/packages/astro-forms/themes/tailwind/README.md)
19 |
20 | ## Usage
21 |
22 | ### Installation
23 |
24 | ```bash
25 | yarn add astro-forms
26 | ```
27 |
28 | or
29 |
30 | ```bash
31 | npm install astro-forms
32 | ```
33 |
34 | ### Setup
35 |
36 | ```astro
37 | ---
38 | import { Form } from "astro-forms";
39 | const schema = {
40 | type: "object",
41 | properties: {
42 | name: {
43 | type: "string",
44 | title: "Name",
45 | },
46 | email: {
47 | type: "string",
48 | title: "Email",
49 | },
50 | password: {
51 | type: "string",
52 | title: "Password",
53 | },
54 | submit: {
55 | type: "submit",
56 | title: "Submit",
57 | },
58 | },
59 | }; // Or whatever you want it to be, must be an object.
60 | ---
61 |
62 |
63 | ```
64 |
65 | ## Schema
66 |
67 | The JSON schema for this form component has a single type that can repeat itself.
68 |
69 | ```ts
70 | export type InputType =
71 | | "string"
72 | | "email"
73 | | "password"
74 | | "search"
75 | | "url"
76 | | "number"
77 | | "boolean"
78 | | "array"
79 | | "object"
80 | | "date"
81 | | "submit";
82 |
83 | export interface FormSchema {
84 | type: InputType;
85 | title: string;
86 | subtitle?: string;
87 | properties: {
88 | [key: string]: FormSchema;
89 | };
90 | items?: FormSchema;
91 | }
92 | ```
93 |
94 | These types may be updated and will be marked as a breaking change if done so.
95 |
96 | Schema example:
97 |
98 | ```json
99 | {
100 | "type": "object",
101 | "title": "Form",
102 | "properties": {
103 | "name": {
104 | "type": "string",
105 | "title": "Name",
106 | "subtitle": "Alphanumeric characters only!!!!"
107 | },
108 | "email": {
109 | "type": "string",
110 | "title": "Email",
111 | "subtitle": "Don't worry, we'll spam you every day!"
112 | },
113 | "password": {
114 | "type": "password",
115 | "title": "Password",
116 | "subtitle": "We didn't invest much into security, choose wisely."
117 | },
118 | "personalInfo": {
119 | "type": "object",
120 | "title": "Personal Info",
121 | "properties": {
122 | "age": {
123 | "type": "number",
124 | "title": "Age",
125 | "subtitle": "How old are you?"
126 | },
127 | "birthday": {
128 | "type": "date",
129 | "title": "Birthday",
130 | "subtitle": "So we can send you a cake, duh."
131 | },
132 | "misc": {
133 | "type": "object",
134 | "title": "Misc. Stuff",
135 | "properties": {
136 | "isScary": {
137 | "type": "boolean",
138 | "title": "Sus?",
139 | "subtitle": "Are you known by the FBI, CIA, or any governmental body?"
140 | }
141 | }
142 | },
143 | "acceptsTerms": {
144 | "type": "boolean",
145 | "title": "Accept Terms of Service",
146 | "subtitle": "We're not responsible for your actions."
147 | }
148 | }
149 | },
150 | "submit": {
151 | "type": "submit",
152 | "title": "Submit"
153 | }
154 | }
155 | }
156 | ```
157 |
158 | Input names are tokenized and have a `.` delimiter, so they can be used with HTML forms with ease.
159 |
--------------------------------------------------------------------------------
/packages/astro-forms/index.mjs:
--------------------------------------------------------------------------------
1 | export { default as Form } from "./Form.astro";
2 |
--------------------------------------------------------------------------------
/packages/astro-forms/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astro-forms",
3 | "version": "1.0.11",
4 | "description": "Forms in Astro, made easy.",
5 | "main": "index.mjs",
6 | "homepage": "https://github.com/jackmerrill/astroforms#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/jackmerrill/astroforms.git",
10 | "directory": "packages/astro-forms"
11 | },
12 | "bugs": {
13 | "url": "https://github.com/jackmerrill/astroforms/issues"
14 | },
15 | "author": "Jack Merrill",
16 | "license": "MPL-2.0",
17 | "keywords": [
18 | "astro",
19 | "forms",
20 | "jsonform"
21 | ],
22 | "dependencies": {
23 | "@tailwindcss/forms": "^0.5.2",
24 | "tailwindcss": "^3.1.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/default/ArrayInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { FormSchema } from "../../types";
3 | import GenericInput from "./GenericInput.astro";
4 |
5 | const { title, items } = Astro.props as { title: string; items: FormSchema };
6 | ---
7 |
8 |
12 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/default/BooleanInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { title, checked } = Astro.props as { title: string; checked: boolean };
3 | ---
4 |
5 |
9 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/default/DateInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { title, name } = Astro.props as { title: string; name: string };
3 | ---
4 |
5 |
9 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/default/GenericInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Theme, FormSchema } from "../../types";
3 | import { GetInput } from ".";
4 |
5 | const { schema, schemaKey, components } = Astro.props as {
6 | schema: FormSchema;
7 | schemaKey: string;
8 | components: Theme;
9 | };
10 |
11 | const Inputs = [];
12 | const InputArgs = [];
13 |
14 | if (!schema.properties) {
15 | throw new Error("No properties found in schema");
16 | }
17 |
18 | Object.entries(schema.properties).forEach(([key, value]) => {
19 | let inputKey;
20 |
21 | if (schemaKey) {
22 | inputKey = `${schemaKey}.${key}`;
23 | } else {
24 | inputKey = key;
25 | }
26 |
27 | let FormInput;
28 | let FormArgs: Record = { title: value.title, name: inputKey };
29 |
30 | FormInput = GetInput(value.type);
31 | FormArgs = {
32 | ...FormArgs,
33 | schema: value,
34 | schemaKey: key,
35 | items: value.items,
36 | components,
37 | };
38 |
39 | Inputs.push(FormInput);
40 |
41 | InputArgs.push({
42 | key,
43 | value,
44 | ...FormArgs,
45 | });
46 | });
47 | ---
48 |
49 |
50 |
{schema.title}
51 | {Inputs.map((Input, index) => )}
52 |
53 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/default/NumberInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { title, name } = Astro.props as { title: string; name: string };
3 | ---
4 |
5 |
9 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/default/StringInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { title, name } = Astro.props as { title: string; name: string };
3 | ---
4 |
5 |
9 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/default/Submit.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { title } = Astro.props as { title: string };
3 | ---
4 |
5 |
6 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/default/index.ts:
--------------------------------------------------------------------------------
1 | import { InputType } from "../../types";
2 | import StringInput from "./StringInput.astro";
3 | import BooleanInput from "./BooleanInput.astro";
4 | import ArrayInput from "./ArrayInput.astro";
5 | import GenericInput from "./GenericInput.astro";
6 | import DateInput from "./DateInput.astro";
7 | import NumberInput from "./NumberInput.astro";
8 | import Submit from "./Submit.astro";
9 |
10 | export function GetInput(type: InputType) {
11 | switch (type) {
12 | case "string":
13 | return StringInput;
14 | case "number":
15 | return NumberInput;
16 | case "date":
17 | return DateInput;
18 | case "boolean":
19 | return BooleanInput;
20 | case "array":
21 | return ArrayInput;
22 | case "object":
23 | return GenericInput;
24 | case "submit":
25 | return Submit;
26 | default:
27 | return StringInput;
28 | }
29 | }
30 |
31 | export default {
32 | String: StringInput,
33 | Boolean: BooleanInput,
34 | Array: ArrayInput,
35 | Generic: GenericInput,
36 | Date: DateInput,
37 | Number: NumberInput,
38 | Submit: Submit,
39 | };
40 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/index.ts:
--------------------------------------------------------------------------------
1 | import GenericTheme from "./default";
2 |
3 | export { GenericTheme };
4 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/ArrayInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | // THIS IS VERY EXPERIMENTAL.
3 | // IT IS NOT RECOMMENDED TO USE THIS IN PRODUCTION.
4 | // YOU CURRENTLY CANNOT ADD NEW INPUTS.
5 |
6 | import { GetInput } from ".";
7 | import { FormSchema } from "../../types";
8 | import InputLayout from "./InputLayout.astro";
9 |
10 | const { schema, name, data } = Astro.props as { schema: FormSchema; name: string, data: any };
11 |
12 | const Input = GetInput(schema.items.type);
13 |
14 | const arrayData = Object.entries(data).map(([key, value]) => {
15 | if (key.includes(name)) {
16 | return value;
17 | }
18 | }).filter(Boolean);
19 | ---
20 |
21 |
33 |
34 |
35 |
38 |
39 | {arrayData.map((value, index) => (
40 |
41 | ))}
42 |
43 |
47 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/BooleanInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { FormSchema } from "../../types";
3 | import InputLayout from "./InputLayout.astro";
4 |
5 | const { schema, name, value } = Astro.props as { schema: FormSchema; name: string, value: any };
6 | ---
7 |
8 |
9 |
11 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/DateInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { FormSchema } from "../../types";
3 | import InputLayout from "./InputLayout.astro";
4 |
5 | const { schema, name, value } = Astro.props as { schema: FormSchema; name: string, value: any };
6 | ---
7 |
8 |
9 |
11 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/GenericInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Theme, FormSchema } from "../../types";
3 | import { GetInput } from ".";
4 |
5 | const { schema, schemaKey, components, data } = Astro.props as {
6 | schema: FormSchema;
7 | schemaKey: string;
8 | components: Theme;
9 | data: Record;
10 | };
11 |
12 | const Inputs = [];
13 | const InputArgs = [];
14 |
15 | if (!schema.properties) {
16 | if (schema.type !== 'array') {
17 | throw new Error("No properties found in schema");
18 | }
19 |
20 | if (!schema.items) {
21 | throw new Error("No items found in array schema");
22 | }
23 |
24 | Inputs.push(components.Array)
25 | InputArgs.push({
26 | schema: schema.items,
27 | schemaKey: schemaKey,
28 | components,
29 | data
30 | })
31 | } else {
32 | Object.entries(schema.properties).forEach(([key, value]) => {
33 | let inputKey;
34 |
35 | if (schemaKey) {
36 | inputKey = `${schemaKey}.${key}`;
37 | } else {
38 | inputKey = key;
39 | }
40 |
41 | let FormInput;
42 | let FormArgs: Record = { title: value.title, name: inputKey };
43 |
44 | FormInput = GetInput(value.type);
45 | FormArgs = {
46 | ...FormArgs,
47 | schema: value,
48 | schemaKey: key,
49 | items: value.items,
50 | components,
51 | subtitle: value.subtitle,
52 | data,
53 | value: data[inputKey]
54 | };
55 |
56 | Inputs.push(FormInput);
57 |
58 | InputArgs.push({
59 | key,
60 | value,
61 | ...FormArgs,
62 | });
63 | });
64 |
65 | }
66 |
67 | ---
68 |
69 |
70 |
{schema.title}
71 | {Inputs.map((Input, index) => )}
72 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/InputLayout.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { FormSchema } from "../../types";
3 |
4 | const { schema, name } = Astro.props as { schema: FormSchema; name: string };
5 | ---
6 |
7 |
8 |
10 |
11 |
12 |
13 | {schema.subtitle && (
14 |
15 | {schema.subtitle}
16 |
17 | )}
18 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/NumberInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { FormSchema } from "../../types";
3 | import InputLayout from "./InputLayout.astro";
4 |
5 | const { schema, name, value } = Astro.props as { schema: FormSchema; name: string, value: any };
6 | ---
7 |
8 |
9 |
11 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/README.md:
--------------------------------------------------------------------------------
1 | # Tailwind Theme
2 |
3 | Prerequisites:
4 |
5 | - [Tailwind CSS](https://tailwindcss.com) v3 or greater
6 | - [@tailwindcss/forms](https://github.com/tailwindlabs/tailwindcss-forms) plugin
7 |
8 | Usage:
9 |
10 | ```astro
11 | ---
12 | import tailwind from "astro-forms/themes/tailwind";
13 | import Form from "../components/Form/Form.astro";
14 | ---
15 |
16 |
17 | ```
18 |
19 | ## Important
20 |
21 | Make sure your Tailwind config file has the following:
22 |
23 | ```js
24 | module.exports = {
25 | content: [
26 | "./src/**/*.{astro,html,js,jsx,md,svelte,ts,tsx,vue}",
27 | "./node_modules/astro-forms/themes/tailwind/*.astro",
28 | ],
29 | theme: {
30 | extend: {},
31 | },
32 | plugins: [],
33 | };
34 | ```
35 |
36 | You can either add the `@tailwindcss/forms` plugin to your Tailwind config file, or you may import the Tailwind config from the package.
37 |
38 | ```js
39 | module.exports = {
40 | content: [
41 | "./src/**/*.{astro,html,js,jsx,md,svelte,ts,tsx,vue}",
42 | "./node_modules/astro-forms/themes/tailwind/*.astro",
43 | ],
44 | theme: {
45 | extend: {},
46 | },
47 | plugins: [require("@tailwindcss/forms")],
48 | };
49 |
50 | // Or
51 |
52 | module.exports = {
53 | presets: [require("astro-forms/themes/tailwind/tailwind.config.cjs")],
54 | content: [
55 | "./src/**/*.{astro,html,js,jsx,md,svelte,ts,tsx,vue}",
56 | "./node_modules/astro-forms/themes/tailwind/*.astro",
57 | ],
58 | theme: {
59 | extend: {},
60 | },
61 | plugins: [],
62 | };
63 | ```
64 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/StringInput.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { FormSchema } from "../../types";
3 | import InputLayout from "./InputLayout.astro";
4 |
5 | const { title, name, schema, value } = Astro.props as {
6 | title: string;
7 | name: string;
8 | schema: FormSchema;
9 | value: any;
10 | };
11 |
12 | const getInputType = () => {
13 | switch (schema.type) {
14 | case "string":
15 | return "text";
16 | case "password":
17 | return "password";
18 | case "email":
19 | return "email";
20 | case "search":
21 | return "search";
22 | case "url":
23 | return "url";
24 | default:
25 | return "text";
26 | }
27 | };
28 | ---
29 |
30 |
31 |
34 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/Submit.astro:
--------------------------------------------------------------------------------
1 | ---
2 | const { title } = Astro.props as { title: string };
3 | ---
4 |
5 |
10 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/index.ts:
--------------------------------------------------------------------------------
1 | import { InputType } from "../../types";
2 | import StringInput from "./StringInput.astro";
3 | import BooleanInput from "./BooleanInput.astro";
4 | import ArrayInput from "./ArrayInput.astro";
5 | import GenericInput from "./GenericInput.astro";
6 | import DateInput from "./DateInput.astro";
7 | import NumberInput from "./NumberInput.astro";
8 | import Submit from "./Submit.astro";
9 |
10 | export function GetInput(type: InputType) {
11 | switch (type) {
12 | case "string":
13 | return StringInput;
14 | case "password":
15 | return StringInput;
16 | case "email":
17 | return StringInput;
18 | case "number":
19 | return NumberInput;
20 | case "date":
21 | return DateInput;
22 | case "boolean":
23 | return BooleanInput;
24 | case "array":
25 | return ArrayInput;
26 | case "object":
27 | return GenericInput;
28 | case "submit":
29 | return Submit;
30 | default:
31 | return StringInput;
32 | }
33 | }
34 |
35 | export default {
36 | String: StringInput,
37 | Boolean: BooleanInput,
38 | Array: ArrayInput,
39 | Generic: GenericInput,
40 | Date: DateInput,
41 | Number: NumberInput,
42 | Submit: Submit,
43 | };
44 |
--------------------------------------------------------------------------------
/packages/astro-forms/themes/tailwind/tailwind.config.cjs:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ["./*.{astro,html,js,jsx,md,svelte,ts,tsx,vue}"],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [require("@tailwindcss/forms")],
8 | };
9 |
--------------------------------------------------------------------------------
/packages/astro-forms/types.ts:
--------------------------------------------------------------------------------
1 | export type InputType =
2 | | "string"
3 | | "email"
4 | | "password"
5 | | "search"
6 | | "url"
7 | | "number"
8 | | "boolean"
9 | | "array"
10 | | "object"
11 | | "date"
12 | | "submit";
13 |
14 | export type Input = string | number | boolean | Array | object | Date;
15 |
16 | export interface FormSchema {
17 | type: InputType;
18 | title: string;
19 | subtitle?: string;
20 | properties: {
21 | [key: string]: FormSchema;
22 | };
23 | items?: FormSchema;
24 | }
25 |
26 | export interface Theme {
27 | String: any;
28 | Boolean: any;
29 | Array: any;
30 | Generic: any;
31 | Date: any;
32 | Number: any;
33 | Submit: any;
34 | }
35 |
--------------------------------------------------------------------------------
/packages/astro-forms/util.ts:
--------------------------------------------------------------------------------
1 | export function flatten(data) {
2 | var result = {};
3 | function recurse(cur, prop) {
4 | if (Object(cur) !== cur) {
5 | result[prop] = cur;
6 | } else if (Array.isArray(cur)) {
7 | for (var i = 0, l = cur.length; i < l; i++)
8 | recurse(cur[i], prop + "[" + i + "]");
9 | if (l == 0) result[prop] = [];
10 | } else {
11 | var isEmpty = true;
12 | for (var p in cur) {
13 | isEmpty = false;
14 | recurse(cur[p], prop ? prop + "." + p : p);
15 | }
16 | if (isEmpty && prop) result[prop] = {};
17 | }
18 | }
19 | recurse(data, "");
20 | return result;
21 | }
22 |
--------------------------------------------------------------------------------
/packages/demo/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "astro/config";
2 |
3 | import tailwind from "@astrojs/tailwind";
4 |
5 | // https://astro.build/config
6 | export default defineConfig({
7 | integrations: [tailwind()],
8 | });
9 |
--------------------------------------------------------------------------------
/packages/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "version": "0.0.1",
4 | "private": false,
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview"
10 | },
11 | "devDependencies": {
12 | "@astrojs/tailwind": "^0.2.2",
13 | "@babel/core": "^7.18.6",
14 | "@babel/helper-validator-identifier": "7.18.6",
15 | "@babel/preset-env": "^7.18.6",
16 | "@babel/types": "^7.18.6",
17 | "astro": "^1.0.0-beta.64",
18 | "prettier": "^2.7.1",
19 | "prettier-plugin-astro": "^0.1.1"
20 | },
21 | "dependencies": {
22 | "astro-forms": "^1.0.6"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/demo/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jackmerrill/AstroForms/12d103b231265108f99634680c5c69fdc52a89df/packages/demo/public/favicon.ico
--------------------------------------------------------------------------------
/packages/demo/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import schema, { sampleData } from "../util/schema";
3 | import { Form } from "../../../astro-forms";
4 | import tailwind from "../../../astro-forms/themes/tailwind";
5 |
6 | ---
7 |
8 |
9 |
10 |
11 |
12 |
13 | Astro Forms
14 |
15 |
16 |
17 |
18 |
19 | Astro Forms Example (TailwindCSS)
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/packages/demo/src/util/schema.ts:
--------------------------------------------------------------------------------
1 | export default JSON.parse(`
2 | {
3 | "type": "object",
4 | "title": "Form",
5 | "properties": {
6 | "name": {
7 | "type": "string",
8 | "title": "Name",
9 | "subtitle": "Alphanumeric characters only!!!!"
10 | },
11 | "email": {
12 | "type": "string",
13 | "title": "Email",
14 | "subtitle": "Don't worry, we'll spam you every day!"
15 | },
16 | "password": {
17 | "type": "password",
18 | "title": "Password",
19 | "subtitle": "We didn't invest much into security, choose wisely."
20 | },
21 | "personalInfo": {
22 | "type": "object",
23 | "title": "Personal Info",
24 | "properties": {
25 | "age": {
26 | "type": "number",
27 | "title": "Age",
28 | "subtitle": "How old are you?"
29 | },
30 | "birthday": {
31 | "type": "date",
32 | "title": "Birthday",
33 | "subtitle": "So we can send you a cake, duh."
34 | },
35 | "scaryStuff": {
36 | "type": "object",
37 | "title": "Scary Stuff",
38 | "properties": {
39 | "isScary": {
40 | "type": "boolean",
41 | "title": "Is Scary?",
42 | "subtitle": "Are you really scary?"
43 | }
44 | }
45 | },
46 | "acceptsTerms": {
47 | "type": "boolean",
48 | "title": "Accept Terms of Service",
49 | "subtitle": "We're not responsible for your actions."
50 | }
51 | }
52 | },
53 | "randomArray": {
54 | "type": "array",
55 | "title": "Random Array",
56 | "subtitle": "This is a random array, don't worry about it.",
57 | "items": {
58 | "type": "string"
59 | }
60 | },
61 | "arrayOfObjects": {
62 | "type": "array",
63 | "title": "Array of Objects",
64 | "subtitle": "This is an array of objects, don't worry about it.",
65 | "items": {
66 | "type": "object",
67 | "properties": {
68 | "key": {
69 | "type": "string",
70 | "title": "Key"
71 | },
72 | "value": {
73 | "type": "string",
74 | "title": "Value"
75 | }
76 | }
77 | }
78 | },
79 | "submit": {
80 | "type": "submit",
81 | "title": "Submit"
82 | }
83 | }
84 | }
85 | `);
86 |
87 | export const sampleData = {
88 | name: "John Doe",
89 | email: "johndoe@email.com",
90 | password: "123456",
91 | personalInfo: {
92 | age: 30,
93 | birthday: "2020-01-01",
94 | scaryStuff: {
95 | isScary: true,
96 | },
97 | acceptsTerms: true,
98 | },
99 | randomArray: ["a", "b", "c", "d", "e"],
100 | arrayOfObjects: [
101 | {
102 | key: "a",
103 | value: "A",
104 | },
105 | {
106 | key: "b",
107 | value: "B",
108 | },
109 | ],
110 | };
111 |
--------------------------------------------------------------------------------
/packages/demo/tailwind.config.cjs:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{astro,html,js,jsx,md,svelte,ts,tsx,vue}",
5 | "./node_modules/astro-forms/**/*.{astro,html,js,jsx,md,svelte,ts,tsx,vue}",
6 | "../astro-forms/**/*.{astro,html,js,jsx,md,svelte,ts,tsx,vue}",
7 | ],
8 | theme: {
9 | extend: {},
10 | },
11 | plugins: [require("@tailwindcss/forms")],
12 | };
13 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | // Enable top-level await, and other modern ESM features.
4 | "target": "ESNext",
5 | "module": "ESNext",
6 | // Enable node-style module resolution, for things like npm package imports.
7 | "moduleResolution": "node",
8 | // Enable JSON imports.
9 | "resolveJsonModule": true,
10 | // Enable stricter transpilation for better output.
11 | "isolatedModules": true,
12 | // Add type definitions for our Vite runtime.
13 | "types": ["vite/client"]
14 | }
15 | }
16 |
--------------------------------------------------------------------------------