Skip to content

Commit c5f9337

Browse files
committed
feat: add "clean" sources + misc files
1 parent 7bc1787 commit c5f9337

16 files changed

+3038
-5
lines changed

LICENSE

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
ISC License
2+
3+
Copyright (c) 2023 Julian Cataldo — https://www.juliancataldo.com
4+
5+
Permission to use, copy, modify, and/or distribute this software for any
6+
purpose with or without fee is hereby granted, provided that the above
7+
copyright notice and this permission notice appear in all copies.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15+
PERFORMANCE OF THIS SOFTWARE.

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,21 @@ See also the [inspirations](#acknowledgements) for this project.
1919
2020
![](https://ik.imagekit.io/jc0/jsfe/design/header_json-schema-form-element_2RpVU_W-y-.png?updatedAt=1695289194993)
2121

22-
<div align="center"><a href="https://jsfe.netlify.app" >🕹️ Open the playground</a></div>
22+
<div align="center">
23+
<h4><a href="https://jsfe.netlify.app" >🕹️ Open the playground</a></h4>
24+
25+
---
26+
27+
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/json-schema-form-element/examples)
28+
29+
</div>
2330

2431
---
2532

2633
<div align="center">
2734

2835
Jump to **implementations**:
29-
[TypeScript](#typescript-no-framework)
36+
[TypeScript only](#typescript-no-framework)
3037
[Astro (SSR)](#astro-ssr)
3138
[Lit](#lit)
3239
[Solid](#solid)

lib/components/alternate.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type { JSONSchema7 } from 'json-schema';
2+
import type { Jsf, Path, UiSchema } from '../json-schema-form.js';
3+
import { html } from 'lit';
4+
import { flag } from './callout.js';
5+
6+
import '@shoelace-style/shoelace/dist/components/select/select.js';
7+
import '@shoelace-style/shoelace/dist/components/option/option.js';
8+
9+
// NOTE: Experimental!
10+
export const alternateField = (
11+
schema: JSONSchema7,
12+
data: any,
13+
path: Path,
14+
uiState: any,
15+
uiSchema: UiSchema,
16+
handleChange: Jsf['_handleChange'],
17+
dig: Jsf['_dig'],
18+
updateUi: Jsf['_updateUi'],
19+
) => {
20+
if (typeof schema.oneOf !== 'object' && typeof schema.anyOf !== 'object')
21+
return flag('Wrong alternate field');
22+
23+
return html` <!-- -->
24+
<fieldset part="alternate">
25+
<!-- -->
26+
${JSON.stringify(path)} ${JSON.stringify(uiState?.alternative)}
27+
<sl-select
28+
value=${0}
29+
@sl-change=${(e: Event) => {
30+
handleChange([...path], {});
31+
updateUi(
32+
[...path, 'alternative'],
33+
Number((e.target as HTMLSelectElement)?.value),
34+
);
35+
}}
36+
>
37+
${(schema.oneOf || schema.anyOf || []).map((prop, index) => {
38+
if (typeof prop === 'boolean') return flag('Missing object input');
39+
40+
return html`
41+
<sl-option value=${index}
42+
>${prop.title ?? `Option ${index + 1}`}</sl-option
43+
>
44+
`;
45+
})}
46+
</sl-select>
47+
<div>
48+
${(schema.oneOf || schema.anyOf)?.map((prop, index) => {
49+
if (typeof prop === 'boolean') return flag('Missing object input');
50+
return html` <div
51+
.hidden=${uiState.alternative
52+
? uiState.alternative !== index
53+
: index !== 0}
54+
>
55+
${dig(prop, data[index], [...path], uiState, uiSchema)}
56+
</div>`;
57+
})}
58+
</div>
59+
</fieldset>`;
60+
};

lib/components/array.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import type { JSONSchema7 } from 'json-schema';
2+
import { html } from 'lit';
3+
4+
import '@shoelace-style/shoelace/dist/components/button/button.js';
5+
import '@shoelace-style/shoelace/dist/components/card/card.js';
6+
import '@shoelace-style/shoelace/dist/components/icon/icon.js';
7+
import '@shoelace-style/shoelace/dist/components/tag/tag.js';
8+
import '@shoelace-style/shoelace/dist/components/divider/divider.js';
9+
import '@shoelace-style/shoelace/dist/components/button-group/button-group.js';
10+
import '@shoelace-style/shoelace/dist/components/tooltip/tooltip.js';
11+
12+
import type { Jsf, Path, UiSchema } from '../json-schema-form.js';
13+
14+
export const arrayField = (
15+
schema: JSONSchema7,
16+
dataLevel: any[],
17+
path: Path,
18+
uiState: any,
19+
uiSchema: UiSchema,
20+
handleChange: Jsf['_handleChange'],
21+
dig: Jsf['_dig'],
22+
) => {
23+
return html` <!-- -->
24+
<fieldset part="array">
25+
<!-- -->
26+
<legend>${schema.title}</legend>
27+
${dataLevel?.map?.((_item, index) => {
28+
if (typeof schema.items !== 'object' || Array.isArray(schema.items))
29+
return;
30+
return html` <sl-card>
31+
${dig(
32+
schema.items,
33+
dataLevel[index],
34+
[...path, String(index)],
35+
uiState,
36+
uiSchema,
37+
)}
38+
39+
<div slot="header" class="array-card-header">
40+
<div>
41+
<sl-tag size="medium" pill>${index + 1}</sl-tag>
42+
</div>
43+
<div class="handle">
44+
<sl-icon name="grip-horizontal" label="Settings"></sl-icon>
45+
</div>
46+
<div>
47+
<sl-tooltip content="Delete">
48+
<sl-button
49+
size="small"
50+
@click=${(_event: Event) => {
51+
dataLevel = dataLevel.filter((_, i) => i !== index);
52+
handleChange([...path], dataLevel);
53+
}}
54+
>
55+
<sl-icon name="trash3" label="Settings"></sl-icon>
56+
</sl-button>
57+
</sl-tooltip>
58+
59+
<sl-divider vertical></sl-divider>
60+
61+
<sl-button-group>
62+
<sl-button
63+
size="small"
64+
@click=${(_event: Event) => {
65+
const hold = dataLevel[index];
66+
dataLevel[index] = dataLevel[index - 1];
67+
dataLevel[index - 1] = hold;
68+
handleChange([...path], dataLevel);
69+
}}
70+
.disabled=${typeof dataLevel?.[index - 1] === 'undefined'}
71+
>
72+
<sl-icon name="arrow-up" label="Up"></sl-icon>
73+
</sl-button>
74+
<sl-button
75+
size="small"
76+
@click=${(_event: Event) => {
77+
const hold = dataLevel[index];
78+
79+
dataLevel[index] = dataLevel[index + 1];
80+
dataLevel[index + 1] = hold;
81+
handleChange([...path], dataLevel);
82+
}}
83+
.disabled=${typeof dataLevel?.[index + 1] === 'undefined'}
84+
>
85+
<sl-icon name="arrow-down" label="Down"></sl-icon>
86+
</sl-button>
87+
</sl-button-group>
88+
</div>
89+
</div>
90+
</sl-card>`;
91+
})}
92+
93+
<div class="add-zone">
94+
<sl-button
95+
@click=${(_event: Event) => {
96+
dataLevel ||= [];
97+
98+
if (typeof schema.items !== 'object' || Array.isArray(schema.items))
99+
return;
100+
if (schema.items?.type === 'string') {
101+
dataLevel.push(schema.items?.default || '');
102+
} else if (schema.items.properties) {
103+
dataLevel.push(schema.items?.default || {});
104+
}
105+
106+
handleChange([...path], dataLevel);
107+
}}
108+
size="large"
109+
>
110+
<sl-icon name="plus"></sl-icon> Add
111+
</sl-button>
112+
</div>
113+
</fieldset>`;
114+
};

lib/components/callout.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { html } from 'lit';
2+
import { classMap } from 'lit/directives/class-map.js';
3+
4+
export const error = (
5+
message: string,
6+
type: 'tip' | 'warning' | 'danger' = 'danger',
7+
) => {
8+
console.error(message);
9+
return html`
10+
<div
11+
role="alert"
12+
class=${classMap({
13+
callout: true,
14+
[`callout--${type}`]: true,
15+
})}
16+
>
17+
<p>${message}</p>
18+
</div>
19+
`;
20+
};
21+
22+
export const flag = (feature: string) => {
23+
const message = `\`${feature}\` is not supported yet, but you can preview it with \`experimental = { ${feature}: true, ... }\``;
24+
console.error(message);
25+
return html`
26+
<div
27+
role="alert"
28+
class=${classMap({
29+
callout: true,
30+
[`callout--danger`]: true,
31+
})}
32+
>
33+
<p>${message}</p>
34+
</div>
35+
`;
36+
};

0 commit comments

Comments
 (0)