@duskmoon-dev/components 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -3
- package/dist/components/dm-pro-table/index.js +12 -0
- package/dist/components/dm-query/index.js +12 -0
- package/dist/components/dm-search/index.js +12 -0
- package/dist/components/dm-table/index.js +12 -0
- package/dist/components/json-schema-form/JsonSchemaForm.d.ts +19 -0
- package/dist/components/json-schema-form/JsonSchemaWidget.d.ts +14 -0
- package/dist/components/json-schema-form/index.d.ts +8 -0
- package/dist/components/json-schema-form/index.js +7661 -0
- package/dist/components/json-schema-form/json-form-widgets.d.ts +26 -0
- package/dist/components/json-schema-form/json-schema-form.d.ts +50 -0
- package/dist/components/select/index.js +12 -0
- package/dist/generated/version.d.ts +1 -1
- package/dist/index.js +13 -1
- package/dist/infrastructure.js +1 -1
- package/dist/styles.css +220 -10
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ import { Button, DmTable, theme } from "@duskmoon-dev/components";
|
|
|
41
41
|
|
|
42
42
|
## Public Surface
|
|
43
43
|
|
|
44
|
-
-
|
|
44
|
+
- 79 standard components such as `Button`, `Chat`, `OtpInput`, `Swap`, `Fab`,
|
|
45
45
|
`Megamenu`, `ConsolePage`, `Table`, `Modal`, `Select`, and `Typography`.
|
|
46
46
|
- 21 DuskMoon workflow components such as `DmLayout`, `DmSearch`, `DmTable`,
|
|
47
47
|
`DmProTable`, and `DmToolbar`.
|
|
@@ -90,10 +90,14 @@ export function Conversation() {
|
|
|
90
90
|
<Chat.Bubble>The build passed.</Chat.Bubble>
|
|
91
91
|
<Chat.Status>
|
|
92
92
|
<Chat.StatusItem>Completed</Chat.StatusItem>
|
|
93
|
-
<Chat.StatusItem
|
|
93
|
+
<Chat.StatusItem>
|
|
94
|
+
<Chat.StatusValue>42</Chat.StatusValue> token/s
|
|
95
|
+
</Chat.StatusItem>
|
|
94
96
|
</Chat.Status>
|
|
95
97
|
<Chat.Actions hover>
|
|
96
|
-
<button type="button" onClick={copyReply}>
|
|
98
|
+
<button type="button" onClick={copyReply}>
|
|
99
|
+
Copy reply
|
|
100
|
+
</button>
|
|
97
101
|
</Chat.Actions>
|
|
98
102
|
</Chat>
|
|
99
103
|
</Chat.ScrollBody>
|
|
@@ -124,3 +128,80 @@ bun run typecheck
|
|
|
124
128
|
# Check parity manifest coverage
|
|
125
129
|
bun run parity:components
|
|
126
130
|
```
|
|
131
|
+
|
|
132
|
+
## JSON Schema forms
|
|
133
|
+
|
|
134
|
+
`@duskmoon-dev/components/json-schema-form` exports `JsonSchemaForm`,
|
|
135
|
+
`compileForm`, `JsonSchemaWidget`, and the `RenderableSchema`, `CompiledForm`,
|
|
136
|
+
`FormValue`, `JsonValue`, `FormErrors`, `FormValidationResult`,
|
|
137
|
+
`JsonSchemaFormProps`, `JsonSchemaWidgetProps`, and widget contract types.
|
|
138
|
+
Ajv and ajv-formats are installed as package runtime dependencies. The package
|
|
139
|
+
stylesheet includes the renderer layout. Import these APIs from the explicit
|
|
140
|
+
subpath; schema compilation is kept separate from the root component bundle.
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
import { useState } from "react";
|
|
144
|
+
import "@duskmoon-dev/components/styles.css";
|
|
145
|
+
import {
|
|
146
|
+
JsonSchemaForm,
|
|
147
|
+
type FormErrors,
|
|
148
|
+
type FormValue,
|
|
149
|
+
type RenderableSchema,
|
|
150
|
+
} from "@duskmoon-dev/components/json-schema-form";
|
|
151
|
+
|
|
152
|
+
const schema: RenderableSchema = {
|
|
153
|
+
type: "object",
|
|
154
|
+
required: ["name"],
|
|
155
|
+
properties: {
|
|
156
|
+
name: { type: "string", title: "Name", minLength: 1 },
|
|
157
|
+
age: { type: "integer", title: "Age", minimum: 0 },
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export function ProfileIsland({ send }: { send: (value: FormValue) => void }) {
|
|
162
|
+
const [value, setValue] = useState<FormValue>({ name: "Ada" });
|
|
163
|
+
const [errors, setErrors] = useState<FormErrors>({});
|
|
164
|
+
return (
|
|
165
|
+
<JsonSchemaForm
|
|
166
|
+
schema={schema}
|
|
167
|
+
value={value}
|
|
168
|
+
onChange={setValue}
|
|
169
|
+
errors={errors}
|
|
170
|
+
onErrorsChange={setErrors}
|
|
171
|
+
onSubmit={send}
|
|
172
|
+
/>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Mount the React root inside a LiveView element with a stable `id` and
|
|
178
|
+
`phx-update="ignore"`. Parse the backend's schema JSON and call `compileForm`
|
|
179
|
+
when accepting untrusted input; catch compilation errors before rendering.
|
|
180
|
+
Pass the returned object as `compiled` instead of `schema` to compile once.
|
|
181
|
+
Send the validated object from `onSubmit` through the island's LiveView hook;
|
|
182
|
+
backend validation is still required. Use a new React `key` when replacing a
|
|
183
|
+
schema and starting a fresh form.
|
|
184
|
+
|
|
185
|
+
`value` and `onChange` control values. Omit `value` for internal state, optionally
|
|
186
|
+
seeded by `defaultValue`. Reset restores `defaultValue` or schema defaults,
|
|
187
|
+
notifies `onChange`, clears validation errors, and calls `onReset`. Backend
|
|
188
|
+
`errors` merge with local errors and use escaped JSON Pointer keys such as
|
|
189
|
+
`/address/email` (the empty key denotes a form error). Clear backend errors in
|
|
190
|
+
`onErrorsChange`, which receives an empty object on edits/reset and validation
|
|
191
|
+
errors on submission. `onSubmit` runs only for valid values and receives a
|
|
192
|
+
copied JSON object with numbers and booleans preserved.
|
|
193
|
+
|
|
194
|
+
The supported schema is a strict JSON Schema draft 2020-12 subset: object roots,
|
|
195
|
+
nested objects, homogeneous arrays, primitive fields/enums/defaults, required
|
|
196
|
+
fields, `additionalProperties: false`, string constraints/formats, numeric
|
|
197
|
+
constraints, and array/object size constraints. References, combinators,
|
|
198
|
+
nullable types, and arbitrary keywords are rejected. Validation does not coerce,
|
|
199
|
+
remove, or default submitted values.
|
|
200
|
+
|
|
201
|
+
Use `x-widget` for explicit component selection, `x-options` for typed option
|
|
202
|
+
labels/hierarchies, and `x-widget-options` for orientation, length, count,
|
|
203
|
+
allowHalf, min, max, and step where supported. `widgetNames`, `WidgetName`,
|
|
204
|
+
`WidgetOption`, `WidgetConfig`, and `OrientationWidgetConfig` expose this
|
|
205
|
+
contract; `compileForm` checks widget/type/config compatibility. Upload widgets
|
|
206
|
+
submit JSON file metadata (`name`, `size`, `type`, `lastModified`), with file
|
|
207
|
+
transfer owned by the application.
|
|
@@ -2142,11 +2142,17 @@ var OptGroup = forwardRef6(({ children, ...props }, ref) => /* @__PURE__ */ jsx8
|
|
|
2142
2142
|
OptGroup.displayName = "Select.OptGroup";
|
|
2143
2143
|
var SelectRoot = forwardRef6(({
|
|
2144
2144
|
allowClear,
|
|
2145
|
+
"aria-describedby": ariaDescribedBy,
|
|
2146
|
+
"aria-errormessage": ariaErrorMessage,
|
|
2147
|
+
"aria-invalid": ariaInvalid,
|
|
2148
|
+
"aria-label": ariaLabel,
|
|
2149
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2145
2150
|
children,
|
|
2146
2151
|
className,
|
|
2147
2152
|
defaultValue,
|
|
2148
2153
|
disabled,
|
|
2149
2154
|
filterOption,
|
|
2155
|
+
id,
|
|
2150
2156
|
loading,
|
|
2151
2157
|
mode,
|
|
2152
2158
|
onChange,
|
|
@@ -2269,8 +2275,14 @@ var SelectRoot = forwardRef6(({
|
|
|
2269
2275
|
children: [
|
|
2270
2276
|
/* @__PURE__ */ jsxs7("button", {
|
|
2271
2277
|
type: "button",
|
|
2278
|
+
id,
|
|
2272
2279
|
className: getSelectClasses({ size, status, disabled }),
|
|
2273
2280
|
disabled: disabled || loading,
|
|
2281
|
+
"aria-describedby": ariaDescribedBy,
|
|
2282
|
+
"aria-errormessage": ariaErrorMessage,
|
|
2283
|
+
"aria-invalid": ariaInvalid,
|
|
2284
|
+
"aria-label": ariaLabel,
|
|
2285
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2274
2286
|
"aria-haspopup": "listbox",
|
|
2275
2287
|
"aria-expanded": open,
|
|
2276
2288
|
onClick: () => setOpen((current) => !current),
|
|
@@ -1640,11 +1640,17 @@ var OptGroup = forwardRef4(({ children, ...props }, ref) => /* @__PURE__ */ jsx5
|
|
|
1640
1640
|
OptGroup.displayName = "Select.OptGroup";
|
|
1641
1641
|
var SelectRoot = forwardRef4(({
|
|
1642
1642
|
allowClear,
|
|
1643
|
+
"aria-describedby": ariaDescribedBy,
|
|
1644
|
+
"aria-errormessage": ariaErrorMessage,
|
|
1645
|
+
"aria-invalid": ariaInvalid,
|
|
1646
|
+
"aria-label": ariaLabel,
|
|
1647
|
+
"aria-labelledby": ariaLabelledBy,
|
|
1643
1648
|
children,
|
|
1644
1649
|
className,
|
|
1645
1650
|
defaultValue,
|
|
1646
1651
|
disabled,
|
|
1647
1652
|
filterOption,
|
|
1653
|
+
id,
|
|
1648
1654
|
loading,
|
|
1649
1655
|
mode,
|
|
1650
1656
|
onChange,
|
|
@@ -1767,8 +1773,14 @@ var SelectRoot = forwardRef4(({
|
|
|
1767
1773
|
children: [
|
|
1768
1774
|
/* @__PURE__ */ jsxs5("button", {
|
|
1769
1775
|
type: "button",
|
|
1776
|
+
id,
|
|
1770
1777
|
className: getSelectClasses({ size, status, disabled }),
|
|
1771
1778
|
disabled: disabled || loading,
|
|
1779
|
+
"aria-describedby": ariaDescribedBy,
|
|
1780
|
+
"aria-errormessage": ariaErrorMessage,
|
|
1781
|
+
"aria-invalid": ariaInvalid,
|
|
1782
|
+
"aria-label": ariaLabel,
|
|
1783
|
+
"aria-labelledby": ariaLabelledBy,
|
|
1772
1784
|
"aria-haspopup": "listbox",
|
|
1773
1785
|
"aria-expanded": open,
|
|
1774
1786
|
onClick: () => setOpen((current) => !current),
|
|
@@ -1632,11 +1632,17 @@ var OptGroup = forwardRef4(({ children, ...props }, ref) => /* @__PURE__ */ jsx5
|
|
|
1632
1632
|
OptGroup.displayName = "Select.OptGroup";
|
|
1633
1633
|
var SelectRoot = forwardRef4(({
|
|
1634
1634
|
allowClear,
|
|
1635
|
+
"aria-describedby": ariaDescribedBy,
|
|
1636
|
+
"aria-errormessage": ariaErrorMessage,
|
|
1637
|
+
"aria-invalid": ariaInvalid,
|
|
1638
|
+
"aria-label": ariaLabel,
|
|
1639
|
+
"aria-labelledby": ariaLabelledBy,
|
|
1635
1640
|
children,
|
|
1636
1641
|
className,
|
|
1637
1642
|
defaultValue,
|
|
1638
1643
|
disabled,
|
|
1639
1644
|
filterOption,
|
|
1645
|
+
id,
|
|
1640
1646
|
loading,
|
|
1641
1647
|
mode,
|
|
1642
1648
|
onChange,
|
|
@@ -1759,8 +1765,14 @@ var SelectRoot = forwardRef4(({
|
|
|
1759
1765
|
children: [
|
|
1760
1766
|
/* @__PURE__ */ jsxs5("button", {
|
|
1761
1767
|
type: "button",
|
|
1768
|
+
id,
|
|
1762
1769
|
className: getSelectClasses({ size, status, disabled }),
|
|
1763
1770
|
disabled: disabled || loading,
|
|
1771
|
+
"aria-describedby": ariaDescribedBy,
|
|
1772
|
+
"aria-errormessage": ariaErrorMessage,
|
|
1773
|
+
"aria-invalid": ariaInvalid,
|
|
1774
|
+
"aria-label": ariaLabel,
|
|
1775
|
+
"aria-labelledby": ariaLabelledBy,
|
|
1764
1776
|
"aria-haspopup": "listbox",
|
|
1765
1777
|
"aria-expanded": open,
|
|
1766
1778
|
onClick: () => setOpen((current) => !current),
|
|
@@ -2132,11 +2132,17 @@ var OptGroup = forwardRef6(({ children, ...props }, ref) => /* @__PURE__ */ jsx8
|
|
|
2132
2132
|
OptGroup.displayName = "Select.OptGroup";
|
|
2133
2133
|
var SelectRoot = forwardRef6(({
|
|
2134
2134
|
allowClear,
|
|
2135
|
+
"aria-describedby": ariaDescribedBy,
|
|
2136
|
+
"aria-errormessage": ariaErrorMessage,
|
|
2137
|
+
"aria-invalid": ariaInvalid,
|
|
2138
|
+
"aria-label": ariaLabel,
|
|
2139
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2135
2140
|
children,
|
|
2136
2141
|
className,
|
|
2137
2142
|
defaultValue,
|
|
2138
2143
|
disabled,
|
|
2139
2144
|
filterOption,
|
|
2145
|
+
id,
|
|
2140
2146
|
loading,
|
|
2141
2147
|
mode,
|
|
2142
2148
|
onChange,
|
|
@@ -2259,8 +2265,14 @@ var SelectRoot = forwardRef6(({
|
|
|
2259
2265
|
children: [
|
|
2260
2266
|
/* @__PURE__ */ jsxs7("button", {
|
|
2261
2267
|
type: "button",
|
|
2268
|
+
id,
|
|
2262
2269
|
className: getSelectClasses({ size, status, disabled }),
|
|
2263
2270
|
disabled: disabled || loading,
|
|
2271
|
+
"aria-describedby": ariaDescribedBy,
|
|
2272
|
+
"aria-errormessage": ariaErrorMessage,
|
|
2273
|
+
"aria-invalid": ariaInvalid,
|
|
2274
|
+
"aria-label": ariaLabel,
|
|
2275
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2264
2276
|
"aria-haspopup": "listbox",
|
|
2265
2277
|
"aria-expanded": open,
|
|
2266
2278
|
onClick: () => setOpen((current) => !current),
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { CompiledForm, FormErrors, RenderableSchema, FormValue } from "./json-schema-form";
|
|
3
|
+
export type JsonSchemaFormProps = {
|
|
4
|
+
value?: FormValue;
|
|
5
|
+
defaultValue?: FormValue;
|
|
6
|
+
onChange?: (value: FormValue) => void;
|
|
7
|
+
/** Backend errors keyed by JSON Pointer; clear these in onErrorsChange. */
|
|
8
|
+
errors?: FormErrors;
|
|
9
|
+
onErrorsChange?: (errors: FormErrors) => void;
|
|
10
|
+
onSubmit: (value: FormValue) => void;
|
|
11
|
+
onReset?: () => void;
|
|
12
|
+
} & ({
|
|
13
|
+
compiled: CompiledForm;
|
|
14
|
+
schema?: never;
|
|
15
|
+
} | {
|
|
16
|
+
schema: RenderableSchema;
|
|
17
|
+
compiled?: never;
|
|
18
|
+
});
|
|
19
|
+
export declare function JsonSchemaForm({ compiled: suppliedCompiled, schema, value: controlledValue, defaultValue, onChange, errors: suppliedErrors, onErrorsChange, onSubmit, onReset, }: JsonSchemaFormProps): React.JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { JsonValue, RenderableSchema } from "./json-schema-form";
|
|
3
|
+
export type JsonSchemaWidgetProps = {
|
|
4
|
+
schema: RenderableSchema;
|
|
5
|
+
value: JsonValue | undefined;
|
|
6
|
+
onChange: (value: JsonValue | undefined) => void;
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
path: string;
|
|
10
|
+
describedBy?: string;
|
|
11
|
+
invalid: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare const specializedWidgets: Set<string>;
|
|
14
|
+
export declare function JsonSchemaWidget({ schema, value, onChange, id, label, path, describedBy, invalid, }: JsonSchemaWidgetProps): React.JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { JsonSchemaForm } from "./JsonSchemaForm";
|
|
2
|
+
export type { JsonSchemaFormProps } from "./JsonSchemaForm";
|
|
3
|
+
export { JsonSchemaWidget, specializedWidgets } from "./JsonSchemaWidget";
|
|
4
|
+
export type { JsonSchemaWidgetProps } from "./JsonSchemaWidget";
|
|
5
|
+
export { compileForm } from "./json-schema-form";
|
|
6
|
+
export type { CompiledForm, FormErrors, FormValidationResult, FormValue, JsonValue, RenderableSchema, } from "./json-schema-form";
|
|
7
|
+
export { flattenOptions, inspectWidgets, naturalWidgetValue, optionsFor, widgetConfig, widgetNames, widgetValueError, } from "./json-form-widgets";
|
|
8
|
+
export type { OrientationWidgetConfig, WidgetConfig, WidgetName, WidgetOption, } from "./json-form-widgets";
|