@cratis/scene.react 4.30.0 → 4.31.0
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/dist/cjs/slices/SliceDialogView.js +9 -1
- package/dist/cjs/slices/SliceDialogView.js.map +1 -1
- package/dist/esm/slices/SliceCommandField.d.ts +1 -0
- package/dist/esm/slices/SliceCommandField.d.ts.map +1 -1
- package/dist/esm/slices/SliceDialogView.d.ts.map +1 -1
- package/dist/esm/slices/SliceDialogView.js +9 -1
- package/dist/esm/slices/SliceDialogView.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/slices/SliceCommandField.ts +3 -0
- package/slices/SliceDialogView.tsx +12 -1
|
@@ -38,6 +38,14 @@ function inputTypeOf(field) {
|
|
|
38
38
|
return 'text';
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
/** What the form starts with: the fields that carry an initial value, as the strings and booleans the inputs hold. */ function initialValuesOf(fields) {
|
|
42
|
+
const values = {};
|
|
43
|
+
for (const field of fields){
|
|
44
|
+
if (field.initialValue === undefined) continue;
|
|
45
|
+
values[field.name] = typeof field.initialValue === 'boolean' && inputTypeOf(field) === 'checkbox' ? field.initialValue : String(field.initialValue);
|
|
46
|
+
}
|
|
47
|
+
return values;
|
|
48
|
+
}
|
|
41
49
|
/** The payload a form's values make: numbers and booleans as such, an empty number left out. */ function slicePayload(fields, values) {
|
|
42
50
|
const payload = {};
|
|
43
51
|
for (const field of fields){
|
|
@@ -84,7 +92,7 @@ function inputTypeOf(field) {
|
|
|
84
92
|
model,
|
|
85
93
|
slice
|
|
86
94
|
]);
|
|
87
|
-
const [values, setValues] = react.useState(
|
|
95
|
+
const [values, setValues] = react.useState(()=>initialValuesOf(fields));
|
|
88
96
|
const [errors, setErrors] = react.useState([]);
|
|
89
97
|
const [submitting, setSubmitting] = react.useState(false);
|
|
90
98
|
const form = react.useRef(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliceDialogView.js","sources":["../../../slices/SliceDialogView.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { FormEvent, KeyboardEvent, useContext, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { ApplicationStructureIndex } from '@cratis/scene.engine';\nimport { SceneNavigationContextInternal } from '../navigation/SceneNavigationContext';\nimport { useSceneNavigationModel } from '../navigation/region/SceneNavigationModelContext';\nimport { InvocationResult } from './InvocationResult';\nimport { InvocationValidationError } from './InvocationValidationError';\nimport { SliceCommandField } from './SliceCommandField';\nimport { useSliceCommandFields } from './SliceCommandFieldsContext';\nimport { useSliceInvoker } from './SliceInvokerContext';\nimport { sliceDialogParameters } from './sliceDialogDestination';\n\nexport interface SliceDialogViewProps {\n /** The qualified id of the slice; the open dialog's `slice` parameter when absent. */\n slice?: string;\n\n /** The command the slice accepts; the open dialog's `command` parameter when absent. */\n command?: string;\n\n /** The title - the toolbar button's - also the label of the submit button; the open dialog's `title` parameter when absent. */\n title?: string;\n\n /** Called when the dialog is cancelled or the slice accepted the command; the host's `closeDialog` when absent. */\n onClose?(result?: InvocationResult): void;\n}\n\nconst focusable = 'input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [href], [tabindex]:not([tabindex=\"-1\"])';\n\n/** A label for a command property: `customerName` becomes `Customer name`. */\nexport function sliceFieldLabel(field: SliceCommandField): string {\n if (field.label) return field.label;\n const spaced = field.name.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ').trim().toLowerCase();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nfunction inputTypeOf(field: SliceCommandField): string {\n switch (field.type.toLowerCase()) {\n case 'number': case 'int': case 'integer': case 'long': case 'double': case 'decimal': case 'float': case 'single': case 'int32': case 'int64': return 'number';\n case 'boolean': case 'bool': return 'checkbox';\n case 'date': case 'dateonly': return 'date';\n default: return 'text';\n }\n}\n\n/** The payload a form's values make: numbers and booleans as such, an empty number left out. */\nexport function slicePayload(fields: SliceCommandField[], values: Record<string, string | boolean>): Record<string, unknown> {\n const payload: Record<string, unknown> = {};\n for (const field of fields) {\n const value = values[field.name];\n const type = inputTypeOf(field);\n if (type === 'checkbox') payload[field.name] = value === true;\n else if (type === 'number') { if (value !== undefined && value !== '') payload[field.name] = Number(value); }\n else payload[field.name] = value ?? '';\n }\n\n return payload;\n}\n\n/**\n * The task dialog of a toolbar slice button (TB4): a modal card with the button's title, the slice as its subtitle, a labelled\n * field for each command property, and Cancel and a submit button labelled with the title.\n *\n * - The first field takes focus when it opens, Tab stays inside, Escape cancels, and focus returns to the button that opened it.\n * - Submit validates required fields, then calls the `SliceInvoker` in scope - real, dry-run or the announcing default. The\n * problems it reports are shown against their fields (`aria-invalid`, `aria-describedby`) or for the form; success closes the\n * dialog and hands the result to the host (`dialogResult`).\n * - The fields come from the `SliceCommandFieldsProvider`; the subtitle names the slice from the navigation model.\n *\n * Inside a navigation host it is the content of the dialog a toolbar button opens; `core:sliceDialog` registers it so a host can\n * author the dialog template with it.\n */\nexport function SliceDialogView({ slice: sliceProp, command: commandProp, title: titleProp, onClose }: SliceDialogViewProps) {\n const navigation = useContext(SceneNavigationContextInternal);\n const opened = sliceDialogParameters(navigation?.currentDialogParameters);\n const slice = sliceProp ?? opened?.slice ?? '';\n const command = commandProp ?? opened?.command ?? slice;\n const title = titleProp ?? opened?.title ?? command;\n\n const invoker = useSliceInvoker();\n const fieldsFor = useSliceCommandFields();\n const model = useSceneNavigationModel();\n const fields = useMemo(() => fieldsFor?.(command, slice) ?? [], [command, fieldsFor, slice]);\n const sliceName = useMemo(() => {\n if (!model) return slice.split('.').pop() ?? slice;\n const index = model.structure instanceof ApplicationStructureIndex ? model.structure : new ApplicationStructureIndex(model.structure);\n return index.findSlice(slice)?.id ?? slice.split('.').pop() ?? slice;\n }, [model, slice]);\n\n const [values, setValues] = useState<Record<string, string | boolean>>({});\n const [errors, setErrors] = useState<InvocationValidationError[]>([]);\n const [submitting, setSubmitting] = useState(false);\n const form = useRef<HTMLFormElement>(null);\n const identity = useId();\n\n const close = (result?: InvocationResult) => onClose ? onClose(result) : navigation?.closeDialog(result);\n\n // Focus the first field, and give focus back to whatever opened the dialog when it goes.\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n (form.current?.querySelector<HTMLElement>('input, select, textarea') ?? form.current?.querySelector<HTMLElement>('button'))?.focus();\n return () => { if (opener && opener.isConnected) opener.focus(); };\n }, []);\n\n const errorsOf = (name: string | undefined) => errors.filter(error => error.field === name);\n const fieldNames = new Set(fields.map(field => field.name));\n const general = errors.filter(error => error.field === undefined || !fieldNames.has(error.field));\n\n const submit = async (event: FormEvent) => {\n event.preventDefault();\n if (submitting) return;\n\n const missing = fields.filter(field => field.required && (values[field.name] === undefined || values[field.name] === '')).map(field => ({ field: field.name, message: `${sliceFieldLabel(field)} is required.` }));\n setErrors(missing);\n if (missing.length > 0) {\n form.current?.querySelector<HTMLElement>('[aria-invalid=\"true\"]')?.focus();\n return;\n }\n\n setSubmitting(true);\n try {\n const result = await invoker.invoke(slice, slicePayload(fields, values), command);\n if (result.succeeded) {\n close(result);\n } else {\n const reported = result.validationErrors ?? [];\n setErrors(reported.length > 0 || !result.message ? reported : [{ message: result.message }]);\n }\n } finally {\n setSubmitting(false);\n }\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLFormElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n close();\n } else if (event.key === 'Tab') {\n const targets = Array.from(form.current?.querySelectorAll<HTMLElement>(focusable) ?? []);\n if (targets.length === 0) return;\n const first = targets[0];\n const last = targets[targets.length - 1];\n if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }\n else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }\n }\n };\n\n return <form ref={form} className='scene-slice-dialog' data-scene-slice-dialog={slice} data-scene-command={command} noValidate onSubmit={submit} onKeyDown={onKeyDown}>\n <header className='scene-slice-dialog-header'>\n <h2 className='scene-slice-dialog-title'>{title}</h2>\n <p className='scene-slice-dialog-subtitle'>State Change · {sliceName}</p>\n </header>\n <div className='scene-slice-dialog-fields'>\n {fields.map(field => {\n const id = `${identity}-${field.name}`;\n const own = errorsOf(field.name);\n const type = inputTypeOf(field);\n const description = own.length > 0 ? `${id}-error` : undefined;\n return <div key={field.name} className='scene-slice-dialog-field' data-type={type}>\n <label htmlFor={id}>{sliceFieldLabel(field)}{field.required ? <span aria-hidden='true'> *</span> : null}</label>\n <input id={id} name={field.name} type={type} required={field.required} aria-required={field.required || undefined}\n aria-invalid={own.length > 0 ? true : undefined} aria-describedby={description}\n {...(type === 'checkbox' ? { checked: values[field.name] === true } : { value: (values[field.name] as string | undefined) ?? '' })}\n onChange={event => setValues({ ...values, [field.name]: type === 'checkbox' ? event.target.checked : event.target.value })} />\n {own.length > 0 && <p id={description} className='scene-slice-dialog-error' role='alert'>{own.map(error => error.message).join(' ')}</p>}\n </div>;\n })}\n </div>\n {general.length > 0 && <p className='scene-slice-dialog-error scene-slice-dialog-summary' role='alert'>{general.map(error => error.message).join(' ')}</p>}\n <footer className='scene-slice-dialog-footer'>\n <button type='button' className='scene-slice-dialog-cancel' onClick={() => close()}>Cancel</button>\n <button type='submit' className='scene-slice-dialog-submit' disabled={submitting}>{title}</button>\n </footer>\n </form>;\n}\n"],"names":["focusable","sliceFieldLabel","field","label","spaced","name","replace","trim","toLowerCase","charAt","toUpperCase","slice","inputTypeOf","type","slicePayload","fields","values","payload","value","undefined","Number","SliceDialogView","sliceProp","command","commandProp","title","titleProp","onClose","navigation","useContext","SceneNavigationContextInternal","opened","sliceDialogParameters","currentDialogParameters","invoker","useSliceInvoker","fieldsFor","useSliceCommandFields","model","useSceneNavigationModel","useMemo","sliceName","split","pop","index","structure","ApplicationStructureIndex","findSlice","id","setValues","useState","errors","setErrors","submitting","setSubmitting","form","useRef","identity","useId","close","result","closeDialog","useEffect","opener","document","activeElement","current","querySelector","focus","isConnected","errorsOf","filter","error","fieldNames","Set","map","general","has","submit","event","preventDefault","missing","required","message","length","invoke","succeeded","reported","validationErrors","onKeyDown","key","targets","Array","from","querySelectorAll","first","last","shiftKey","_jsxs","ref","className","data-scene-slice-dialog","data-scene-command","noValidate","onSubmit","header","_jsx","h2","p","div","own","description","data-type","htmlFor","span","aria-hidden","input","aria-required","aria-invalid","aria-describedby","checked","onChange","target","role","join","footer","button","onClick","disabled"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SliceDialogView.js","sources":["../../../slices/SliceDialogView.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { FormEvent, KeyboardEvent, useContext, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { ApplicationStructureIndex } from '@cratis/scene.engine';\nimport { SceneNavigationContextInternal } from '../navigation/SceneNavigationContext';\nimport { useSceneNavigationModel } from '../navigation/region/SceneNavigationModelContext';\nimport { InvocationResult } from './InvocationResult';\nimport { InvocationValidationError } from './InvocationValidationError';\nimport { SliceCommandField } from './SliceCommandField';\nimport { useSliceCommandFields } from './SliceCommandFieldsContext';\nimport { useSliceInvoker } from './SliceInvokerContext';\nimport { sliceDialogParameters } from './sliceDialogDestination';\n\nexport interface SliceDialogViewProps {\n /** The qualified id of the slice; the open dialog's `slice` parameter when absent. */\n slice?: string;\n\n /** The command the slice accepts; the open dialog's `command` parameter when absent. */\n command?: string;\n\n /** The title - the toolbar button's - also the label of the submit button; the open dialog's `title` parameter when absent. */\n title?: string;\n\n /** Called when the dialog is cancelled or the slice accepted the command; the host's `closeDialog` when absent. */\n onClose?(result?: InvocationResult): void;\n}\n\nconst focusable = 'input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [href], [tabindex]:not([tabindex=\"-1\"])';\n\n/** A label for a command property: `customerName` becomes `Customer name`. */\nexport function sliceFieldLabel(field: SliceCommandField): string {\n if (field.label) return field.label;\n const spaced = field.name.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ').trim().toLowerCase();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nfunction inputTypeOf(field: SliceCommandField): string {\n switch (field.type.toLowerCase()) {\n case 'number': case 'int': case 'integer': case 'long': case 'double': case 'decimal': case 'float': case 'single': case 'int32': case 'int64': return 'number';\n case 'boolean': case 'bool': return 'checkbox';\n case 'date': case 'dateonly': return 'date';\n default: return 'text';\n }\n}\n\n/** What the form starts with: the fields that carry an initial value, as the strings and booleans the inputs hold. */\nfunction initialValuesOf(fields: SliceCommandField[]): Record<string, string | boolean> {\n const values: Record<string, string | boolean> = {};\n for (const field of fields) {\n if (field.initialValue === undefined) continue;\n values[field.name] = typeof field.initialValue === 'boolean' && inputTypeOf(field) === 'checkbox' ? field.initialValue : String(field.initialValue);\n }\n\n return values;\n}\n\n/** The payload a form's values make: numbers and booleans as such, an empty number left out. */\nexport function slicePayload(fields: SliceCommandField[], values: Record<string, string | boolean>): Record<string, unknown> {\n const payload: Record<string, unknown> = {};\n for (const field of fields) {\n const value = values[field.name];\n const type = inputTypeOf(field);\n if (type === 'checkbox') payload[field.name] = value === true;\n else if (type === 'number') { if (value !== undefined && value !== '') payload[field.name] = Number(value); }\n else payload[field.name] = value ?? '';\n }\n\n return payload;\n}\n\n/**\n * The task dialog of a toolbar slice button (TB4): a modal card with the button's title, the slice as its subtitle, a labelled\n * field for each command property, and Cancel and a submit button labelled with the title.\n *\n * - The first field takes focus when it opens, Tab stays inside, Escape cancels, and focus returns to the button that opened it.\n * - Submit validates required fields, then calls the `SliceInvoker` in scope - real, dry-run or the announcing default. The\n * problems it reports are shown against their fields (`aria-invalid`, `aria-describedby`) or for the form; success closes the\n * dialog and hands the result to the host (`dialogResult`).\n * - The fields come from the `SliceCommandFieldsProvider`; the subtitle names the slice from the navigation model.\n *\n * Inside a navigation host it is the content of the dialog a toolbar button opens; `core:sliceDialog` registers it so a host can\n * author the dialog template with it.\n */\nexport function SliceDialogView({ slice: sliceProp, command: commandProp, title: titleProp, onClose }: SliceDialogViewProps) {\n const navigation = useContext(SceneNavigationContextInternal);\n const opened = sliceDialogParameters(navigation?.currentDialogParameters);\n const slice = sliceProp ?? opened?.slice ?? '';\n const command = commandProp ?? opened?.command ?? slice;\n const title = titleProp ?? opened?.title ?? command;\n\n const invoker = useSliceInvoker();\n const fieldsFor = useSliceCommandFields();\n const model = useSceneNavigationModel();\n const fields = useMemo(() => fieldsFor?.(command, slice) ?? [], [command, fieldsFor, slice]);\n const sliceName = useMemo(() => {\n if (!model) return slice.split('.').pop() ?? slice;\n const index = model.structure instanceof ApplicationStructureIndex ? model.structure : new ApplicationStructureIndex(model.structure);\n return index.findSlice(slice)?.id ?? slice.split('.').pop() ?? slice;\n }, [model, slice]);\n\n const [values, setValues] = useState<Record<string, string | boolean>>(() => initialValuesOf(fields));\n const [errors, setErrors] = useState<InvocationValidationError[]>([]);\n const [submitting, setSubmitting] = useState(false);\n const form = useRef<HTMLFormElement>(null);\n const identity = useId();\n\n const close = (result?: InvocationResult) => onClose ? onClose(result) : navigation?.closeDialog(result);\n\n // Focus the first field, and give focus back to whatever opened the dialog when it goes.\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n (form.current?.querySelector<HTMLElement>('input, select, textarea') ?? form.current?.querySelector<HTMLElement>('button'))?.focus();\n return () => { if (opener && opener.isConnected) opener.focus(); };\n }, []);\n\n const errorsOf = (name: string | undefined) => errors.filter(error => error.field === name);\n const fieldNames = new Set(fields.map(field => field.name));\n const general = errors.filter(error => error.field === undefined || !fieldNames.has(error.field));\n\n const submit = async (event: FormEvent) => {\n event.preventDefault();\n if (submitting) return;\n\n const missing = fields.filter(field => field.required && (values[field.name] === undefined || values[field.name] === '')).map(field => ({ field: field.name, message: `${sliceFieldLabel(field)} is required.` }));\n setErrors(missing);\n if (missing.length > 0) {\n form.current?.querySelector<HTMLElement>('[aria-invalid=\"true\"]')?.focus();\n return;\n }\n\n setSubmitting(true);\n try {\n const result = await invoker.invoke(slice, slicePayload(fields, values), command);\n if (result.succeeded) {\n close(result);\n } else {\n const reported = result.validationErrors ?? [];\n setErrors(reported.length > 0 || !result.message ? reported : [{ message: result.message }]);\n }\n } finally {\n setSubmitting(false);\n }\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLFormElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n close();\n } else if (event.key === 'Tab') {\n const targets = Array.from(form.current?.querySelectorAll<HTMLElement>(focusable) ?? []);\n if (targets.length === 0) return;\n const first = targets[0];\n const last = targets[targets.length - 1];\n if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }\n else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }\n }\n };\n\n return <form ref={form} className='scene-slice-dialog' data-scene-slice-dialog={slice} data-scene-command={command} noValidate onSubmit={submit} onKeyDown={onKeyDown}>\n <header className='scene-slice-dialog-header'>\n <h2 className='scene-slice-dialog-title'>{title}</h2>\n <p className='scene-slice-dialog-subtitle'>State Change · {sliceName}</p>\n </header>\n <div className='scene-slice-dialog-fields'>\n {fields.map(field => {\n const id = `${identity}-${field.name}`;\n const own = errorsOf(field.name);\n const type = inputTypeOf(field);\n const description = own.length > 0 ? `${id}-error` : undefined;\n return <div key={field.name} className='scene-slice-dialog-field' data-type={type}>\n <label htmlFor={id}>{sliceFieldLabel(field)}{field.required ? <span aria-hidden='true'> *</span> : null}</label>\n <input id={id} name={field.name} type={type} required={field.required} aria-required={field.required || undefined}\n aria-invalid={own.length > 0 ? true : undefined} aria-describedby={description}\n {...(type === 'checkbox' ? { checked: values[field.name] === true } : { value: (values[field.name] as string | undefined) ?? '' })}\n onChange={event => setValues({ ...values, [field.name]: type === 'checkbox' ? event.target.checked : event.target.value })} />\n {own.length > 0 && <p id={description} className='scene-slice-dialog-error' role='alert'>{own.map(error => error.message).join(' ')}</p>}\n </div>;\n })}\n </div>\n {general.length > 0 && <p className='scene-slice-dialog-error scene-slice-dialog-summary' role='alert'>{general.map(error => error.message).join(' ')}</p>}\n <footer className='scene-slice-dialog-footer'>\n <button type='button' className='scene-slice-dialog-cancel' onClick={() => close()}>Cancel</button>\n <button type='submit' className='scene-slice-dialog-submit' disabled={submitting}>{title}</button>\n </footer>\n </form>;\n}\n"],"names":["focusable","sliceFieldLabel","field","label","spaced","name","replace","trim","toLowerCase","charAt","toUpperCase","slice","inputTypeOf","type","initialValuesOf","fields","values","initialValue","undefined","String","slicePayload","payload","value","Number","SliceDialogView","sliceProp","command","commandProp","title","titleProp","onClose","navigation","useContext","SceneNavigationContextInternal","opened","sliceDialogParameters","currentDialogParameters","invoker","useSliceInvoker","fieldsFor","useSliceCommandFields","model","useSceneNavigationModel","useMemo","sliceName","split","pop","index","structure","ApplicationStructureIndex","findSlice","id","setValues","useState","errors","setErrors","submitting","setSubmitting","form","useRef","identity","useId","close","result","closeDialog","useEffect","opener","document","activeElement","current","querySelector","focus","isConnected","errorsOf","filter","error","fieldNames","Set","map","general","has","submit","event","preventDefault","missing","required","message","length","invoke","succeeded","reported","validationErrors","onKeyDown","key","targets","Array","from","querySelectorAll","first","last","shiftKey","_jsxs","ref","className","data-scene-slice-dialog","data-scene-command","noValidate","onSubmit","header","_jsx","h2","p","div","own","description","data-type","htmlFor","span","aria-hidden","input","aria-required","aria-invalid","aria-describedby","checked","onChange","target","role","join","footer","button","onClick","disabled"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliceCommandField.d.ts","sourceRoot":"","sources":["../../../slices/SliceCommandField.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IAE9B,IAAI,EAAE,MAAM,CAAC;IAGb,IAAI,EAAE,MAAM,CAAC;IAGb,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,QAAQ,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SliceCommandField.d.ts","sourceRoot":"","sources":["../../../slices/SliceCommandField.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IAE9B,IAAI,EAAE,MAAM,CAAC;IAGb,IAAI,EAAE,MAAM,CAAC;IAGb,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAC5C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliceDialogView.d.ts","sourceRoot":"","sources":["../../../slices/SliceDialogView.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAKxD,MAAM,WAAW,oBAAoB;IAEjC,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC7C;AAKD,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAIhE;
|
|
1
|
+
{"version":3,"file":"SliceDialogView.d.ts","sourceRoot":"","sources":["../../../slices/SliceDialogView.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAKxD,MAAM,WAAW,oBAAoB;IAEjC,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC7C;AAKD,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAIhE;AAuBD,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAW3H;AAeD,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,oBAAoB,+BAsG1H"}
|
|
@@ -36,6 +36,14 @@ function inputTypeOf(field) {
|
|
|
36
36
|
return 'text';
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
/** What the form starts with: the fields that carry an initial value, as the strings and booleans the inputs hold. */ function initialValuesOf(fields) {
|
|
40
|
+
const values = {};
|
|
41
|
+
for (const field of fields){
|
|
42
|
+
if (field.initialValue === undefined) continue;
|
|
43
|
+
values[field.name] = typeof field.initialValue === 'boolean' && inputTypeOf(field) === 'checkbox' ? field.initialValue : String(field.initialValue);
|
|
44
|
+
}
|
|
45
|
+
return values;
|
|
46
|
+
}
|
|
39
47
|
/** The payload a form's values make: numbers and booleans as such, an empty number left out. */ function slicePayload(fields, values) {
|
|
40
48
|
const payload = {};
|
|
41
49
|
for (const field of fields){
|
|
@@ -82,7 +90,7 @@ function inputTypeOf(field) {
|
|
|
82
90
|
model,
|
|
83
91
|
slice
|
|
84
92
|
]);
|
|
85
|
-
const [values, setValues] = useState(
|
|
93
|
+
const [values, setValues] = useState(()=>initialValuesOf(fields));
|
|
86
94
|
const [errors, setErrors] = useState([]);
|
|
87
95
|
const [submitting, setSubmitting] = useState(false);
|
|
88
96
|
const form = useRef(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SliceDialogView.js","sources":["../../../slices/SliceDialogView.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { FormEvent, KeyboardEvent, useContext, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { ApplicationStructureIndex } from '@cratis/scene.engine';\nimport { SceneNavigationContextInternal } from '../navigation/SceneNavigationContext';\nimport { useSceneNavigationModel } from '../navigation/region/SceneNavigationModelContext';\nimport { InvocationResult } from './InvocationResult';\nimport { InvocationValidationError } from './InvocationValidationError';\nimport { SliceCommandField } from './SliceCommandField';\nimport { useSliceCommandFields } from './SliceCommandFieldsContext';\nimport { useSliceInvoker } from './SliceInvokerContext';\nimport { sliceDialogParameters } from './sliceDialogDestination';\n\nexport interface SliceDialogViewProps {\n /** The qualified id of the slice; the open dialog's `slice` parameter when absent. */\n slice?: string;\n\n /** The command the slice accepts; the open dialog's `command` parameter when absent. */\n command?: string;\n\n /** The title - the toolbar button's - also the label of the submit button; the open dialog's `title` parameter when absent. */\n title?: string;\n\n /** Called when the dialog is cancelled or the slice accepted the command; the host's `closeDialog` when absent. */\n onClose?(result?: InvocationResult): void;\n}\n\nconst focusable = 'input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [href], [tabindex]:not([tabindex=\"-1\"])';\n\n/** A label for a command property: `customerName` becomes `Customer name`. */\nexport function sliceFieldLabel(field: SliceCommandField): string {\n if (field.label) return field.label;\n const spaced = field.name.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ').trim().toLowerCase();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nfunction inputTypeOf(field: SliceCommandField): string {\n switch (field.type.toLowerCase()) {\n case 'number': case 'int': case 'integer': case 'long': case 'double': case 'decimal': case 'float': case 'single': case 'int32': case 'int64': return 'number';\n case 'boolean': case 'bool': return 'checkbox';\n case 'date': case 'dateonly': return 'date';\n default: return 'text';\n }\n}\n\n/** The payload a form's values make: numbers and booleans as such, an empty number left out. */\nexport function slicePayload(fields: SliceCommandField[], values: Record<string, string | boolean>): Record<string, unknown> {\n const payload: Record<string, unknown> = {};\n for (const field of fields) {\n const value = values[field.name];\n const type = inputTypeOf(field);\n if (type === 'checkbox') payload[field.name] = value === true;\n else if (type === 'number') { if (value !== undefined && value !== '') payload[field.name] = Number(value); }\n else payload[field.name] = value ?? '';\n }\n\n return payload;\n}\n\n/**\n * The task dialog of a toolbar slice button (TB4): a modal card with the button's title, the slice as its subtitle, a labelled\n * field for each command property, and Cancel and a submit button labelled with the title.\n *\n * - The first field takes focus when it opens, Tab stays inside, Escape cancels, and focus returns to the button that opened it.\n * - Submit validates required fields, then calls the `SliceInvoker` in scope - real, dry-run or the announcing default. The\n * problems it reports are shown against their fields (`aria-invalid`, `aria-describedby`) or for the form; success closes the\n * dialog and hands the result to the host (`dialogResult`).\n * - The fields come from the `SliceCommandFieldsProvider`; the subtitle names the slice from the navigation model.\n *\n * Inside a navigation host it is the content of the dialog a toolbar button opens; `core:sliceDialog` registers it so a host can\n * author the dialog template with it.\n */\nexport function SliceDialogView({ slice: sliceProp, command: commandProp, title: titleProp, onClose }: SliceDialogViewProps) {\n const navigation = useContext(SceneNavigationContextInternal);\n const opened = sliceDialogParameters(navigation?.currentDialogParameters);\n const slice = sliceProp ?? opened?.slice ?? '';\n const command = commandProp ?? opened?.command ?? slice;\n const title = titleProp ?? opened?.title ?? command;\n\n const invoker = useSliceInvoker();\n const fieldsFor = useSliceCommandFields();\n const model = useSceneNavigationModel();\n const fields = useMemo(() => fieldsFor?.(command, slice) ?? [], [command, fieldsFor, slice]);\n const sliceName = useMemo(() => {\n if (!model) return slice.split('.').pop() ?? slice;\n const index = model.structure instanceof ApplicationStructureIndex ? model.structure : new ApplicationStructureIndex(model.structure);\n return index.findSlice(slice)?.id ?? slice.split('.').pop() ?? slice;\n }, [model, slice]);\n\n const [values, setValues] = useState<Record<string, string | boolean>>({});\n const [errors, setErrors] = useState<InvocationValidationError[]>([]);\n const [submitting, setSubmitting] = useState(false);\n const form = useRef<HTMLFormElement>(null);\n const identity = useId();\n\n const close = (result?: InvocationResult) => onClose ? onClose(result) : navigation?.closeDialog(result);\n\n // Focus the first field, and give focus back to whatever opened the dialog when it goes.\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n (form.current?.querySelector<HTMLElement>('input, select, textarea') ?? form.current?.querySelector<HTMLElement>('button'))?.focus();\n return () => { if (opener && opener.isConnected) opener.focus(); };\n }, []);\n\n const errorsOf = (name: string | undefined) => errors.filter(error => error.field === name);\n const fieldNames = new Set(fields.map(field => field.name));\n const general = errors.filter(error => error.field === undefined || !fieldNames.has(error.field));\n\n const submit = async (event: FormEvent) => {\n event.preventDefault();\n if (submitting) return;\n\n const missing = fields.filter(field => field.required && (values[field.name] === undefined || values[field.name] === '')).map(field => ({ field: field.name, message: `${sliceFieldLabel(field)} is required.` }));\n setErrors(missing);\n if (missing.length > 0) {\n form.current?.querySelector<HTMLElement>('[aria-invalid=\"true\"]')?.focus();\n return;\n }\n\n setSubmitting(true);\n try {\n const result = await invoker.invoke(slice, slicePayload(fields, values), command);\n if (result.succeeded) {\n close(result);\n } else {\n const reported = result.validationErrors ?? [];\n setErrors(reported.length > 0 || !result.message ? reported : [{ message: result.message }]);\n }\n } finally {\n setSubmitting(false);\n }\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLFormElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n close();\n } else if (event.key === 'Tab') {\n const targets = Array.from(form.current?.querySelectorAll<HTMLElement>(focusable) ?? []);\n if (targets.length === 0) return;\n const first = targets[0];\n const last = targets[targets.length - 1];\n if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }\n else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }\n }\n };\n\n return <form ref={form} className='scene-slice-dialog' data-scene-slice-dialog={slice} data-scene-command={command} noValidate onSubmit={submit} onKeyDown={onKeyDown}>\n <header className='scene-slice-dialog-header'>\n <h2 className='scene-slice-dialog-title'>{title}</h2>\n <p className='scene-slice-dialog-subtitle'>State Change · {sliceName}</p>\n </header>\n <div className='scene-slice-dialog-fields'>\n {fields.map(field => {\n const id = `${identity}-${field.name}`;\n const own = errorsOf(field.name);\n const type = inputTypeOf(field);\n const description = own.length > 0 ? `${id}-error` : undefined;\n return <div key={field.name} className='scene-slice-dialog-field' data-type={type}>\n <label htmlFor={id}>{sliceFieldLabel(field)}{field.required ? <span aria-hidden='true'> *</span> : null}</label>\n <input id={id} name={field.name} type={type} required={field.required} aria-required={field.required || undefined}\n aria-invalid={own.length > 0 ? true : undefined} aria-describedby={description}\n {...(type === 'checkbox' ? { checked: values[field.name] === true } : { value: (values[field.name] as string | undefined) ?? '' })}\n onChange={event => setValues({ ...values, [field.name]: type === 'checkbox' ? event.target.checked : event.target.value })} />\n {own.length > 0 && <p id={description} className='scene-slice-dialog-error' role='alert'>{own.map(error => error.message).join(' ')}</p>}\n </div>;\n })}\n </div>\n {general.length > 0 && <p className='scene-slice-dialog-error scene-slice-dialog-summary' role='alert'>{general.map(error => error.message).join(' ')}</p>}\n <footer className='scene-slice-dialog-footer'>\n <button type='button' className='scene-slice-dialog-cancel' onClick={() => close()}>Cancel</button>\n <button type='submit' className='scene-slice-dialog-submit' disabled={submitting}>{title}</button>\n </footer>\n </form>;\n}\n"],"names":["focusable","sliceFieldLabel","field","label","spaced","name","replace","trim","toLowerCase","charAt","toUpperCase","slice","inputTypeOf","type","slicePayload","fields","values","payload","value","undefined","Number","SliceDialogView","sliceProp","command","commandProp","title","titleProp","onClose","navigation","useContext","SceneNavigationContextInternal","opened","sliceDialogParameters","currentDialogParameters","invoker","useSliceInvoker","fieldsFor","useSliceCommandFields","model","useSceneNavigationModel","useMemo","sliceName","split","pop","index","structure","ApplicationStructureIndex","findSlice","id","setValues","useState","errors","setErrors","submitting","setSubmitting","form","useRef","identity","useId","close","result","closeDialog","useEffect","opener","document","activeElement","current","querySelector","focus","isConnected","errorsOf","filter","error","fieldNames","Set","map","general","has","submit","event","preventDefault","missing","required","message","length","invoke","succeeded","reported","validationErrors","onKeyDown","key","targets","Array","from","querySelectorAll","first","last","shiftKey","_jsxs","ref","className","data-scene-slice-dialog","data-scene-command","noValidate","onSubmit","header","_jsx","h2","p","div","own","description","data-type","htmlFor","span","aria-hidden","input","aria-required","aria-invalid","aria-describedby","checked","onChange","target","role","join","footer","button","onClick","disabled"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SliceDialogView.js","sources":["../../../slices/SliceDialogView.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { FormEvent, KeyboardEvent, useContext, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { ApplicationStructureIndex } from '@cratis/scene.engine';\nimport { SceneNavigationContextInternal } from '../navigation/SceneNavigationContext';\nimport { useSceneNavigationModel } from '../navigation/region/SceneNavigationModelContext';\nimport { InvocationResult } from './InvocationResult';\nimport { InvocationValidationError } from './InvocationValidationError';\nimport { SliceCommandField } from './SliceCommandField';\nimport { useSliceCommandFields } from './SliceCommandFieldsContext';\nimport { useSliceInvoker } from './SliceInvokerContext';\nimport { sliceDialogParameters } from './sliceDialogDestination';\n\nexport interface SliceDialogViewProps {\n /** The qualified id of the slice; the open dialog's `slice` parameter when absent. */\n slice?: string;\n\n /** The command the slice accepts; the open dialog's `command` parameter when absent. */\n command?: string;\n\n /** The title - the toolbar button's - also the label of the submit button; the open dialog's `title` parameter when absent. */\n title?: string;\n\n /** Called when the dialog is cancelled or the slice accepted the command; the host's `closeDialog` when absent. */\n onClose?(result?: InvocationResult): void;\n}\n\nconst focusable = 'input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [href], [tabindex]:not([tabindex=\"-1\"])';\n\n/** A label for a command property: `customerName` becomes `Customer name`. */\nexport function sliceFieldLabel(field: SliceCommandField): string {\n if (field.label) return field.label;\n const spaced = field.name.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ').trim().toLowerCase();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nfunction inputTypeOf(field: SliceCommandField): string {\n switch (field.type.toLowerCase()) {\n case 'number': case 'int': case 'integer': case 'long': case 'double': case 'decimal': case 'float': case 'single': case 'int32': case 'int64': return 'number';\n case 'boolean': case 'bool': return 'checkbox';\n case 'date': case 'dateonly': return 'date';\n default: return 'text';\n }\n}\n\n/** What the form starts with: the fields that carry an initial value, as the strings and booleans the inputs hold. */\nfunction initialValuesOf(fields: SliceCommandField[]): Record<string, string | boolean> {\n const values: Record<string, string | boolean> = {};\n for (const field of fields) {\n if (field.initialValue === undefined) continue;\n values[field.name] = typeof field.initialValue === 'boolean' && inputTypeOf(field) === 'checkbox' ? field.initialValue : String(field.initialValue);\n }\n\n return values;\n}\n\n/** The payload a form's values make: numbers and booleans as such, an empty number left out. */\nexport function slicePayload(fields: SliceCommandField[], values: Record<string, string | boolean>): Record<string, unknown> {\n const payload: Record<string, unknown> = {};\n for (const field of fields) {\n const value = values[field.name];\n const type = inputTypeOf(field);\n if (type === 'checkbox') payload[field.name] = value === true;\n else if (type === 'number') { if (value !== undefined && value !== '') payload[field.name] = Number(value); }\n else payload[field.name] = value ?? '';\n }\n\n return payload;\n}\n\n/**\n * The task dialog of a toolbar slice button (TB4): a modal card with the button's title, the slice as its subtitle, a labelled\n * field for each command property, and Cancel and a submit button labelled with the title.\n *\n * - The first field takes focus when it opens, Tab stays inside, Escape cancels, and focus returns to the button that opened it.\n * - Submit validates required fields, then calls the `SliceInvoker` in scope - real, dry-run or the announcing default. The\n * problems it reports are shown against their fields (`aria-invalid`, `aria-describedby`) or for the form; success closes the\n * dialog and hands the result to the host (`dialogResult`).\n * - The fields come from the `SliceCommandFieldsProvider`; the subtitle names the slice from the navigation model.\n *\n * Inside a navigation host it is the content of the dialog a toolbar button opens; `core:sliceDialog` registers it so a host can\n * author the dialog template with it.\n */\nexport function SliceDialogView({ slice: sliceProp, command: commandProp, title: titleProp, onClose }: SliceDialogViewProps) {\n const navigation = useContext(SceneNavigationContextInternal);\n const opened = sliceDialogParameters(navigation?.currentDialogParameters);\n const slice = sliceProp ?? opened?.slice ?? '';\n const command = commandProp ?? opened?.command ?? slice;\n const title = titleProp ?? opened?.title ?? command;\n\n const invoker = useSliceInvoker();\n const fieldsFor = useSliceCommandFields();\n const model = useSceneNavigationModel();\n const fields = useMemo(() => fieldsFor?.(command, slice) ?? [], [command, fieldsFor, slice]);\n const sliceName = useMemo(() => {\n if (!model) return slice.split('.').pop() ?? slice;\n const index = model.structure instanceof ApplicationStructureIndex ? model.structure : new ApplicationStructureIndex(model.structure);\n return index.findSlice(slice)?.id ?? slice.split('.').pop() ?? slice;\n }, [model, slice]);\n\n const [values, setValues] = useState<Record<string, string | boolean>>(() => initialValuesOf(fields));\n const [errors, setErrors] = useState<InvocationValidationError[]>([]);\n const [submitting, setSubmitting] = useState(false);\n const form = useRef<HTMLFormElement>(null);\n const identity = useId();\n\n const close = (result?: InvocationResult) => onClose ? onClose(result) : navigation?.closeDialog(result);\n\n // Focus the first field, and give focus back to whatever opened the dialog when it goes.\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n (form.current?.querySelector<HTMLElement>('input, select, textarea') ?? form.current?.querySelector<HTMLElement>('button'))?.focus();\n return () => { if (opener && opener.isConnected) opener.focus(); };\n }, []);\n\n const errorsOf = (name: string | undefined) => errors.filter(error => error.field === name);\n const fieldNames = new Set(fields.map(field => field.name));\n const general = errors.filter(error => error.field === undefined || !fieldNames.has(error.field));\n\n const submit = async (event: FormEvent) => {\n event.preventDefault();\n if (submitting) return;\n\n const missing = fields.filter(field => field.required && (values[field.name] === undefined || values[field.name] === '')).map(field => ({ field: field.name, message: `${sliceFieldLabel(field)} is required.` }));\n setErrors(missing);\n if (missing.length > 0) {\n form.current?.querySelector<HTMLElement>('[aria-invalid=\"true\"]')?.focus();\n return;\n }\n\n setSubmitting(true);\n try {\n const result = await invoker.invoke(slice, slicePayload(fields, values), command);\n if (result.succeeded) {\n close(result);\n } else {\n const reported = result.validationErrors ?? [];\n setErrors(reported.length > 0 || !result.message ? reported : [{ message: result.message }]);\n }\n } finally {\n setSubmitting(false);\n }\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLFormElement>) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n close();\n } else if (event.key === 'Tab') {\n const targets = Array.from(form.current?.querySelectorAll<HTMLElement>(focusable) ?? []);\n if (targets.length === 0) return;\n const first = targets[0];\n const last = targets[targets.length - 1];\n if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }\n else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }\n }\n };\n\n return <form ref={form} className='scene-slice-dialog' data-scene-slice-dialog={slice} data-scene-command={command} noValidate onSubmit={submit} onKeyDown={onKeyDown}>\n <header className='scene-slice-dialog-header'>\n <h2 className='scene-slice-dialog-title'>{title}</h2>\n <p className='scene-slice-dialog-subtitle'>State Change · {sliceName}</p>\n </header>\n <div className='scene-slice-dialog-fields'>\n {fields.map(field => {\n const id = `${identity}-${field.name}`;\n const own = errorsOf(field.name);\n const type = inputTypeOf(field);\n const description = own.length > 0 ? `${id}-error` : undefined;\n return <div key={field.name} className='scene-slice-dialog-field' data-type={type}>\n <label htmlFor={id}>{sliceFieldLabel(field)}{field.required ? <span aria-hidden='true'> *</span> : null}</label>\n <input id={id} name={field.name} type={type} required={field.required} aria-required={field.required || undefined}\n aria-invalid={own.length > 0 ? true : undefined} aria-describedby={description}\n {...(type === 'checkbox' ? { checked: values[field.name] === true } : { value: (values[field.name] as string | undefined) ?? '' })}\n onChange={event => setValues({ ...values, [field.name]: type === 'checkbox' ? event.target.checked : event.target.value })} />\n {own.length > 0 && <p id={description} className='scene-slice-dialog-error' role='alert'>{own.map(error => error.message).join(' ')}</p>}\n </div>;\n })}\n </div>\n {general.length > 0 && <p className='scene-slice-dialog-error scene-slice-dialog-summary' role='alert'>{general.map(error => error.message).join(' ')}</p>}\n <footer className='scene-slice-dialog-footer'>\n <button type='button' className='scene-slice-dialog-cancel' onClick={() => close()}>Cancel</button>\n <button type='submit' className='scene-slice-dialog-submit' disabled={submitting}>{title}</button>\n </footer>\n </form>;\n}\n"],"names":["focusable","sliceFieldLabel","field","label","spaced","name","replace","trim","toLowerCase","charAt","toUpperCase","slice","inputTypeOf","type","initialValuesOf","fields","values","initialValue","undefined","String","slicePayload","payload","value","Number","SliceDialogView","sliceProp","command","commandProp","title","titleProp","onClose","navigation","useContext","SceneNavigationContextInternal","opened","sliceDialogParameters","currentDialogParameters","invoker","useSliceInvoker","fieldsFor","useSliceCommandFields","model","useSceneNavigationModel","useMemo","sliceName","split","pop","index","structure","ApplicationStructureIndex","findSlice","id","setValues","useState","errors","setErrors","submitting","setSubmitting","form","useRef","identity","useId","close","result","closeDialog","useEffect","opener","document","activeElement","current","querySelector","focus","isConnected","errorsOf","filter","error","fieldNames","Set","map","general","has","submit","event","preventDefault","missing","required","message","length","invoke","succeeded","reported","validationErrors","onKeyDown","key","targets","Array","from","querySelectorAll","first","last","shiftKey","_jsxs","ref","className","data-scene-slice-dialog","data-scene-command","noValidate","onSubmit","header","_jsx","h2","p","div","own","description","data-type","htmlFor","span","aria-hidden","input","aria-required","aria-invalid","aria-describedby","checked","onChange","target","role","join","footer","button","onClick","disabled"],"mappings":"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"}
|