@morscherlab/mint-sdk 1.0.63 → 1.1.0-beta.2
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 +101 -2
- package/dist/EmptyState-D1c4RdC7.js +638 -0
- package/dist/EmptyState-D1c4RdC7.js.map +1 -0
- package/dist/{ExperimentPopover-BbPkIFsI.js → ExperimentPopover-BFw3QX8L.js} +10 -9
- package/dist/{ExperimentPopover-BbPkIFsI.js.map → ExperimentPopover-BFw3QX8L.js.map} +1 -1
- package/dist/{ExperimentSelectorModal-DZeSd-yr.js → ExperimentSelectorModal-B7w6k3Y8.js} +12 -216
- package/dist/ExperimentSelectorModal-B7w6k3Y8.js.map +1 -0
- package/dist/{SettingsModal-CJgLadsN.js → SettingsModal-DPDwCbXK.js} +12 -9
- package/dist/{SettingsModal-CJgLadsN.js.map → SettingsModal-DPDwCbXK.js.map} +1 -1
- package/dist/__tests__/components/GeneratedPlotlyResult.test.d.ts +1 -0
- package/dist/__tests__/components/GeneratedPluginView.test.d.ts +1 -0
- package/dist/__tests__/components/GeneratedResultRenderer.test.d.ts +1 -0
- package/dist/__tests__/components/InstrumentAlertLog.test.d.ts +1 -0
- package/dist/__tests__/composables/useGeneratedAnalysis.test.d.ts +1 -0
- package/dist/__tests__/generatedUi.test.d.ts +1 -0
- package/dist/{analysisArtifactTypes-Cu40dzSG.js → analysisArtifactTypes-ejqR8MX3.js} +1 -1
- package/dist/analysisArtifactTypes-ejqR8MX3.js.map +1 -0
- package/dist/{auth-DZAwEeis.js → auth-B87xM--s.js} +1 -1
- package/dist/{auth-DZAwEeis.js.map → auth-B87xM--s.js.map} +1 -1
- package/dist/chunk-BoAXSpZd.js +33 -0
- package/dist/components/AppSidebar.vue.d.ts +1 -1
- package/dist/components/AutoGroupModal.vue.d.ts +2 -2
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
- package/dist/components/CollapsibleCard.vue.d.ts +1 -1
- package/dist/components/ComponentBindingRenderer.vue.d.ts +1 -1
- package/dist/components/ConfirmDialog.vue.d.ts +1 -1
- package/dist/components/ExperimentDataViewer.vue.d.ts +1 -1
- package/dist/components/ExperimentTimeline.vue.d.ts +1 -1
- package/dist/components/FileUploader.vue.d.ts +4 -2
- package/dist/components/FitPanel.vue.d.ts +1 -1
- package/dist/components/FormActions.vue.d.ts +1 -1
- package/dist/components/FormBuilder.vue.d.ts +1 -1
- package/dist/components/GeneratedPathInput.vue.d.ts +12 -0
- package/dist/components/GeneratedPlotlyResult.vue.d.ts +11 -0
- package/dist/components/GeneratedPluginView.vue.d.ts +10 -0
- package/dist/components/GeneratedResultRenderer.vue.d.ts +6 -0
- package/dist/components/JobsStatusTray.vue.d.ts +5 -1
- package/dist/components/LcmsSequenceTable.vue.d.ts +1 -1
- package/dist/components/SampleLegend.vue.d.ts +1 -1
- package/dist/components/SampleSelector.vue.d.ts +2 -2
- package/dist/components/SettingsModal.vue.d.ts +1 -1
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -2
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +8 -9
- package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +2 -2
- package/dist/{components-DdzHh3a_.js → components-UfkPN1bK.js} +2255 -2303
- package/dist/components-UfkPN1bK.js.map +1 -0
- package/dist/composables/index.d.ts +2 -3
- package/dist/composables/index.js +10 -11
- package/dist/composables/platformContextHelpers.d.ts +0 -2
- package/dist/composables/useAnalysisArtifacts.d.ts +1 -3
- package/dist/composables/useGeneratedAnalysis.d.ts +62 -0
- package/dist/composables/useJobsStatusTray.d.ts +48 -4
- package/dist/composables/usePlatformContext.d.ts +3 -0
- package/dist/composables/usePluginClient.d.ts +6 -3
- package/dist/{composables-BUUphBqg.js → composables-B512bWJP.js} +155 -74
- package/dist/composables-B512bWJP.js.map +1 -0
- package/dist/experiment-utils-CxkruZ3G.js +392 -0
- package/dist/experiment-utils-CxkruZ3G.js.map +1 -0
- package/dist/generated/schema.d.ts +7 -0
- package/dist/generated-ui/main.d.ts +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -18
- package/dist/index.js.map +1 -1
- package/dist/install.js +7 -8
- package/dist/install.js.map +1 -1
- package/dist/plotly.min-BR53hja4.js +180634 -0
- package/dist/plotly.min-BR53hja4.js.map +1 -0
- package/dist/stores/auth.d.ts +2 -2
- package/dist/stores/index.js +1 -1
- package/dist/styles.css +10543 -10404
- package/dist/templates/index.js +4 -3
- package/dist/templates/packs.d.ts +0 -1
- package/dist/{templates-CNbPQNID.js → templates-Cttbjbyc.js} +2 -4
- package/dist/templates-Cttbjbyc.js.map +1 -0
- package/dist/types/analysisArtifactTypes.d.ts +0 -8
- package/dist/types/form-builder.d.ts +1 -1
- package/dist/types/generated-ui.d.ts +170 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.js +1 -1
- package/dist/types/instrument.d.ts +1 -0
- package/dist/types/jobs.d.ts +7 -1
- package/dist/types/platform.d.ts +2 -0
- package/dist/{useControlSchema-BZNdalmL.js → useControlSchema-Dallso-L.js} +1852 -171
- package/dist/useControlSchema-Dallso-L.js.map +1 -0
- package/dist/{useDropdownState-Bb-c_PeE.js → useDropdownState-gVaMXtwW.js} +2 -2
- package/dist/{useDropdownState-Bb-c_PeE.js.map → useDropdownState-gVaMXtwW.js.map} +1 -1
- package/dist/{useExperimentSelector-DRbj6vse.js → useExperimentSelector-BMjzNcf2.js} +4 -255
- package/dist/useExperimentSelector-BMjzNcf2.js.map +1 -0
- package/dist/{useFormBuilder-DKekvXRs.js → useFormBuilder-BXaaDI41.js} +2 -2
- package/dist/{useFormBuilder-DKekvXRs.js.map → useFormBuilder-BXaaDI41.js.map} +1 -1
- package/dist/{useAnalysisArtifacts-C3l0a0vu.js → useProtocolTemplates-BP7_4RGQ.js} +307 -475
- package/dist/useProtocolTemplates-BP7_4RGQ.js.map +1 -0
- package/package.json +7 -3
- package/src/__tests__/components/GeneratedPathInput.test.ts +132 -0
- package/src/__tests__/components/GeneratedPlotlyResult.test.ts +117 -0
- package/src/__tests__/components/GeneratedPluginView.test.ts +230 -0
- package/src/__tests__/components/GeneratedResultRenderer.test.ts +93 -0
- package/src/__tests__/components/InstrumentAlertLog.test.ts +59 -0
- package/src/__tests__/composables/formBuilderRegistry.test.ts +5 -1
- package/src/__tests__/composables/useAnalysisArtifacts.test.ts +1 -74
- package/src/__tests__/composables/useApi.test.ts +8 -0
- package/src/__tests__/composables/useGeneratedAnalysis.test.ts +1740 -0
- package/src/__tests__/composables/useJobsStatusTray.test.ts +179 -1
- package/src/__tests__/composables/usePlatformContext.test.ts +28 -0
- package/src/__tests__/composables/usePluginClient.test.ts +366 -20
- package/src/__tests__/composables/usePluginConfig.test.ts +323 -7
- package/src/__tests__/docs/extractDocsTemplates.test.ts +0 -1
- package/src/__tests__/generatedUi.test.ts +119 -0
- package/src/__tests__/templates/templates.test.ts +1 -1
- package/src/components/FileUploader.vue +49 -11
- package/src/components/GeneratedPathInput.vue +218 -0
- package/src/components/GeneratedPlotlyResult.vue +87 -0
- package/src/components/GeneratedPluginView.vue +279 -0
- package/src/components/GeneratedResultRenderer.vue +137 -0
- package/src/components/InstrumentAlertLog.vue +2 -2
- package/src/components/JobsStatusTray.vue +14 -8
- package/src/components/index.ts +4 -0
- package/src/composables/formBuilderRegistry.ts +2 -0
- package/src/composables/index.ts +18 -5
- package/src/composables/platformContextHelpers.ts +3 -10
- package/src/composables/useAnalysisArtifacts.ts +0 -48
- package/src/composables/useApi.ts +1 -0
- package/src/composables/useGeneratedAnalysis.ts +1252 -0
- package/src/composables/useJobsStatusTray.ts +234 -45
- package/src/composables/usePluginClient.ts +152 -25
- package/src/composables/usePluginConfig.ts +156 -20
- package/src/generated/schema.ts +130 -0
- package/src/generated-ui/main.ts +21 -0
- package/src/index.ts +3 -0
- package/src/jobs.ts +5 -0
- package/src/plotly-dist.d.ts +3 -0
- package/src/templates/packs.ts +0 -3
- package/src/types/analysisArtifactTypes.ts +0 -9
- package/src/types/form-builder.ts +1 -0
- package/src/types/generated-ui.ts +176 -0
- package/src/types/index.ts +2 -1
- package/src/types/instrument.ts +1 -0
- package/src/types/jobs.ts +10 -1
- package/src/types/platform.ts +2 -0
- package/dist/BaseButton-Dgqrze41.js +0 -74
- package/dist/BaseButton-Dgqrze41.js.map +0 -1
- package/dist/BaseModal-B9UA8Y_I.js +0 -165
- package/dist/BaseModal-B9UA8Y_I.js.map +0 -1
- package/dist/BaseSelect-ekgr9fDo.js +0 -179
- package/dist/BaseSelect-ekgr9fDo.js.map +0 -1
- package/dist/ExperimentPopover-Ryusjrhv.js +0 -4
- package/dist/ExperimentSelectorModal-Cg4-LXBD.js +0 -5
- package/dist/ExperimentSelectorModal-DZeSd-yr.js.map +0 -1
- package/dist/SettingsModal-Bl_9w2Y3.js +0 -5
- package/dist/analysisArtifactTypes-Cu40dzSG.js.map +0 -1
- package/dist/components-DdzHh3a_.js.map +0 -1
- package/dist/composables/analysisArtifactTarget.d.ts +0 -5
- package/dist/composables-BUUphBqg.js.map +0 -1
- package/dist/experiment-utils-Bfa7CwPU.js +0 -108
- package/dist/experiment-utils-Bfa7CwPU.js.map +0 -1
- package/dist/templates-CNbPQNID.js.map +0 -1
- package/dist/useAnalysisArtifacts-C3l0a0vu.js.map +0 -1
- package/dist/useControlSchema-BZNdalmL.js.map +0 -1
- package/dist/useEventListener-CfVkP9Xz.js +0 -57
- package/dist/useEventListener-CfVkP9Xz.js.map +0 -1
- package/dist/useExperimentSelector-DRbj6vse.js.map +0 -1
- package/src/__tests__/composables/analysisArtifactTarget.test.ts +0 -77
- package/src/composables/analysisArtifactTarget.ts +0 -53
- /package/dist/__tests__/{composables/analysisArtifactTarget.test.d.ts → components/GeneratedPathInput.test.d.ts} +0 -0
package/src/index.ts
CHANGED
package/src/jobs.ts
CHANGED
|
@@ -43,6 +43,11 @@ export function normalizeJobState(job: JobStateInput): JobState {
|
|
|
43
43
|
const capabilities = resolveJobCapabilities(job)
|
|
44
44
|
return {
|
|
45
45
|
...job,
|
|
46
|
+
definition_id: job.definition_id
|
|
47
|
+
?? (typeof job.metadata.definition_id === 'string' ? job.metadata.definition_id : null),
|
|
48
|
+
result_status: job.result_status
|
|
49
|
+
?? (job.status === 'completed' && job.metadata.has_result === true ? 'available' : 'none'),
|
|
50
|
+
result_expires_at: job.result_expires_at ?? null,
|
|
46
51
|
progress: {
|
|
47
52
|
...job.progress,
|
|
48
53
|
percent: normalizeJobPercent(job.progress.percent),
|
package/src/templates/packs.ts
CHANGED
|
@@ -13,7 +13,6 @@ export interface BioTemplatePackEntry {
|
|
|
13
13
|
frontend_adapters: readonly string[]
|
|
14
14
|
components: readonly string[]
|
|
15
15
|
add_command: string
|
|
16
|
-
init_command: string
|
|
17
16
|
docs_command: string
|
|
18
17
|
}
|
|
19
18
|
|
|
@@ -55,7 +54,6 @@ function createPack(definition: BioTemplatePackDefinition): BioTemplatePackEntry
|
|
|
55
54
|
frontend_adapters: collectTemplateField(definition.templates, 'frontend_adapters'),
|
|
56
55
|
components: collectTemplateField(definition.templates, 'components'),
|
|
57
56
|
add_command: `mint add data-template-pack ${definition.name} --page`,
|
|
58
|
-
init_command: `mint init --template ${definition.name}`,
|
|
59
57
|
docs_command: `mint docs template-pack ${definition.name}`,
|
|
60
58
|
}
|
|
61
59
|
}
|
|
@@ -155,7 +153,6 @@ export function searchBioTemplatePacks(query: string): readonly BioTemplatePackE
|
|
|
155
153
|
entry.label,
|
|
156
154
|
entry.purpose,
|
|
157
155
|
entry.add_command,
|
|
158
|
-
entry.init_command,
|
|
159
156
|
entry.docs_command,
|
|
160
157
|
...entry.templates,
|
|
161
158
|
...entry.aliases,
|
|
@@ -38,15 +38,6 @@ export interface AnalysisArtifactListResponse {
|
|
|
38
38
|
artifacts: AnalysisArtifactSummary[]
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
/** Stable identity used when one plugin opens another plugin's artifact. */
|
|
42
|
-
export interface AnalysisArtifactTarget {
|
|
43
|
-
experimentId: number
|
|
44
|
-
artifactPluginId: string
|
|
45
|
-
artifactKey: string
|
|
46
|
-
/** Optional lookup hint. The stable identity remains the three fields above. */
|
|
47
|
-
artifactId?: number
|
|
48
|
-
}
|
|
49
|
-
|
|
50
41
|
/** Body of PATCH /experiments/{id}/analysis-artifacts/{artifactId}. */
|
|
51
42
|
export interface AnalysisArtifactMetadataUpdate {
|
|
52
43
|
display_name?: string
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import type { JobState, JobStateInput } from './jobs'
|
|
2
|
+
|
|
3
|
+
export interface GeneratedJsonSchema {
|
|
4
|
+
type?: string | string[]
|
|
5
|
+
format?: string
|
|
6
|
+
title?: string
|
|
7
|
+
description?: string
|
|
8
|
+
default?: unknown
|
|
9
|
+
const?: unknown
|
|
10
|
+
enum?: unknown[]
|
|
11
|
+
minimum?: number
|
|
12
|
+
maximum?: number
|
|
13
|
+
minLength?: number
|
|
14
|
+
maxLength?: number
|
|
15
|
+
properties?: Record<string, GeneratedJsonSchema>
|
|
16
|
+
additionalProperties?: boolean | GeneratedJsonSchema
|
|
17
|
+
required?: string[]
|
|
18
|
+
anyOf?: GeneratedJsonSchema[]
|
|
19
|
+
allOf?: GeneratedJsonSchema[]
|
|
20
|
+
items?: GeneratedJsonSchema
|
|
21
|
+
$ref?: string
|
|
22
|
+
$defs?: Record<string, GeneratedJsonSchema>
|
|
23
|
+
'x-mint-component'?: 'path'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface PluginJobPathInput {
|
|
27
|
+
kind: 'path'
|
|
28
|
+
files: File[]
|
|
29
|
+
relativePaths: string[]
|
|
30
|
+
rootName?: string
|
|
31
|
+
signal?: AbortSignal
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PluginJobPathUpload {
|
|
35
|
+
token: string
|
|
36
|
+
kind: 'file' | 'directory'
|
|
37
|
+
name: string
|
|
38
|
+
size: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface PluginJobStagedPartInput<Metadata = Record<string, unknown>> {
|
|
42
|
+
job: GeneratedAnalysisJob | string
|
|
43
|
+
key: string
|
|
44
|
+
file: Blob
|
|
45
|
+
metadata: Metadata
|
|
46
|
+
expectedSize?: number
|
|
47
|
+
expectedSha256?: string
|
|
48
|
+
signal?: AbortSignal
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface PluginJobStagedPart<Metadata = unknown> {
|
|
52
|
+
key: string
|
|
53
|
+
size: number
|
|
54
|
+
sha256: string
|
|
55
|
+
metadata: Metadata
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface PluginJobStagingSummary {
|
|
59
|
+
job_id: string
|
|
60
|
+
sealed: boolean
|
|
61
|
+
part_count: number
|
|
62
|
+
total_bytes: number
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface PluginJobStagedPartUploadResult<Metadata = unknown> {
|
|
66
|
+
part: PluginJobStagedPart<Metadata>
|
|
67
|
+
staging: PluginJobStagingSummary
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface PluginJobStagingPagination {
|
|
71
|
+
offset?: number
|
|
72
|
+
limit?: number
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface PluginJobStaging<Metadata = unknown> extends PluginJobStagingSummary {
|
|
76
|
+
parts: PluginJobStagedPart<Metadata>[]
|
|
77
|
+
offset: number
|
|
78
|
+
limit: number
|
|
79
|
+
next_offset: number | null
|
|
80
|
+
has_more: boolean
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type GeneratedJobLifecycle = 'process' | 'staged' | 'service'
|
|
84
|
+
|
|
85
|
+
export type GeneratedJobProfile =
|
|
86
|
+
| { kind: 'process' }
|
|
87
|
+
| {
|
|
88
|
+
kind: 'staged'
|
|
89
|
+
partSchema: GeneratedJsonSchema
|
|
90
|
+
minParts: number
|
|
91
|
+
maxParts: number
|
|
92
|
+
maxBytes: number
|
|
93
|
+
}
|
|
94
|
+
| {
|
|
95
|
+
kind: 'service'
|
|
96
|
+
timeoutSeconds: number
|
|
97
|
+
maxConcurrency: number
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface GeneratedJobDefinition {
|
|
101
|
+
id: string
|
|
102
|
+
title: string
|
|
103
|
+
description: string
|
|
104
|
+
cpu: number
|
|
105
|
+
/** Defaults to process for manifests generated before lifecycle profiles. */
|
|
106
|
+
lifecycle?: GeneratedJobLifecycle
|
|
107
|
+
/** Defaults to `{ kind: 'process' }` for older manifests. */
|
|
108
|
+
profile?: GeneratedJobProfile
|
|
109
|
+
input_schema: GeneratedJsonSchema
|
|
110
|
+
output_schema: GeneratedJsonSchema
|
|
111
|
+
result_schema?: GeneratedJsonSchema
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface GeneratedAnalysisManifest {
|
|
115
|
+
schema_version: '1'
|
|
116
|
+
plugin: {
|
|
117
|
+
name: string
|
|
118
|
+
version: string
|
|
119
|
+
description: string
|
|
120
|
+
routes_prefix: string
|
|
121
|
+
}
|
|
122
|
+
ui: {
|
|
123
|
+
title: string
|
|
124
|
+
description: string
|
|
125
|
+
}
|
|
126
|
+
jobs: GeneratedJobDefinition[]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface GeneratedSession {
|
|
130
|
+
id: string
|
|
131
|
+
tab_id: string
|
|
132
|
+
created_at: string
|
|
133
|
+
last_seen_at: string
|
|
134
|
+
active_job_ids: string[]
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export type GeneratedAnalysisResult =
|
|
138
|
+
| { kind: 'text'; text: string }
|
|
139
|
+
| { kind: 'json'; value: unknown }
|
|
140
|
+
| { kind: 'table'; columns: string[]; rows: Record<string, unknown>[] }
|
|
141
|
+
| { kind: 'image'; media_type: string; data: string; alt: string }
|
|
142
|
+
| {
|
|
143
|
+
kind: 'plotly'
|
|
144
|
+
spec: Record<string, unknown>
|
|
145
|
+
fallback?: { media_type: 'image/png'; data: string }
|
|
146
|
+
}
|
|
147
|
+
| {
|
|
148
|
+
kind: 'artifact'
|
|
149
|
+
id: string
|
|
150
|
+
name: string
|
|
151
|
+
media_type: string
|
|
152
|
+
size: number | null
|
|
153
|
+
data?: string
|
|
154
|
+
download_url?: string
|
|
155
|
+
download_expires_at?: string
|
|
156
|
+
sha256?: string
|
|
157
|
+
managed?: boolean
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface GeneratedAnalysisJobInput extends JobStateInput {
|
|
161
|
+
definition_id?: string | null
|
|
162
|
+
metadata: JobStateInput['metadata'] & {
|
|
163
|
+
definition_id?: string
|
|
164
|
+
client_request_id?: string
|
|
165
|
+
has_result?: boolean
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Canonical job state exposed after transport payloads cross the SDK boundary. */
|
|
170
|
+
export interface GeneratedAnalysisJob extends JobState {
|
|
171
|
+
metadata: JobState['metadata'] & {
|
|
172
|
+
definition_id?: string
|
|
173
|
+
client_request_id?: string
|
|
174
|
+
has_result?: boolean
|
|
175
|
+
}
|
|
176
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -176,13 +176,14 @@ export type {
|
|
|
176
176
|
TreeNode,
|
|
177
177
|
} from './components'
|
|
178
178
|
|
|
179
|
+
export type * from './generated-ui'
|
|
180
|
+
|
|
179
181
|
export type {
|
|
180
182
|
AnalysisArtifactStatus,
|
|
181
183
|
AnalysisArtifactStatusFilter,
|
|
182
184
|
AnalysisArtifactSummary,
|
|
183
185
|
AnalysisArtifactDetail,
|
|
184
186
|
AnalysisArtifactListResponse,
|
|
185
|
-
AnalysisArtifactTarget,
|
|
186
187
|
AnalysisArtifactMetadataUpdate,
|
|
187
188
|
ArtifactSaveMode,
|
|
188
189
|
ArtifactFileSource,
|
package/src/types/instrument.ts
CHANGED
package/src/types/jobs.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface JobState {
|
|
|
22
22
|
job_id: string
|
|
23
23
|
kind: string
|
|
24
24
|
name: string
|
|
25
|
+
definition_id: string | null
|
|
25
26
|
status: JobStatus
|
|
26
27
|
progress: JobProgress
|
|
27
28
|
queue_position: number
|
|
@@ -42,12 +43,20 @@ export interface JobState {
|
|
|
42
43
|
completed_at: string | null
|
|
43
44
|
can_cancel: boolean
|
|
44
45
|
can_delete: boolean
|
|
46
|
+
result_status: 'none' | 'available' | 'expired'
|
|
47
|
+
result_expires_at: string | null
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
/** Backward-compatible transport shape accepted from pre-capability backends. */
|
|
48
|
-
export type JobStateInput = Omit<
|
|
51
|
+
export type JobStateInput = Omit<
|
|
52
|
+
JobState,
|
|
53
|
+
'can_cancel' | 'can_delete' | 'definition_id' | 'result_status' | 'result_expires_at'
|
|
54
|
+
> & {
|
|
49
55
|
can_cancel?: boolean | null
|
|
50
56
|
can_delete?: boolean | null
|
|
57
|
+
definition_id?: string | null
|
|
58
|
+
result_status?: 'none' | 'available' | 'expired'
|
|
59
|
+
result_expires_at?: string | null
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
export interface JobListPayload {
|
package/src/types/platform.ts
CHANGED
|
@@ -10,6 +10,8 @@ export interface PluginInfo {
|
|
|
10
10
|
color?: string
|
|
11
11
|
route_prefix: string
|
|
12
12
|
api_prefix: string
|
|
13
|
+
/** Settings route selected by the platform for this plugin runtime. */
|
|
14
|
+
settings_api?: 'plugin' | 'platform'
|
|
13
15
|
nav_items?: PluginNavItem[]
|
|
14
16
|
settings?: PluginSettings
|
|
15
17
|
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeClass, openBlock, renderSlot } from "vue";
|
|
2
|
-
//#region src/components/BaseButton.vue?vue&type=script&setup=true&lang.ts
|
|
3
|
-
var _hoisted_1 = ["type", "disabled"];
|
|
4
|
-
var _hoisted_2 = {
|
|
5
|
-
key: 0,
|
|
6
|
-
class: "mint-button__spinner",
|
|
7
|
-
fill: "none",
|
|
8
|
-
viewBox: "0 0 24 24"
|
|
9
|
-
};
|
|
10
|
-
//#endregion
|
|
11
|
-
//#region src/components/BaseButton.vue
|
|
12
|
-
var BaseButton_default = /* @__PURE__ */ defineComponent({
|
|
13
|
-
__name: "BaseButton",
|
|
14
|
-
props: {
|
|
15
|
-
variant: { default: "primary" },
|
|
16
|
-
size: { default: "md" },
|
|
17
|
-
disabled: {
|
|
18
|
-
type: Boolean,
|
|
19
|
-
default: false
|
|
20
|
-
},
|
|
21
|
-
loading: {
|
|
22
|
-
type: Boolean,
|
|
23
|
-
default: false
|
|
24
|
-
},
|
|
25
|
-
type: { default: "button" },
|
|
26
|
-
fullWidth: {
|
|
27
|
-
type: Boolean,
|
|
28
|
-
default: false
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
emits: ["click"],
|
|
32
|
-
setup(__props, { emit: __emit }) {
|
|
33
|
-
/** Renders a styled `<button>` with variant, size, loading spinner, and full-width options. */
|
|
34
|
-
const props = __props;
|
|
35
|
-
const emit = __emit;
|
|
36
|
-
function handleClick(event) {
|
|
37
|
-
if (!props.disabled && !props.loading) emit("click", event);
|
|
38
|
-
}
|
|
39
|
-
return (_ctx, _cache) => {
|
|
40
|
-
return openBlock(), createElementBlock("button", {
|
|
41
|
-
type: __props.type,
|
|
42
|
-
disabled: __props.disabled || __props.loading,
|
|
43
|
-
class: normalizeClass([
|
|
44
|
-
"mint-button",
|
|
45
|
-
`mint-button--${__props.variant}`,
|
|
46
|
-
`mint-button--${__props.size}`,
|
|
47
|
-
__props.fullWidth ? "mint-button--full-width" : "",
|
|
48
|
-
__props.disabled || __props.loading ? "mint-button--disabled" : ""
|
|
49
|
-
]),
|
|
50
|
-
onClick: handleClick
|
|
51
|
-
}, [
|
|
52
|
-
__props.loading ? (openBlock(), createElementBlock("svg", _hoisted_2, [..._cache[0] || (_cache[0] = [createElementVNode("circle", {
|
|
53
|
-
style: { "opacity": "0.25" },
|
|
54
|
-
cx: "12",
|
|
55
|
-
cy: "12",
|
|
56
|
-
r: "10",
|
|
57
|
-
stroke: "currentColor",
|
|
58
|
-
"stroke-width": "4"
|
|
59
|
-
}, null, -1), createElementVNode("path", {
|
|
60
|
-
style: { "opacity": "0.75" },
|
|
61
|
-
fill: "currentColor",
|
|
62
|
-
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
63
|
-
}, null, -1)])])) : createCommentVNode("", true),
|
|
64
|
-
renderSlot(_ctx.$slots, "icon-left"),
|
|
65
|
-
renderSlot(_ctx.$slots, "default"),
|
|
66
|
-
renderSlot(_ctx.$slots, "icon-right")
|
|
67
|
-
], 10, _hoisted_1);
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
//#endregion
|
|
72
|
-
export { BaseButton_default as t };
|
|
73
|
-
|
|
74
|
-
//# sourceMappingURL=BaseButton-Dgqrze41.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BaseButton-Dgqrze41.js","names":[],"sources":["../src/components/BaseButton.vue","../src/components/BaseButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/** Renders a styled `<button>` with variant, size, loading spinner, and full-width options. */\nimport type { ButtonVariant, ButtonSize } from '../types'\n\ninterface Props {\n variant?: ButtonVariant\n size?: ButtonSize\n disabled?: boolean\n loading?: boolean\n type?: 'button' | 'submit' | 'reset'\n fullWidth?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n fullWidth: false,\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nfunction handleClick(event: MouseEvent) {\n if (!props.disabled && !props.loading) {\n emit('click', event)\n }\n}\n</script>\n\n<template>\n <button\n :type=\"type\"\n :disabled=\"disabled || loading\"\n :class=\"[\n 'mint-button',\n `mint-button--${variant}`,\n `mint-button--${size}`,\n fullWidth ? 'mint-button--full-width' : '',\n (disabled || loading) ? 'mint-button--disabled' : '',\n ]\"\n @click=\"handleClick\"\n >\n <svg\n v-if=\"loading\"\n class=\"mint-button__spinner\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n style=\"opacity: 0.25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n />\n <path\n style=\"opacity: 0.75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <slot name=\"icon-left\" />\n <slot />\n <slot name=\"icon-right\" />\n </button>\n</template>\n\n<style>\n@import '../styles/components/button.css';\n</style>\n","<script setup lang=\"ts\">\n/** Renders a styled `<button>` with variant, size, loading spinner, and full-width options. */\nimport type { ButtonVariant, ButtonSize } from '../types'\n\ninterface Props {\n variant?: ButtonVariant\n size?: ButtonSize\n disabled?: boolean\n loading?: boolean\n type?: 'button' | 'submit' | 'reset'\n fullWidth?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n fullWidth: false,\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nfunction handleClick(event: MouseEvent) {\n if (!props.disabled && !props.loading) {\n emit('click', event)\n }\n}\n</script>\n\n<template>\n <button\n :type=\"type\"\n :disabled=\"disabled || loading\"\n :class=\"[\n 'mint-button',\n `mint-button--${variant}`,\n `mint-button--${size}`,\n fullWidth ? 'mint-button--full-width' : '',\n (disabled || loading) ? 'mint-button--disabled' : '',\n ]\"\n @click=\"handleClick\"\n >\n <svg\n v-if=\"loading\"\n class=\"mint-button__spinner\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n style=\"opacity: 0.25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n />\n <path\n style=\"opacity: 0.75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <slot name=\"icon-left\" />\n <slot />\n <slot name=\"icon-right\" />\n </button>\n</template>\n\n<style>\n@import '../styles/components/button.css';\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECaA,MAAM,QAAQ;EASd,MAAM,OAAO;EAIb,SAAS,YAAY,OAAmB;AACtC,OAAI,CAAC,MAAM,YAAY,CAAC,MAAM,QAC5B,MAAK,SAAS,MAAK;;;uBAMrB,mBAmCS,UAAA;IAlCN,MAAM,QAAA;IACN,UAAU,QAAA,YAAY,QAAA;IACtB,OAAK,eAAA;;qBAA+C,QAAA;qBAAiC,QAAA;KAAc,QAAA,YAAS,4BAAA;KAA0C,QAAA,YAAY,QAAA,UAAO,0BAAA;;IAOzK,SAAO;;IAGA,QAAA,WAAA,WAAA,EADR,mBAmBM,OAnBN,YAmBM,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAbJ,mBAOE,UAAA;KANA,OAAA,EAAA,WAAA,QAAqB;KACrB,IAAG;KACH,IAAG;KACH,GAAE;KACF,QAAO;KACP,gBAAa;kBAEf,mBAIE,QAAA;KAHA,OAAA,EAAA,WAAA,QAAqB;KACrB,MAAK;KACL,GAAE;;IAGN,WAAyB,KAAA,QAAA,YAAA;IACzB,WAAQ,KAAA,QAAA,UAAA;IACR,WAA0B,KAAA,QAAA,aAAA"}
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { t as useEventListener } from "./useEventListener-CfVkP9Xz.js";
|
|
2
|
-
import { Teleport, Transition, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, onUnmounted, openBlock, ref, renderSlot, toDisplayString, watch, withCtx } from "vue";
|
|
3
|
-
//#region src/components/BaseModal.vue?vue&type=script&setup=true&lang.ts
|
|
4
|
-
var _hoisted_1 = {
|
|
5
|
-
key: 0,
|
|
6
|
-
class: "mint-modal__grab-hint",
|
|
7
|
-
"aria-hidden": "true"
|
|
8
|
-
};
|
|
9
|
-
var _hoisted_2 = {
|
|
10
|
-
key: 1,
|
|
11
|
-
class: "mint-modal__header"
|
|
12
|
-
};
|
|
13
|
-
var _hoisted_3 = {
|
|
14
|
-
key: 0,
|
|
15
|
-
class: "mint-modal__header-text"
|
|
16
|
-
};
|
|
17
|
-
var _hoisted_4 = {
|
|
18
|
-
key: 0,
|
|
19
|
-
class: "mint-modal__title"
|
|
20
|
-
};
|
|
21
|
-
var _hoisted_5 = {
|
|
22
|
-
key: 1,
|
|
23
|
-
class: "mint-modal__subtitle"
|
|
24
|
-
};
|
|
25
|
-
var _hoisted_6 = { class: "mint-modal__body" };
|
|
26
|
-
var _hoisted_7 = {
|
|
27
|
-
key: 2,
|
|
28
|
-
class: "mint-modal__footer"
|
|
29
|
-
};
|
|
30
|
-
//#endregion
|
|
31
|
-
//#region src/components/BaseModal.vue
|
|
32
|
-
var BaseModal_default = /* @__PURE__ */ defineComponent({
|
|
33
|
-
__name: "BaseModal",
|
|
34
|
-
props: {
|
|
35
|
-
modelValue: { type: Boolean },
|
|
36
|
-
title: {},
|
|
37
|
-
subtitle: {},
|
|
38
|
-
size: { default: "md" },
|
|
39
|
-
variant: { default: "centered" },
|
|
40
|
-
closable: {
|
|
41
|
-
type: Boolean,
|
|
42
|
-
default: true
|
|
43
|
-
},
|
|
44
|
-
closeOnOverlay: {
|
|
45
|
-
type: Boolean,
|
|
46
|
-
default: false
|
|
47
|
-
},
|
|
48
|
-
closeOnEscape: {
|
|
49
|
-
type: Boolean,
|
|
50
|
-
default: true
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
emits: ["update:modelValue", "close"],
|
|
54
|
-
setup(__props, { emit: __emit }) {
|
|
55
|
-
/** Modal dialog with backdrop, focus trap, Escape-to-close, and configurable size/variant. */
|
|
56
|
-
const props = __props;
|
|
57
|
-
const emit = __emit;
|
|
58
|
-
const containerRef = ref(null);
|
|
59
|
-
let previouslyFocused = null;
|
|
60
|
-
const FOCUSABLE_SELECTOR = [
|
|
61
|
-
"a[href]",
|
|
62
|
-
"button:not([disabled])",
|
|
63
|
-
"input:not([disabled])",
|
|
64
|
-
"select:not([disabled])",
|
|
65
|
-
"textarea:not([disabled])",
|
|
66
|
-
"[tabindex]:not([tabindex=\"-1\"])"
|
|
67
|
-
].join(", ");
|
|
68
|
-
function getFocusableElements() {
|
|
69
|
-
if (!containerRef.value) return [];
|
|
70
|
-
return Array.from(containerRef.value.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
71
|
-
}
|
|
72
|
-
function handleKeydown(event) {
|
|
73
|
-
if (event.key === "Escape" && props.closeOnEscape && props.modelValue) {
|
|
74
|
-
close();
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
if (event.key !== "Tab" || !containerRef.value) return;
|
|
78
|
-
const focusable = getFocusableElements();
|
|
79
|
-
if (focusable.length === 0) {
|
|
80
|
-
event.preventDefault();
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const first = focusable[0];
|
|
84
|
-
const last = focusable[focusable.length - 1];
|
|
85
|
-
if (event.shiftKey && document.activeElement === first) {
|
|
86
|
-
event.preventDefault();
|
|
87
|
-
last.focus();
|
|
88
|
-
} else if (!event.shiftKey && document.activeElement === last) {
|
|
89
|
-
event.preventDefault();
|
|
90
|
-
first.focus();
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function close() {
|
|
94
|
-
if (props.closable) {
|
|
95
|
-
emit("update:modelValue", false);
|
|
96
|
-
emit("close");
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
function handleOverlayClick(event) {
|
|
100
|
-
if (props.closeOnOverlay && event.target === event.currentTarget) close();
|
|
101
|
-
}
|
|
102
|
-
watch(() => props.modelValue, async (isOpen) => {
|
|
103
|
-
if (isOpen) {
|
|
104
|
-
previouslyFocused = document.activeElement;
|
|
105
|
-
document.body.style.overflow = "hidden";
|
|
106
|
-
await nextTick();
|
|
107
|
-
const focusable = getFocusableElements();
|
|
108
|
-
if (focusable.length > 0) focusable[0].focus();
|
|
109
|
-
else containerRef.value?.focus();
|
|
110
|
-
} else {
|
|
111
|
-
document.body.style.overflow = "";
|
|
112
|
-
previouslyFocused?.focus();
|
|
113
|
-
previouslyFocused = null;
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
useEventListener(() => document, "keydown", handleKeydown);
|
|
117
|
-
onUnmounted(() => {
|
|
118
|
-
document.body.style.overflow = "";
|
|
119
|
-
});
|
|
120
|
-
return (_ctx, _cache) => {
|
|
121
|
-
return openBlock(), createBlock(Teleport, { to: "body" }, [createVNode(Transition, { name: `modal-${__props.variant}` }, {
|
|
122
|
-
default: withCtx(() => [__props.modelValue ? (openBlock(), createElementBlock("div", {
|
|
123
|
-
key: 0,
|
|
124
|
-
class: normalizeClass(["mint-modal", `mint-modal--${__props.variant}`]),
|
|
125
|
-
onClick: handleOverlayClick
|
|
126
|
-
}, [_cache[1] || (_cache[1] = createElementVNode("div", { class: "mint-modal__overlay" }, null, -1)), createElementVNode("div", {
|
|
127
|
-
ref_key: "containerRef",
|
|
128
|
-
ref: containerRef,
|
|
129
|
-
class: normalizeClass([
|
|
130
|
-
"mint-modal__container",
|
|
131
|
-
`mint-modal__container--${__props.size}`,
|
|
132
|
-
`mint-modal__container--${__props.variant}`
|
|
133
|
-
]),
|
|
134
|
-
role: "dialog",
|
|
135
|
-
"aria-modal": "true",
|
|
136
|
-
tabindex: "-1"
|
|
137
|
-
}, [
|
|
138
|
-
__props.variant === "sheet" ? (openBlock(), createElementBlock("div", _hoisted_1)) : createCommentVNode("", true),
|
|
139
|
-
__props.title || __props.subtitle || __props.closable || _ctx.$slots.header ? (openBlock(), createElementBlock("div", _hoisted_2, [__props.title || __props.subtitle || _ctx.$slots.header ? (openBlock(), createElementBlock("div", _hoisted_3, [renderSlot(_ctx.$slots, "header", {}, () => [__props.title ? (openBlock(), createElementBlock("h3", _hoisted_4, toDisplayString(__props.title), 1)) : createCommentVNode("", true), __props.subtitle ? (openBlock(), createElementBlock("p", _hoisted_5, toDisplayString(__props.subtitle), 1)) : createCommentVNode("", true)])])) : createCommentVNode("", true), __props.closable ? (openBlock(), createElementBlock("button", {
|
|
140
|
-
key: 1,
|
|
141
|
-
type: "button",
|
|
142
|
-
class: "mint-modal__close",
|
|
143
|
-
"aria-label": "Close modal",
|
|
144
|
-
onClick: close
|
|
145
|
-
}, [..._cache[0] || (_cache[0] = [createElementVNode("svg", {
|
|
146
|
-
class: "mint-modal__close-icon",
|
|
147
|
-
fill: "none",
|
|
148
|
-
stroke: "currentColor",
|
|
149
|
-
"stroke-width": "2",
|
|
150
|
-
"stroke-linecap": "round",
|
|
151
|
-
"stroke-linejoin": "round",
|
|
152
|
-
viewBox: "0 0 24 24"
|
|
153
|
-
}, [createElementVNode("path", { d: "M18 6 6 18" }), createElementVNode("path", { d: "m6 6 12 12" })], -1)])])) : createCommentVNode("", true)])) : createCommentVNode("", true),
|
|
154
|
-
createElementVNode("div", _hoisted_6, [renderSlot(_ctx.$slots, "default")]),
|
|
155
|
-
_ctx.$slots.footer ? (openBlock(), createElementBlock("div", _hoisted_7, [renderSlot(_ctx.$slots, "footer")])) : createCommentVNode("", true)
|
|
156
|
-
], 2)], 2)) : createCommentVNode("", true)]),
|
|
157
|
-
_: 3
|
|
158
|
-
}, 8, ["name"])]);
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
//#endregion
|
|
163
|
-
export { BaseModal_default as t };
|
|
164
|
-
|
|
165
|
-
//# sourceMappingURL=BaseModal-B9UA8Y_I.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BaseModal-B9UA8Y_I.js","names":["$slots"],"sources":["../src/components/BaseModal.vue","../src/components/BaseModal.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/** Modal dialog with backdrop, focus trap, Escape-to-close, and configurable size/variant. */\nimport { ref, watch, nextTick, onUnmounted } from 'vue'\nimport type { ModalSize, ModalVariant } from '../types'\nimport { useEventListener } from '../composables/useEventListener'\n\ninterface Props {\n modelValue: boolean\n title?: string\n subtitle?: string\n size?: ModalSize\n variant?: ModalVariant\n closable?: boolean\n closeOnOverlay?: boolean\n closeOnEscape?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'centered',\n closable: true,\n closeOnOverlay: false,\n closeOnEscape: true,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n close: []\n}>()\n\nconst containerRef = ref<HTMLElement | null>(null)\nlet previouslyFocused: HTMLElement | null = null\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ')\n\nfunction getFocusableElements(): HTMLElement[] {\n if (!containerRef.value) return []\n return Array.from(containerRef.value.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR))\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && props.closeOnEscape && props.modelValue) {\n close()\n return\n }\n\n if (event.key !== 'Tab' || !containerRef.value) return\n\n const focusable = getFocusableElements()\n if (focusable.length === 0) {\n event.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault()\n last.focus()\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault()\n first.focus()\n }\n}\n\nfunction close() {\n if (props.closable) {\n emit('update:modelValue', false)\n emit('close')\n }\n}\n\nfunction handleOverlayClick(event: MouseEvent) {\n if (props.closeOnOverlay && event.target === event.currentTarget) {\n close()\n }\n}\n\nwatch(() => props.modelValue, async (isOpen) => {\n if (isOpen) {\n previouslyFocused = document.activeElement as HTMLElement | null\n document.body.style.overflow = 'hidden'\n await nextTick()\n const focusable = getFocusableElements()\n if (focusable.length > 0) {\n focusable[0].focus()\n } else {\n containerRef.value?.focus()\n }\n } else {\n document.body.style.overflow = ''\n previouslyFocused?.focus()\n previouslyFocused = null\n }\n})\n\nuseEventListener(() => document, 'keydown', handleKeydown)\n\nonUnmounted(() => {\n document.body.style.overflow = ''\n})\n</script>\n\n<template>\n <Teleport to=\"body\">\n <Transition :name=\"`modal-${variant}`\">\n <div\n v-if=\"modelValue\"\n :class=\"['mint-modal', `mint-modal--${variant}`]\"\n @click=\"handleOverlayClick\"\n >\n <!-- Overlay -->\n <div class=\"mint-modal__overlay\" />\n\n <!-- Modal -->\n <div\n ref=\"containerRef\"\n :class=\"[\n 'mint-modal__container',\n `mint-modal__container--${size}`,\n `mint-modal__container--${variant}`,\n ]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n >\n <!-- Sheet grab-hint bar (sheet variant only) -->\n <div v-if=\"variant === 'sheet'\" class=\"mint-modal__grab-hint\" aria-hidden=\"true\" />\n\n <!-- Header -->\n <div v-if=\"title || subtitle || closable || $slots.header\" class=\"mint-modal__header\">\n <div v-if=\"title || subtitle || $slots.header\" class=\"mint-modal__header-text\">\n <slot name=\"header\">\n <h3 v-if=\"title\" class=\"mint-modal__title\">\n {{ title }}\n </h3>\n <p v-if=\"subtitle\" class=\"mint-modal__subtitle\">\n {{ subtitle }}\n </p>\n </slot>\n </div>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"mint-modal__close\"\n aria-label=\"Close modal\"\n @click=\"close\"\n >\n <svg class=\"mint-modal__close-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"mint-modal__body\">\n <slot />\n </div>\n\n <!-- Footer -->\n <div v-if=\"$slots.footer\" class=\"mint-modal__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n</template>\n\n<style>\n@import '../styles/components/modal.css';\n</style>\n","<script setup lang=\"ts\">\n/** Modal dialog with backdrop, focus trap, Escape-to-close, and configurable size/variant. */\nimport { ref, watch, nextTick, onUnmounted } from 'vue'\nimport type { ModalSize, ModalVariant } from '../types'\nimport { useEventListener } from '../composables/useEventListener'\n\ninterface Props {\n modelValue: boolean\n title?: string\n subtitle?: string\n size?: ModalSize\n variant?: ModalVariant\n closable?: boolean\n closeOnOverlay?: boolean\n closeOnEscape?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'centered',\n closable: true,\n closeOnOverlay: false,\n closeOnEscape: true,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n close: []\n}>()\n\nconst containerRef = ref<HTMLElement | null>(null)\nlet previouslyFocused: HTMLElement | null = null\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ')\n\nfunction getFocusableElements(): HTMLElement[] {\n if (!containerRef.value) return []\n return Array.from(containerRef.value.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR))\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && props.closeOnEscape && props.modelValue) {\n close()\n return\n }\n\n if (event.key !== 'Tab' || !containerRef.value) return\n\n const focusable = getFocusableElements()\n if (focusable.length === 0) {\n event.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault()\n last.focus()\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault()\n first.focus()\n }\n}\n\nfunction close() {\n if (props.closable) {\n emit('update:modelValue', false)\n emit('close')\n }\n}\n\nfunction handleOverlayClick(event: MouseEvent) {\n if (props.closeOnOverlay && event.target === event.currentTarget) {\n close()\n }\n}\n\nwatch(() => props.modelValue, async (isOpen) => {\n if (isOpen) {\n previouslyFocused = document.activeElement as HTMLElement | null\n document.body.style.overflow = 'hidden'\n await nextTick()\n const focusable = getFocusableElements()\n if (focusable.length > 0) {\n focusable[0].focus()\n } else {\n containerRef.value?.focus()\n }\n } else {\n document.body.style.overflow = ''\n previouslyFocused?.focus()\n previouslyFocused = null\n }\n})\n\nuseEventListener(() => document, 'keydown', handleKeydown)\n\nonUnmounted(() => {\n document.body.style.overflow = ''\n})\n</script>\n\n<template>\n <Teleport to=\"body\">\n <Transition :name=\"`modal-${variant}`\">\n <div\n v-if=\"modelValue\"\n :class=\"['mint-modal', `mint-modal--${variant}`]\"\n @click=\"handleOverlayClick\"\n >\n <!-- Overlay -->\n <div class=\"mint-modal__overlay\" />\n\n <!-- Modal -->\n <div\n ref=\"containerRef\"\n :class=\"[\n 'mint-modal__container',\n `mint-modal__container--${size}`,\n `mint-modal__container--${variant}`,\n ]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n >\n <!-- Sheet grab-hint bar (sheet variant only) -->\n <div v-if=\"variant === 'sheet'\" class=\"mint-modal__grab-hint\" aria-hidden=\"true\" />\n\n <!-- Header -->\n <div v-if=\"title || subtitle || closable || $slots.header\" class=\"mint-modal__header\">\n <div v-if=\"title || subtitle || $slots.header\" class=\"mint-modal__header-text\">\n <slot name=\"header\">\n <h3 v-if=\"title\" class=\"mint-modal__title\">\n {{ title }}\n </h3>\n <p v-if=\"subtitle\" class=\"mint-modal__subtitle\">\n {{ subtitle }}\n </p>\n </slot>\n </div>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"mint-modal__close\"\n aria-label=\"Close modal\"\n @click=\"close\"\n >\n <svg class=\"mint-modal__close-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"mint-modal__body\">\n <slot />\n </div>\n\n <!-- Footer -->\n <div v-if=\"$slots.footer\" class=\"mint-modal__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n</template>\n\n<style>\n@import '../styles/components/modal.css';\n</style>\n"],"mappings":"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"}
|