@thunderid/react 1.16.0 → 1.17.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.
Files changed (47) hide show
  1. package/dist/cjs/components/management/FlowVariables/BaseFlowVariables.cjs +210 -0
  2. package/dist/cjs/components/management/FlowVariables/BaseFlowVariables.cjs.map +1 -0
  3. package/dist/cjs/components/management/FlowVariables/FlowVariableField.cjs +162 -0
  4. package/dist/cjs/components/management/FlowVariables/FlowVariableField.cjs.map +1 -0
  5. package/dist/cjs/components/management/FlowVariables/FlowVariables.styles.cjs +123 -0
  6. package/dist/cjs/components/management/FlowVariables/FlowVariables.styles.cjs.map +1 -0
  7. package/dist/cjs/components/management/FlowVariables/FlowVariablesForm.cjs +50 -0
  8. package/dist/cjs/components/management/FlowVariables/FlowVariablesForm.cjs.map +1 -0
  9. package/dist/cjs/components/management/SharedFlowList/BaseSharedFlowList.cjs +78 -0
  10. package/dist/cjs/components/management/SharedFlowList/BaseSharedFlowList.cjs.map +1 -0
  11. package/dist/cjs/components/management/SharedFlowList/SharedFlowList.cjs +69 -0
  12. package/dist/cjs/components/management/SharedFlowList/SharedFlowList.cjs.map +1 -0
  13. package/dist/cjs/hooks/management/useFlowVariables.cjs +107 -0
  14. package/dist/cjs/hooks/management/useFlowVariables.cjs.map +1 -0
  15. package/dist/cjs/index.cjs +48 -0
  16. package/dist/components/management/FlowVariables/BaseFlowVariables.d.ts +124 -0
  17. package/dist/components/management/FlowVariables/BaseFlowVariables.d.ts.map +1 -0
  18. package/dist/components/management/FlowVariables/BaseFlowVariables.js +206 -0
  19. package/dist/components/management/FlowVariables/BaseFlowVariables.js.map +1 -0
  20. package/dist/components/management/FlowVariables/FlowVariableField.d.ts +46 -0
  21. package/dist/components/management/FlowVariables/FlowVariableField.d.ts.map +1 -0
  22. package/dist/components/management/FlowVariables/FlowVariableField.js +158 -0
  23. package/dist/components/management/FlowVariables/FlowVariableField.js.map +1 -0
  24. package/dist/components/management/FlowVariables/FlowVariables.styles.d.ts +11 -0
  25. package/dist/components/management/FlowVariables/FlowVariables.styles.d.ts.map +1 -0
  26. package/dist/components/management/FlowVariables/FlowVariables.styles.js +121 -0
  27. package/dist/components/management/FlowVariables/FlowVariables.styles.js.map +1 -0
  28. package/dist/components/management/FlowVariables/FlowVariablesForm.d.ts +30 -0
  29. package/dist/components/management/FlowVariables/FlowVariablesForm.d.ts.map +1 -0
  30. package/dist/components/management/FlowVariables/FlowVariablesForm.js +47 -0
  31. package/dist/components/management/FlowVariables/FlowVariablesForm.js.map +1 -0
  32. package/dist/components/management/SharedFlowList/BaseSharedFlowList.d.ts +53 -0
  33. package/dist/components/management/SharedFlowList/BaseSharedFlowList.d.ts.map +1 -0
  34. package/dist/components/management/SharedFlowList/BaseSharedFlowList.js +76 -0
  35. package/dist/components/management/SharedFlowList/BaseSharedFlowList.js.map +1 -0
  36. package/dist/components/management/SharedFlowList/SharedFlowList.d.ts +32 -0
  37. package/dist/components/management/SharedFlowList/SharedFlowList.d.ts.map +1 -0
  38. package/dist/components/management/SharedFlowList/SharedFlowList.js +65 -0
  39. package/dist/components/management/SharedFlowList/SharedFlowList.js.map +1 -0
  40. package/dist/hooks/management/useFlowVariables.d.ts +84 -0
  41. package/dist/hooks/management/useFlowVariables.d.ts.map +1 -0
  42. package/dist/hooks/management/useFlowVariables.js +104 -0
  43. package/dist/hooks/management/useFlowVariables.js.map +1 -0
  44. package/dist/index.d.ts +14 -2
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +8 -2
  47. package/package.json +2 -2
@@ -0,0 +1,206 @@
1
+ import useTheme_default from "../../../contexts/Theme/useTheme.js";
2
+ import useTranslation_default from "../../../hooks/useTranslation.js";
3
+ import Button_default from "../../primitives/Button/Button.js";
4
+ import Alert_default from "../../primitives/Alert/Alert.js";
5
+ import AdminSection_default from "../shared/AdminSection.js";
6
+ import FlowVariables_styles_default from "./FlowVariables.styles.js";
7
+ import FlowVariableField_default from "./FlowVariableField.js";
8
+ import { getFlowVariableOptions, resolveFlowVariableRule, validateFlowVariableValue } from "@thunderid/browser";
9
+ import { Fragment, useEffect, useMemo, useRef, useState } from "react";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
+
12
+ //#region src/components/management/FlowVariables/BaseFlowVariables.tsx
13
+ const startingValuesOf = (variables, overlay, initialValues) => variables.reduce((values, definition) => {
14
+ const { defaultValue, editable } = resolveFlowVariableRule(definition, overlay);
15
+ const chosen = editable ? initialValues?.[definition.identifier] ?? defaultValue : defaultValue;
16
+ if (chosen !== void 0 && chosen !== null) values[definition.identifier] = chosen;
17
+ return values;
18
+ }, {});
19
+ /**
20
+ * A form for the variables a flow declares, each in a card with its label, its description, whether it is
21
+ * customized or follows the default, and the input its type calls for. It is what a delegated admin sees when
22
+ * overriding a flow, and what the flow editor previews. Holds no data of its own: pass the variables and handle
23
+ * the submission.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * <BaseFlowVariables variables={variables} connections={connections} overlay={overlay} onSubmit={save} />
28
+ * ```
29
+ */
30
+ const BaseFlowVariables = ({ children, className, connections = [], description, error = null, initialValues, isSubmitting = false, onCancel, onChange, onCreateConnection, onSubmit, ouName, overlay, ownerName, preferences, readOnly = false, renderField, renderFieldAction, showScopeNotice = false, title, variables }) => {
31
+ const { theme, colorScheme } = useTheme_default();
32
+ const styles = FlowVariables_styles_default(theme, colorScheme);
33
+ const { t } = useTranslation_default(preferences?.i18n);
34
+ const startingValues = useMemo(() => startingValuesOf(variables, overlay, initialValues), [
35
+ JSON.stringify(variables),
36
+ JSON.stringify(overlay),
37
+ JSON.stringify(initialValues)
38
+ ]);
39
+ const [values, setValues] = useState(startingValues);
40
+ const [touched, setTouched] = useState({});
41
+ const [submitted, setSubmitted] = useState(false);
42
+ const appliedValues = useRef(startingValues);
43
+ useEffect(() => {
44
+ if (appliedValues.current !== startingValues) {
45
+ appliedValues.current = startingValues;
46
+ setValues(startingValues);
47
+ setTouched({});
48
+ setSubmitted(false);
49
+ }
50
+ }, [startingValues]);
51
+ const getRule = (definition) => resolveFlowVariableRule(definition, overlay);
52
+ const getOptions = (definition) => {
53
+ const { allowedValues, editable, excludedValues } = getRule(definition);
54
+ return getFlowVariableOptions(definition, connections, editable ? {
55
+ allowedValues,
56
+ excludedValues
57
+ } : {});
58
+ };
59
+ const errors = {};
60
+ let isValid = true;
61
+ variables.forEach((definition) => {
62
+ if (!getRule(definition).editable) return;
63
+ const problem = validateFlowVariableValue(definition, values[definition.identifier]);
64
+ if (problem) {
65
+ isValid = false;
66
+ if (submitted || touched[definition.identifier]) errors[definition.identifier] = problem.message ?? t(`admin.flowVariables.errors.${problem.code}`);
67
+ }
68
+ });
69
+ const handleChange = (identifier, value) => {
70
+ const next = {
71
+ ...values,
72
+ [identifier]: value
73
+ };
74
+ setValues(next);
75
+ setTouched((previous) => ({
76
+ ...previous,
77
+ [identifier]: true
78
+ }));
79
+ onChange?.(next);
80
+ };
81
+ const resetToDefaults = () => {
82
+ const next = variables.reduce((accumulated, definition) => {
83
+ const { defaultValue } = getRule(definition);
84
+ if (defaultValue !== void 0) accumulated[definition.identifier] = defaultValue;
85
+ return accumulated;
86
+ }, {});
87
+ setValues(next);
88
+ setTouched({});
89
+ setSubmitted(false);
90
+ onChange?.(next);
91
+ };
92
+ const submit = () => {
93
+ setSubmitted(true);
94
+ if (!isValid) return;
95
+ const overrides = variables.reduce((accumulated, definition) => {
96
+ const { defaultValue, editable } = getRule(definition);
97
+ const value = values[definition.identifier];
98
+ if (editable && value !== void 0 && value !== defaultValue) accumulated[definition.identifier] = value;
99
+ return accumulated;
100
+ }, {});
101
+ onSubmit?.(values, overrides);
102
+ };
103
+ const handleSubmit = (event) => {
104
+ event.preventDefault();
105
+ submit();
106
+ };
107
+ if (children) return /* @__PURE__ */ jsx("div", {
108
+ className,
109
+ children: children({
110
+ error,
111
+ errors,
112
+ getOptions,
113
+ getRule,
114
+ handleChange,
115
+ handleSubmit: submit,
116
+ isSubmitting,
117
+ isValid,
118
+ onCancel,
119
+ resetToDefaults,
120
+ values,
121
+ variables
122
+ })
123
+ });
124
+ const ou = ouName ?? t("admin.flowVariables.ou_fallback");
125
+ return /* @__PURE__ */ jsx(AdminSection_default, {
126
+ block: "flow-variables",
127
+ className,
128
+ title,
129
+ description,
130
+ preferences,
131
+ children: /* @__PURE__ */ jsxs("form", {
132
+ className: styles["form"],
133
+ onSubmit: handleSubmit,
134
+ noValidate: true,
135
+ children: [
136
+ showScopeNotice && /* @__PURE__ */ jsxs(Alert_default, {
137
+ variant: "info",
138
+ children: [/* @__PURE__ */ jsx(Alert_default.Title, { children: t("admin.flowVariables.notice_title", { ou }) }), /* @__PURE__ */ jsx(Alert_default.Description, { children: t("admin.flowVariables.notice_body", { ou }) })]
139
+ }),
140
+ error && /* @__PURE__ */ jsx(Alert_default, {
141
+ variant: "error",
142
+ role: "alert",
143
+ children: error
144
+ }),
145
+ variables.length === 0 && /* @__PURE__ */ jsx("p", {
146
+ className: styles["empty"],
147
+ children: t("admin.flowVariables.empty")
148
+ }),
149
+ variables.map((definition, index) => {
150
+ const rule = getRule(definition);
151
+ const key = `${index}-${definition.identifier}`;
152
+ const field = /* @__PURE__ */ jsx(FlowVariableField_default, {
153
+ action: renderFieldAction?.(definition, index),
154
+ definition,
155
+ defaultValue: rule.defaultValue,
156
+ disabled: readOnly || isSubmitting,
157
+ editable: rule.editable,
158
+ error: errors[definition.identifier],
159
+ hint: definition.type === "CONNECTION_SELECT" && rule.editable ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", { children: t("admin.flowVariables.connections_hint", { ou }) }), onCreateConnection && /* @__PURE__ */ jsx("button", {
160
+ type: "button",
161
+ className: styles["link"],
162
+ onClick: onCreateConnection,
163
+ children: t("admin.flowVariables.create_connection")
164
+ })] }) : void 0,
165
+ options: getOptions(definition),
166
+ ownerName,
167
+ value: values[definition.identifier],
168
+ onChange: (value) => handleChange(definition.identifier, value)
169
+ });
170
+ return /* @__PURE__ */ jsx(Fragment, { children: renderField ? renderField(field, definition, index) : field }, key);
171
+ }),
172
+ onSubmit && !readOnly && variables.length > 0 && /* @__PURE__ */ jsxs("div", {
173
+ className: styles["actions"],
174
+ children: [
175
+ /* @__PURE__ */ jsx(Button_default, {
176
+ type: "button",
177
+ variant: "text",
178
+ onClick: resetToDefaults,
179
+ disabled: isSubmitting,
180
+ children: t("admin.flowVariables.reset_defaults")
181
+ }),
182
+ /* @__PURE__ */ jsx("div", { className: styles["actionsSpacer"] }),
183
+ onCancel && /* @__PURE__ */ jsx(Button_default, {
184
+ type: "button",
185
+ variant: "text",
186
+ onClick: onCancel,
187
+ disabled: isSubmitting,
188
+ children: t("admin.common.actions.cancel")
189
+ }),
190
+ /* @__PURE__ */ jsx(Button_default, {
191
+ type: "submit",
192
+ loading: isSubmitting,
193
+ disabled: isSubmitting,
194
+ children: t("admin.flowVariables.submit")
195
+ })
196
+ ]
197
+ })
198
+ ]
199
+ })
200
+ });
201
+ };
202
+ var BaseFlowVariables_default = BaseFlowVariables;
203
+
204
+ //#endregion
205
+ export { BaseFlowVariables_default as default };
206
+ //# sourceMappingURL=BaseFlowVariables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseFlowVariables.js","names":["chosen: FlowVariableValue | undefined","BaseFlowVariables: FC<BaseFlowVariablesProps>","useTheme","styles: Record<string, string>","useStyles","useTranslation","startingValues: FlowVariableValues","appliedValues: {current: FlowVariableValues}","errors: Record<string, string>","problem: FlowVariableValidationError | undefined","next: FlowVariableValues","overrides: FlowVariableValues","value: FlowVariableValue | undefined","ou: string","AdminSection","Alert","rule: ResolvedFlowVariableRule","field: ReactElement","FlowVariableField","Button"],"sources":["../../../../src/components/management/FlowVariables/BaseFlowVariables.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n ConnectionInstance,\n FlowVariableDefinition,\n FlowVariableOption,\n FlowVariableValidationError,\n FlowVariableValue,\n FlowVariableValues,\n Preferences,\n ResolvedFlowVariableRule,\n ResolvedOverlay,\n getFlowVariableOptions,\n resolveFlowVariableRule,\n validateFlowVariableValue,\n} from '@thunderid/browser';\nimport {FC, Fragment, FormEvent, ReactElement, ReactNode, useEffect, useMemo, useRef, useState} from 'react';\nimport FlowVariableField from './FlowVariableField';\nimport useStyles from './FlowVariables.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport useTranslation from '../../../hooks/useTranslation';\nimport Alert from '../../primitives/Alert/Alert';\nimport Button from '../../primitives/Button/Button';\nimport AdminSection from '../shared/AdminSection';\n\n/**\n * What {@link BaseFlowVariables} hands its `children` render function, so the form can be built with any UI.\n */\nexport interface BaseFlowVariablesRenderProps {\n error: string | null;\n /**\n * The message to show under each variable that is not valid, keyed by identifier.\n */\n errors: Record<string, string>;\n /**\n * The choices of a select variable, narrowed to what the unit may pick.\n */\n getOptions: (definition: FlowVariableDefinition) => FlowVariableOption[];\n /**\n * What the unit may do with a variable: whether it can set its own value, and the default it starts from.\n */\n getRule: (definition: FlowVariableDefinition) => ResolvedFlowVariableRule;\n /**\n * Sets the value of one variable.\n */\n handleChange: (identifier: string, value: FlowVariableValue) => void;\n /**\n * Submits the current values. Does nothing while they are not valid.\n */\n handleSubmit: () => void;\n isSubmitting: boolean;\n /**\n * Whether the values can be submitted.\n */\n isValid: boolean;\n onCancel?: () => void;\n /**\n * Returns every variable the unit may set to its default.\n */\n resetToDefaults: () => void;\n values: FlowVariableValues;\n variables: FlowVariableDefinition[];\n}\n\nexport interface BaseFlowVariablesProps {\n /**\n * Renders custom UI in place of the default form. Receives the variables, their values and setters, and the\n * submit handler.\n */\n children?: (props: BaseFlowVariablesRenderProps) => ReactNode;\n className?: string;\n /**\n * The connections a `CONNECTION_SELECT` variable can take.\n */\n connections?: Pick<ConnectionInstance, 'categories' | 'id' | 'name' | 'type'>[];\n description?: string;\n error?: string | null;\n /**\n * The values the form starts with, over each variable's default. A variable left out starts at its default.\n */\n initialValues?: FlowVariableValues;\n isSubmitting?: boolean;\n onCancel?: () => void;\n /**\n * Called when the user asks to create a connection, from the hint under a connection variable. Without it, the\n * hint does not offer one.\n */\n onCreateConnection?: () => void;\n /**\n * Called with every value after one changes.\n */\n onChange?: (values: FlowVariableValues) => void;\n /**\n * Called when the form is submitted and valid, with every value and the overrides: the values of the variables\n * the unit may set that differ from their default. Without it the form has no save button, which suits a preview.\n */\n onSubmit?: (values: FlowVariableValues, overrides: FlowVariableValues) => void;\n /**\n * What the unit may do with each variable, as `getFlowOverlayRules` returns it. Without it every variable is\n * editable, which suits a preview.\n */\n overlay?: ResolvedOverlay;\n /**\n * The name of the organization unit the variables are set for, used in the notice and the connection hint.\n */\n ouName?: string;\n /**\n * The name of whoever owns the flow, shown on a variable the unit may not set.\n */\n ownerName?: string;\n preferences?: Preferences;\n /**\n * Shows the variables without letting them be changed.\n */\n readOnly?: boolean;\n /**\n * Wraps the card of each variable, so a host can add its own controls around it, such as selecting or removing the\n * variable while it is being designed. Receives the card, the variable and its position.\n */\n renderField?: (field: ReactElement, definition: FlowVariableDefinition, index: number) => ReactNode;\n /**\n * Content at the end of the label row of each variable, for a control a host adds while designing the variables.\n */\n renderFieldAction?: (definition: FlowVariableDefinition, index: number) => ReactNode;\n /**\n * Shows a notice that the settings apply to the organization unit only. Needs `ouName` to be useful.\n */\n showScopeNotice?: boolean;\n title?: string;\n /**\n * The variables to render, as the flow declares them.\n */\n variables: FlowVariableDefinition[];\n}\n\nconst startingValuesOf = (\n variables: FlowVariableDefinition[],\n overlay: ResolvedOverlay | undefined,\n initialValues: FlowVariableValues | undefined,\n): FlowVariableValues =>\n variables.reduce((values: FlowVariableValues, definition: FlowVariableDefinition) => {\n const {defaultValue, editable}: ResolvedFlowVariableRule = resolveFlowVariableRule(definition, overlay);\n const chosen: FlowVariableValue | undefined = editable\n ? (initialValues?.[definition.identifier] ?? defaultValue)\n : defaultValue;\n\n if (chosen !== undefined && chosen !== null) {\n values[definition.identifier] = chosen;\n }\n\n return values;\n }, {});\n\n/**\n * A form for the variables a flow declares, each in a card with its label, its description, whether it is\n * customized or follows the default, and the input its type calls for. It is what a delegated admin sees when\n * overriding a flow, and what the flow editor previews. Holds no data of its own: pass the variables and handle\n * the submission.\n *\n * @example\n * ```tsx\n * <BaseFlowVariables variables={variables} connections={connections} overlay={overlay} onSubmit={save} />\n * ```\n */\nconst BaseFlowVariables: FC<BaseFlowVariablesProps> = ({\n children,\n className,\n connections = [],\n description,\n error = null,\n initialValues,\n isSubmitting = false,\n onCancel,\n onChange,\n onCreateConnection,\n onSubmit,\n ouName,\n overlay,\n ownerName,\n preferences,\n readOnly = false,\n renderField,\n renderFieldAction,\n showScopeNotice = false,\n title,\n variables,\n}: BaseFlowVariablesProps): ReactElement => {\n const {theme, colorScheme} = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme);\n const {t} = useTranslation(preferences?.i18n);\n\n const startingValues: FlowVariableValues = useMemo(\n () => startingValuesOf(variables, overlay, initialValues),\n // The identity of the inputs can change on every render while their content does not.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(variables), JSON.stringify(overlay), JSON.stringify(initialValues)],\n );\n const [values, setValues] = useState<FlowVariableValues>(startingValues);\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n const [submitted, setSubmitted] = useState<boolean>(false);\n const appliedValues: {current: FlowVariableValues} = useRef(startingValues);\n\n // The form already holds the starting values on mount; only a change to them replaces what was typed.\n useEffect(() => {\n if (appliedValues.current !== startingValues) {\n appliedValues.current = startingValues;\n setValues(startingValues);\n setTouched({});\n setSubmitted(false);\n }\n }, [startingValues]);\n\n const getRule = (definition: FlowVariableDefinition): ResolvedFlowVariableRule =>\n resolveFlowVariableRule(definition, overlay);\n\n const getOptions = (definition: FlowVariableDefinition): FlowVariableOption[] => {\n const {allowedValues, editable, excludedValues}: ResolvedFlowVariableRule = getRule(definition);\n\n // A variable the unit cannot set shows its pinned value, which a restriction might hide from the choices.\n return getFlowVariableOptions(definition, connections, editable ? {allowedValues, excludedValues} : {});\n };\n\n const errors: Record<string, string> = {};\n let isValid = true;\n\n variables.forEach((definition: FlowVariableDefinition) => {\n if (!getRule(definition).editable) {\n return;\n }\n\n const problem: FlowVariableValidationError | undefined = validateFlowVariableValue(\n definition,\n values[definition.identifier],\n );\n\n if (problem) {\n isValid = false;\n\n if (submitted || touched[definition.identifier]) {\n errors[definition.identifier] = problem.message ?? t(`admin.flowVariables.errors.${problem.code}`);\n }\n }\n });\n\n const handleChange = (identifier: string, value: FlowVariableValue): void => {\n const next: FlowVariableValues = {...values, [identifier]: value};\n\n setValues(next);\n setTouched((previous: Record<string, boolean>) => ({...previous, [identifier]: true}));\n onChange?.(next);\n };\n\n const resetToDefaults = (): void => {\n const next: FlowVariableValues = variables.reduce(\n (accumulated: FlowVariableValues, definition: FlowVariableDefinition) => {\n const {defaultValue}: ResolvedFlowVariableRule = getRule(definition);\n\n if (defaultValue !== undefined) {\n accumulated[definition.identifier] = defaultValue;\n }\n\n return accumulated;\n },\n {},\n );\n\n setValues(next);\n setTouched({});\n setSubmitted(false);\n onChange?.(next);\n };\n\n const submit = (): void => {\n setSubmitted(true);\n\n if (!isValid) {\n return;\n }\n\n const overrides: FlowVariableValues = variables.reduce(\n (accumulated: FlowVariableValues, definition: FlowVariableDefinition) => {\n const {defaultValue, editable}: ResolvedFlowVariableRule = getRule(definition);\n const value: FlowVariableValue | undefined = values[definition.identifier];\n\n if (editable && value !== undefined && value !== defaultValue) {\n accumulated[definition.identifier] = value;\n }\n\n return accumulated;\n },\n {},\n );\n\n onSubmit?.(values, overrides);\n };\n\n const handleSubmit = (event: FormEvent<HTMLFormElement>): void => {\n event.preventDefault();\n submit();\n };\n\n if (children) {\n return (\n <div className={className}>\n {children({\n error,\n errors,\n getOptions,\n getRule,\n handleChange,\n handleSubmit: submit,\n isSubmitting,\n isValid,\n onCancel,\n resetToDefaults,\n values,\n variables,\n })}\n </div>\n );\n }\n\n const ou: string = ouName ?? t('admin.flowVariables.ou_fallback');\n\n return (\n <AdminSection\n block=\"flow-variables\"\n className={className}\n title={title}\n description={description}\n preferences={preferences}\n >\n <form className={styles['form']} onSubmit={handleSubmit} noValidate>\n {showScopeNotice && (\n <Alert variant=\"info\">\n <Alert.Title>{t('admin.flowVariables.notice_title', {ou})}</Alert.Title>\n <Alert.Description>{t('admin.flowVariables.notice_body', {ou})}</Alert.Description>\n </Alert>\n )}\n {error && (\n <Alert variant=\"error\" role=\"alert\">\n {error}\n </Alert>\n )}\n {variables.length === 0 && <p className={styles['empty']}>{t('admin.flowVariables.empty')}</p>}\n {variables.map((definition: FlowVariableDefinition, index: number) => {\n const rule: ResolvedFlowVariableRule = getRule(definition);\n // An identifier can be repeated while a flow's variables are being edited, so it cannot be the key alone.\n const key = `${index}-${definition.identifier}`;\n\n const field: ReactElement = (\n <FlowVariableField\n action={renderFieldAction?.(definition, index)}\n definition={definition}\n defaultValue={rule.defaultValue}\n disabled={readOnly || isSubmitting}\n editable={rule.editable}\n error={errors[definition.identifier]}\n hint={\n definition.type === 'CONNECTION_SELECT' && rule.editable ? (\n <>\n <span>{t('admin.flowVariables.connections_hint', {ou})}</span>\n {onCreateConnection && (\n <button type=\"button\" className={styles['link']} onClick={onCreateConnection}>\n {t('admin.flowVariables.create_connection')}\n </button>\n )}\n </>\n ) : undefined\n }\n options={getOptions(definition)}\n ownerName={ownerName}\n value={values[definition.identifier]}\n onChange={(value: FlowVariableValue): void => handleChange(definition.identifier, value)}\n />\n );\n\n return <Fragment key={key}>{renderField ? renderField(field, definition, index) : field}</Fragment>;\n })}\n {onSubmit && !readOnly && variables.length > 0 && (\n <div className={styles['actions']}>\n <Button type=\"button\" variant=\"text\" onClick={resetToDefaults} disabled={isSubmitting}>\n {t('admin.flowVariables.reset_defaults')}\n </Button>\n <div className={styles['actionsSpacer']} />\n {onCancel && (\n <Button type=\"button\" variant=\"text\" onClick={onCancel} disabled={isSubmitting}>\n {t('admin.common.actions.cancel')}\n </Button>\n )}\n <Button type=\"submit\" loading={isSubmitting} disabled={isSubmitting}>\n {t('admin.flowVariables.submit')}\n </Button>\n </div>\n )}\n </form>\n </AdminSection>\n );\n};\n\nexport default BaseFlowVariables;\n"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { FlowVariableDefinition, FlowVariableValue, SelectOption } from '@thunderid/browser';
2
+ import { FC, ReactNode } from 'react';
3
+ export interface FlowVariableFieldProps {
4
+ /**
5
+ * Extra content at the end of the label row, such as a control a host adds while the variable is being designed.
6
+ */
7
+ action?: ReactNode;
8
+ className?: string;
9
+ /**
10
+ * The value the variable has until the unit sets its own, which a sharing policy may have set.
11
+ */
12
+ defaultValue?: FlowVariableValue;
13
+ definition: FlowVariableDefinition;
14
+ disabled?: boolean;
15
+ /**
16
+ * Whether the unit may set its own value. A variable it may not set is shown as set by its owner.
17
+ * @default true
18
+ */
19
+ editable?: boolean;
20
+ /**
21
+ * The error to show under the field.
22
+ */
23
+ error?: string;
24
+ /**
25
+ * Extra text under the input, such as where the choices come from.
26
+ */
27
+ hint?: ReactNode;
28
+ onChange: (value: FlowVariableValue) => void;
29
+ /**
30
+ * The choices of a `SELECT` or `CONNECTION_SELECT`, as {@link getFlowVariableOptions} returns them.
31
+ */
32
+ options?: SelectOption[];
33
+ /**
34
+ * Who set the variable, shown while it is not editable.
35
+ */
36
+ ownerName?: string;
37
+ value: FlowVariableValue | undefined;
38
+ }
39
+ /**
40
+ * One variable as the delegated admin sees it, in a card: its label and description, whether it is customized
41
+ * or follows the default, the input its type calls for, and what the default is. A variable the unit may not set
42
+ * is shown as set by its owner.
43
+ */
44
+ declare const FlowVariableField: FC<FlowVariableFieldProps>;
45
+ export default FlowVariableField;
46
+ //# sourceMappingURL=FlowVariableField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowVariableField.d.ts","sourceRoot":"","sources":["../../../../src/components/management/FlowVariables/FlowVariableField.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,EAGb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAc,EAAE,EAAgB,SAAS,EAAQ,MAAM,OAAO,CAAC;AAStE,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,UAAU,EAAE,sBAAsB,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC7C;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACtC;AAUD;;;;GAIG;AACH,QAAA,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CA+KjD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,158 @@
1
+ import { cx } from "../../../styles/emotion.js";
2
+ import useTheme_default from "../../../contexts/Theme/useTheme.js";
3
+ import useTranslation_default from "../../../hooks/useTranslation.js";
4
+ import Toggle_default from "../../primitives/Toggle/Toggle.js";
5
+ import TextField_default from "../../primitives/TextField/TextField.js";
6
+ import Select_default from "../../primitives/Select/Select.js";
7
+ import FlowVariables_styles_default from "./FlowVariables.styles.js";
8
+ import { bem, withVendorCSSClassPrefix } from "@thunderid/browser";
9
+ import { useId } from "react";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
+
12
+ //#region src/components/management/FlowVariables/FlowVariableField.tsx
13
+ const INPUT_TYPES = {
14
+ DATE_INPUT: "date",
15
+ EMAIL_INPUT: "email",
16
+ NUMBER_INPUT: "number",
17
+ PHONE_INPUT: "tel",
18
+ TEXT_INPUT: "text"
19
+ };
20
+ /**
21
+ * One variable as the delegated admin sees it, in a card: its label and description, whether it is customized
22
+ * or follows the default, the input its type calls for, and what the default is. A variable the unit may not set
23
+ * is shown as set by its owner.
24
+ */
25
+ const FlowVariableField = ({ action, className, defaultValue, definition, disabled, editable = true, error, hint, onChange, options = [], ownerName, value }) => {
26
+ const { theme, colorScheme } = useTheme_default();
27
+ const styles = FlowVariables_styles_default(theme, colorScheme);
28
+ const { t } = useTranslation_default();
29
+ const id = useId();
30
+ const descriptionId = definition.description ? `${id}-description` : void 0;
31
+ const label = definition.label ?? definition.identifier;
32
+ const isSelect = definition.type === "SELECT" || definition.type === "CONNECTION_SELECT";
33
+ const isDefault = value === defaultValue;
34
+ const display = (shown) => {
35
+ if (shown === void 0) return "";
36
+ if (typeof shown === "boolean") return t(shown ? "admin.flowVariables.on" : "admin.flowVariables.off");
37
+ return isSelect ? options.find((option) => String(option.value) === String(shown))?.label ?? String(shown) : String(shown);
38
+ };
39
+ const renderControl = () => {
40
+ switch (definition.type) {
41
+ case "BOOLEAN_INPUT": return /* @__PURE__ */ jsx(Toggle_default, {
42
+ id,
43
+ "aria-label": label,
44
+ "aria-describedby": descriptionId,
45
+ checked: value === true,
46
+ disabled: disabled === true || !editable,
47
+ error,
48
+ onChange: (event) => onChange(event.target.checked)
49
+ });
50
+ case "SELECT":
51
+ case "CONNECTION_SELECT": {
52
+ const handleSelect = (event) => {
53
+ const chosen = (definition.options ?? []).find((option) => String(option) === event.target.value);
54
+ onChange(event.target.value === "" && defaultValue !== void 0 ? defaultValue : chosen ?? event.target.value);
55
+ };
56
+ return /* @__PURE__ */ jsx(Select_default, {
57
+ id,
58
+ "aria-label": label,
59
+ "aria-describedby": descriptionId,
60
+ disabled,
61
+ emptyText: t("admin.flowVariables.no_options"),
62
+ error,
63
+ options,
64
+ placeholder: defaultValue === void 0 || defaultValue === "" ? t("admin.flowVariables.select_placeholder") : t("admin.flowVariables.use_default", { default: display(defaultValue) }),
65
+ value: isDefault || value === void 0 ? "" : String(value),
66
+ onChange: handleSelect
67
+ });
68
+ }
69
+ default: return /* @__PURE__ */ jsx(TextField_default, {
70
+ id,
71
+ "aria-label": label,
72
+ "aria-describedby": descriptionId,
73
+ disabled,
74
+ error,
75
+ max: definition.max,
76
+ min: definition.min,
77
+ placeholder: defaultValue === void 0 || defaultValue === "" ? t("admin.flowVariables.enter_value") : display(defaultValue),
78
+ type: INPUT_TYPES[definition.type] ?? "text",
79
+ value: value === void 0 ? "" : String(value),
80
+ onChange: (event) => {
81
+ const raw = event.target.value;
82
+ onChange(definition.type === "NUMBER_INPUT" && raw !== "" && !Number.isNaN(Number(raw)) ? Number(raw) : raw);
83
+ }
84
+ });
85
+ }
86
+ };
87
+ return /* @__PURE__ */ jsxs("section", {
88
+ className: cx(withVendorCSSClassPrefix(bem("flow-variables", "field")), withVendorCSSClassPrefix(bem("flow-variables", "field", definition.type.toLowerCase())), styles["card"], !editable && styles["cardLocked"], className),
89
+ "data-variable": definition.identifier,
90
+ "data-editable": editable,
91
+ children: [/* @__PURE__ */ jsxs("div", {
92
+ className: styles["header"],
93
+ children: [
94
+ /* @__PURE__ */ jsxs("div", {
95
+ className: styles["headerText"],
96
+ children: [/* @__PURE__ */ jsx("label", {
97
+ htmlFor: id,
98
+ className: styles["label"],
99
+ children: label
100
+ }), definition.description && /* @__PURE__ */ jsx("p", {
101
+ id: descriptionId,
102
+ className: styles["description"],
103
+ children: definition.description
104
+ })]
105
+ }),
106
+ editable && !isDefault && /* @__PURE__ */ jsx("span", {
107
+ className: styles["chipCustomized"],
108
+ "data-testid": "flow-variable-status",
109
+ children: t("admin.flowVariables.status.customized")
110
+ }),
111
+ action
112
+ ]
113
+ }), editable ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
114
+ renderControl(),
115
+ hint && /* @__PURE__ */ jsx("p", {
116
+ className: styles["hint"],
117
+ children: hint
118
+ }),
119
+ !isDefault && defaultValue !== void 0 && /* @__PURE__ */ jsx("p", {
120
+ className: styles["hint"],
121
+ children: t("admin.flowVariables.default_hint", { default: display(defaultValue) })
122
+ })
123
+ ] }) : /* @__PURE__ */ jsxs("div", {
124
+ className: styles["lockedLine"],
125
+ children: [
126
+ /* @__PURE__ */ jsxs("svg", {
127
+ width: "16",
128
+ height: "16",
129
+ viewBox: "0 0 24 24",
130
+ fill: "none",
131
+ stroke: "currentColor",
132
+ strokeWidth: "1.7",
133
+ strokeLinecap: "round",
134
+ strokeLinejoin: "round",
135
+ "aria-hidden": "true",
136
+ children: [/* @__PURE__ */ jsx("rect", {
137
+ x: "5",
138
+ y: "11",
139
+ width: "14",
140
+ height: "9",
141
+ rx: "2"
142
+ }), /* @__PURE__ */ jsx("path", { d: "M8 11V8a4 4 0 018 0v3" })]
143
+ }),
144
+ /* @__PURE__ */ jsxs("span", { children: [
145
+ t("admin.flowVariables.locked", { owner: ownerName ?? t("admin.flowVariables.owner_fallback") }),
146
+ " · ",
147
+ display(value)
148
+ ] }),
149
+ definition.type === "BOOLEAN_INPUT" && renderControl()
150
+ ]
151
+ })]
152
+ });
153
+ };
154
+ var FlowVariableField_default = FlowVariableField;
155
+
156
+ //#endregion
157
+ export { FlowVariableField_default as default };
158
+ //# sourceMappingURL=FlowVariableField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowVariableField.js","names":["INPUT_TYPES: Partial<Record<FlowVariableDefinition['type'], string>>","FlowVariableField: FC<FlowVariableFieldProps>","useTheme","styles: Record<string, string>","useStyles","useTranslation","id: string","descriptionId: string | undefined","label: string","isSelect: boolean","isDefault: boolean","Toggle","chosen: FlowVariableValue | undefined","Select","TextField","raw: string"],"sources":["../../../../src/components/management/FlowVariables/FlowVariableField.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n FlowVariableDefinition,\n FlowVariableValue,\n SelectOption,\n bem,\n withVendorCSSClassPrefix,\n} from '@thunderid/browser';\nimport {ChangeEvent, FC, ReactElement, ReactNode, useId} from 'react';\nimport useStyles from './FlowVariables.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport useTranslation from '../../../hooks/useTranslation';\nimport {cx} from '../../../styles/emotion';\nimport Select from '../../primitives/Select/Select';\nimport TextField from '../../primitives/TextField/TextField';\nimport Toggle from '../../primitives/Toggle/Toggle';\n\nexport interface FlowVariableFieldProps {\n /**\n * Extra content at the end of the label row, such as a control a host adds while the variable is being designed.\n */\n action?: ReactNode;\n className?: string;\n /**\n * The value the variable has until the unit sets its own, which a sharing policy may have set.\n */\n defaultValue?: FlowVariableValue;\n definition: FlowVariableDefinition;\n disabled?: boolean;\n /**\n * Whether the unit may set its own value. A variable it may not set is shown as set by its owner.\n * @default true\n */\n editable?: boolean;\n /**\n * The error to show under the field.\n */\n error?: string;\n /**\n * Extra text under the input, such as where the choices come from.\n */\n hint?: ReactNode;\n onChange: (value: FlowVariableValue) => void;\n /**\n * The choices of a `SELECT` or `CONNECTION_SELECT`, as {@link getFlowVariableOptions} returns them.\n */\n options?: SelectOption[];\n /**\n * Who set the variable, shown while it is not editable.\n */\n ownerName?: string;\n value: FlowVariableValue | undefined;\n}\n\nconst INPUT_TYPES: Partial<Record<FlowVariableDefinition['type'], string>> = {\n DATE_INPUT: 'date',\n EMAIL_INPUT: 'email',\n NUMBER_INPUT: 'number',\n PHONE_INPUT: 'tel',\n TEXT_INPUT: 'text',\n};\n\n/**\n * One variable as the delegated admin sees it, in a card: its label and description, whether it is customized\n * or follows the default, the input its type calls for, and what the default is. A variable the unit may not set\n * is shown as set by its owner.\n */\nconst FlowVariableField: FC<FlowVariableFieldProps> = ({\n action,\n className,\n defaultValue,\n definition,\n disabled,\n editable = true,\n error,\n hint,\n onChange,\n options = [],\n ownerName,\n value,\n}: FlowVariableFieldProps): ReactElement => {\n const {theme, colorScheme} = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme);\n const {t} = useTranslation();\n const id: string = useId();\n const descriptionId: string | undefined = definition.description ? `${id}-description` : undefined;\n const label: string = definition.label ?? definition.identifier;\n const isSelect: boolean = definition.type === 'SELECT' || definition.type === 'CONNECTION_SELECT';\n const isDefault: boolean = value === defaultValue;\n\n const display = (shown: FlowVariableValue | undefined): string => {\n if (shown === undefined) {\n return '';\n }\n if (typeof shown === 'boolean') {\n return t(shown ? 'admin.flowVariables.on' : 'admin.flowVariables.off');\n }\n\n return isSelect\n ? (options.find((option: SelectOption) => String(option.value) === String(shown))?.label ?? String(shown))\n : String(shown);\n };\n\n const renderControl = (): ReactElement => {\n switch (definition.type) {\n case 'BOOLEAN_INPUT':\n return (\n <Toggle\n id={id}\n aria-label={label}\n aria-describedby={descriptionId}\n checked={value === true}\n disabled={disabled === true || !editable}\n error={error}\n onChange={(event: ChangeEvent<HTMLInputElement>): void => onChange(event.target.checked)}\n />\n );\n case 'SELECT':\n case 'CONNECTION_SELECT': {\n const handleSelect = (event: ChangeEvent<HTMLSelectElement>): void => {\n const chosen: FlowVariableValue | undefined = (definition.options ?? []).find(\n (option: FlowVariableValue) => String(option) === event.target.value,\n );\n\n // The first entry, the default, clears the choice.\n onChange(\n event.target.value === '' && defaultValue !== undefined ? defaultValue : (chosen ?? event.target.value),\n );\n };\n\n return (\n <Select\n id={id}\n aria-label={label}\n aria-describedby={descriptionId}\n disabled={disabled}\n emptyText={t('admin.flowVariables.no_options')}\n error={error}\n options={options}\n placeholder={\n defaultValue === undefined || defaultValue === ''\n ? t('admin.flowVariables.select_placeholder')\n : t('admin.flowVariables.use_default', {default: display(defaultValue)})\n }\n value={isDefault || value === undefined ? '' : String(value)}\n onChange={handleSelect}\n />\n );\n }\n default:\n return (\n <TextField\n id={id}\n aria-label={label}\n aria-describedby={descriptionId}\n disabled={disabled}\n error={error}\n max={definition.max}\n min={definition.min}\n placeholder={\n defaultValue === undefined || defaultValue === ''\n ? t('admin.flowVariables.enter_value')\n : display(defaultValue)\n }\n type={INPUT_TYPES[definition.type] ?? 'text'}\n value={value === undefined ? '' : String(value)}\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n const raw: string = event.target.value;\n\n onChange(\n definition.type === 'NUMBER_INPUT' && raw !== '' && !Number.isNaN(Number(raw)) ? Number(raw) : raw,\n );\n }}\n />\n );\n }\n };\n\n return (\n <section\n className={cx(\n withVendorCSSClassPrefix(bem('flow-variables', 'field')),\n withVendorCSSClassPrefix(bem('flow-variables', 'field', definition.type.toLowerCase())),\n styles['card'],\n !editable && styles['cardLocked'],\n className,\n )}\n data-variable={definition.identifier}\n data-editable={editable}\n >\n <div className={styles['header']}>\n <div className={styles['headerText']}>\n <label htmlFor={id} className={styles['label']}>\n {label}\n </label>\n {definition.description && (\n <p id={descriptionId} className={styles['description']}>\n {definition.description}\n </p>\n )}\n </div>\n {editable && !isDefault && (\n <span className={styles['chipCustomized']} data-testid=\"flow-variable-status\">\n {t('admin.flowVariables.status.customized')}\n </span>\n )}\n {action}\n </div>\n {editable ? (\n <>\n {renderControl()}\n {hint && <p className={styles['hint']}>{hint}</p>}\n {!isDefault && defaultValue !== undefined && (\n <p className={styles['hint']}>{t('admin.flowVariables.default_hint', {default: display(defaultValue)})}</p>\n )}\n </>\n ) : (\n <div className={styles['lockedLine']}>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.7\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect x=\"5\" y=\"11\" width=\"14\" height=\"9\" rx=\"2\" />\n <path d=\"M8 11V8a4 4 0 018 0v3\" />\n </svg>\n <span>\n {t('admin.flowVariables.locked', {owner: ownerName ?? t('admin.flowVariables.owner_fallback')})}\n {' · '}\n {display(value)}\n </span>\n {definition.type === 'BOOLEAN_INPUT' && renderControl()}\n </div>\n )}\n </section>\n );\n};\n\nexport default FlowVariableField;\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { Theme } from '@thunderid/browser';
2
+ /**
3
+ * Creates the styles of the flow variables form.
4
+ *
5
+ * @param theme - The theme object containing design tokens.
6
+ * @param colorScheme - The current color scheme, used for memoization.
7
+ * @returns The CSS class names for each part.
8
+ */
9
+ declare const useStyles: (theme: Theme, colorScheme: string) => Record<string, string>;
10
+ export default useStyles;
11
+ //# sourceMappingURL=FlowVariables.styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowVariables.styles.d.ts","sourceRoot":"","sources":["../../../../src/components/management/FlowVariables/FlowVariables.styles.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,EAAC,MAAM,oBAAoB,CAAC;AAIzC;;;;;;GAMG;AACH,QAAA,MAAM,SAAS,GAAI,OAAO,KAAK,EAAE,aAAa,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CA0GlD,CAAC;AAE3B,eAAe,SAAS,CAAC"}
@@ -0,0 +1,121 @@
1
+ import { css } from "../../../styles/emotion.js";
2
+ import { useMemo } from "react";
3
+
4
+ //#region src/components/management/FlowVariables/FlowVariables.styles.ts
5
+ /**
6
+ * Creates the styles of the flow variables form.
7
+ *
8
+ * @param theme - The theme object containing design tokens.
9
+ * @param colorScheme - The current color scheme, used for memoization.
10
+ * @returns The CSS class names for each part.
11
+ */
12
+ const useStyles = (theme, colorScheme) => useMemo(() => {
13
+ const unit = theme.vars.spacing.unit;
14
+ const chip = css`
15
+ display: inline-flex;
16
+ align-items: center;
17
+ flex-shrink: 0;
18
+ padding: 2px calc(${unit} * 1.25);
19
+ border-radius: 999px;
20
+ border: 1px solid ${theme.vars.colors.border};
21
+ font-size: ${theme.vars.typography.fontSizes.xs};
22
+ font-weight: ${theme.vars.typography.fontWeights.medium};
23
+ color: ${theme.vars.colors.text.secondary};
24
+ white-space: nowrap;
25
+ `;
26
+ return {
27
+ actions: css`
28
+ display: flex;
29
+ align-items: center;
30
+ gap: ${unit};
31
+ `,
32
+ actionsSpacer: css`
33
+ flex-grow: 1;
34
+ `,
35
+ card: css`
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: calc(${unit} * 2);
39
+ padding: calc(${unit} * 2.5) calc(${unit} * 3);
40
+ background: ${theme.vars.colors.background.surface};
41
+ border: 1px solid ${theme.vars.colors.border};
42
+ border-radius: ${theme.vars.borderRadius.large};
43
+ `,
44
+ cardLocked: css`
45
+ background: ${theme.vars.colors.background.disabled};
46
+ `,
47
+ chip,
48
+ chipCustomized: css`
49
+ ${chip}
50
+ border-color: ${theme.vars.colors.success.main};
51
+ color: ${theme.vars.colors.success.main};
52
+ `,
53
+ description: css`
54
+ margin: calc(${unit} / 4) 0 0;
55
+ color: ${theme.vars.colors.text.secondary};
56
+ font-size: ${theme.vars.typography.fontSizes.sm};
57
+ `,
58
+ empty: css`
59
+ margin: 0;
60
+ color: ${theme.vars.colors.text.secondary};
61
+ `,
62
+ form: css`
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: calc(${unit} * 2.5);
66
+ max-width: 880px;
67
+ `,
68
+ header: css`
69
+ display: flex;
70
+ align-items: flex-start;
71
+ gap: calc(${unit} * 1.5);
72
+ `,
73
+ headerText: css`
74
+ flex-grow: 1;
75
+ min-width: 0;
76
+ `,
77
+ hint: css`
78
+ display: flex;
79
+ flex-wrap: wrap;
80
+ align-items: center;
81
+ gap: calc(${unit} * 1.25);
82
+ margin: 0;
83
+ color: ${theme.vars.colors.text.secondary};
84
+ font-size: ${theme.vars.typography.fontSizes.xs};
85
+ `,
86
+ label: css`
87
+ font-size: ${theme.vars.typography.fontSizes.md};
88
+ font-weight: ${theme.vars.typography.fontWeights.medium};
89
+ color: ${theme.vars.colors.text.primary};
90
+ `,
91
+ link: css`
92
+ padding: 0;
93
+ border: 0;
94
+ background: none;
95
+ font: inherit;
96
+ font-weight: ${theme.vars.typography.fontWeights.medium};
97
+ color: ${theme.vars.colors.primary.main};
98
+ cursor: pointer;
99
+ &:hover {
100
+ text-decoration: underline;
101
+ }
102
+ `,
103
+ lockedLine: css`
104
+ display: flex;
105
+ align-items: center;
106
+ gap: calc(${unit} * 1.25);
107
+ color: ${theme.vars.colors.text.secondary};
108
+ font-size: ${theme.vars.typography.fontSizes.sm};
109
+ `,
110
+ scope: css`
111
+ display: flex;
112
+ align-items: center;
113
+ gap: calc(${unit} * 1.5);
114
+ `
115
+ };
116
+ }, [theme, colorScheme]);
117
+ var FlowVariables_styles_default = useStyles;
118
+
119
+ //#endregion
120
+ export { FlowVariables_styles_default as default };
121
+ //# sourceMappingURL=FlowVariables.styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowVariables.styles.js","names":["unit: string","chip: string"],"sources":["../../../../src/components/management/FlowVariables/FlowVariables.styles.ts"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {Theme} from '@thunderid/browser';\nimport {useMemo} from 'react';\nimport {css} from '../../../styles/emotion';\n\n/**\n * Creates the styles of the flow variables form.\n *\n * @param theme - The theme object containing design tokens.\n * @param colorScheme - The current color scheme, used for memoization.\n * @returns The CSS class names for each part.\n */\nconst useStyles = (theme: Theme, colorScheme: string): Record<string, string> =>\n useMemo(() => {\n const unit: string = theme.vars.spacing.unit;\n const chip: string = css`\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n padding: 2px calc(${unit} * 1.25);\n border-radius: 999px;\n border: 1px solid ${theme.vars.colors.border};\n font-size: ${theme.vars.typography.fontSizes.xs};\n font-weight: ${theme.vars.typography.fontWeights.medium};\n color: ${theme.vars.colors.text.secondary};\n white-space: nowrap;\n `;\n\n return {\n actions: css`\n display: flex;\n align-items: center;\n gap: ${unit};\n `,\n actionsSpacer: css`\n flex-grow: 1;\n `,\n card: css`\n display: flex;\n flex-direction: column;\n gap: calc(${unit} * 2);\n padding: calc(${unit} * 2.5) calc(${unit} * 3);\n background: ${theme.vars.colors.background.surface};\n border: 1px solid ${theme.vars.colors.border};\n border-radius: ${theme.vars.borderRadius.large};\n `,\n cardLocked: css`\n background: ${theme.vars.colors.background.disabled};\n `,\n chip,\n chipCustomized: css`\n ${chip}\n border-color: ${theme.vars.colors.success.main};\n color: ${theme.vars.colors.success.main};\n `,\n description: css`\n margin: calc(${unit} / 4) 0 0;\n color: ${theme.vars.colors.text.secondary};\n font-size: ${theme.vars.typography.fontSizes.sm};\n `,\n empty: css`\n margin: 0;\n color: ${theme.vars.colors.text.secondary};\n `,\n form: css`\n display: flex;\n flex-direction: column;\n gap: calc(${unit} * 2.5);\n max-width: 880px;\n `,\n header: css`\n display: flex;\n align-items: flex-start;\n gap: calc(${unit} * 1.5);\n `,\n headerText: css`\n flex-grow: 1;\n min-width: 0;\n `,\n hint: css`\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: calc(${unit} * 1.25);\n margin: 0;\n color: ${theme.vars.colors.text.secondary};\n font-size: ${theme.vars.typography.fontSizes.xs};\n `,\n label: css`\n font-size: ${theme.vars.typography.fontSizes.md};\n font-weight: ${theme.vars.typography.fontWeights.medium};\n color: ${theme.vars.colors.text.primary};\n `,\n link: css`\n padding: 0;\n border: 0;\n background: none;\n font: inherit;\n font-weight: ${theme.vars.typography.fontWeights.medium};\n color: ${theme.vars.colors.primary.main};\n cursor: pointer;\n &:hover {\n text-decoration: underline;\n }\n `,\n lockedLine: css`\n display: flex;\n align-items: center;\n gap: calc(${unit} * 1.25);\n color: ${theme.vars.colors.text.secondary};\n font-size: ${theme.vars.typography.fontSizes.sm};\n `,\n scope: css`\n display: flex;\n align-items: center;\n gap: calc(${unit} * 1.5);\n `,\n };\n }, [theme, colorScheme]);\n\nexport default useStyles;\n"],"mappings":";;;;;;;;;;;AAcA,MAAM,aAAa,OAAc,gBAC/B,cAAc;CACZ,MAAMA,OAAe,MAAM,KAAK,QAAQ;CACxC,MAAMC,OAAe,GAAG;;;;0BAIF,KAAK;;0BAEL,MAAM,KAAK,OAAO,OAAO;mBAChC,MAAM,KAAK,WAAW,UAAU,GAAG;qBACjC,MAAM,KAAK,WAAW,YAAY,OAAO;eAC/C,MAAM,KAAK,OAAO,KAAK,UAAU;;;AAI5C,QAAO;EACL,SAAS,GAAG;;;eAGH,KAAK;;EAEd,eAAe,GAAG;;;EAGlB,MAAM,GAAG;;;oBAGK,KAAK;wBACD,KAAK,eAAe,KAAK;sBAC3B,MAAM,KAAK,OAAO,WAAW,QAAQ;4BAC/B,MAAM,KAAK,OAAO,OAAO;yBAC5B,MAAM,KAAK,aAAa,MAAM;;EAEjD,YAAY,GAAG;sBACC,MAAM,KAAK,OAAO,WAAW,SAAS;;EAEtD;EACA,gBAAgB,GAAG;UACf,KAAK;wBACS,MAAM,KAAK,OAAO,QAAQ,KAAK;iBACtC,MAAM,KAAK,OAAO,QAAQ,KAAK;;EAE1C,aAAa,GAAG;uBACC,KAAK;iBACX,MAAM,KAAK,OAAO,KAAK,UAAU;qBAC7B,MAAM,KAAK,WAAW,UAAU,GAAG;;EAElD,OAAO,GAAG;;iBAEC,MAAM,KAAK,OAAO,KAAK,UAAU;;EAE5C,MAAM,GAAG;;;oBAGK,KAAK;;;EAGnB,QAAQ,GAAG;;;oBAGG,KAAK;;EAEnB,YAAY,GAAG;;;;EAIf,MAAM,GAAG;;;;oBAIK,KAAK;;iBAER,MAAM,KAAK,OAAO,KAAK,UAAU;qBAC7B,MAAM,KAAK,WAAW,UAAU,GAAG;;EAElD,OAAO,GAAG;qBACK,MAAM,KAAK,WAAW,UAAU,GAAG;uBACjC,MAAM,KAAK,WAAW,YAAY,OAAO;iBAC/C,MAAM,KAAK,OAAO,KAAK,QAAQ;;EAE1C,MAAM,GAAG;;;;;uBAKQ,MAAM,KAAK,WAAW,YAAY,OAAO;iBAC/C,MAAM,KAAK,OAAO,QAAQ,KAAK;;;;;;EAM1C,YAAY,GAAG;;;oBAGD,KAAK;iBACR,MAAM,KAAK,OAAO,KAAK,UAAU;qBAC7B,MAAM,KAAK,WAAW,UAAU,GAAG;;EAElD,OAAO,GAAG;;;oBAGI,KAAK;;EAEpB;GACA,CAAC,OAAO,YAAY,CAAC;AAE1B,mCAAe"}