@ethlete/components 1.0.0-next.77 → 1.0.0-next.78
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/CHANGELOG.md +6 -0
- package/design/config.json +19 -0
- package/design/form-field.ts +40 -1
- package/design/icon-set.ts +19 -0
- package/design/icon.ts +9 -0
- package/design/sdk/components/button/button.ts +39 -0
- package/design/sdk/components/form-field/form-field.ts +100 -0
- package/design/sdk/components/select/select.css +5 -0
- package/design/sdk/components/select/select.ts +16 -0
- package/design/sdk/components/select/shared/select-part.ts +60 -0
- package/design/sdk/fixtures.ts +0 -0
- package/design/sdk/foundations/colors/colors.css +528 -0
- package/design/sdk/foundations/colors/colors.ts +188 -0
- package/design/sdk/foundations/colors/overrides.json +19 -0
- package/design/sdk/foundations/colors/shared/contrast.ts +120 -0
- package/design/select.ts +113 -28
- package/design/tree.ts +106 -0
- package/fesm2022/ethlete-components.mjs +15 -15
- package/fesm2022/ethlete-components.mjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/forms/form-field/form-field-text-shell-styles.component.css +24 -16
- package/src/lib/forms/select/select-option-styles.component.css +3 -2
- package/src/lib/icon/headless/align-icons.ts +30 -0
- package/src/lib/icon/headless/arrow-out-up-right-icon.ts +17 -0
- package/src/lib/icon/headless/arrow-right-icon.ts +23 -0
- package/src/lib/icon/headless/arrow-up-icon.ts +30 -0
- package/src/lib/icon/headless/arrows-left-right-icon.ts +31 -0
- package/src/lib/icon/headless/bold-icon.ts +11 -0
- package/src/lib/icon/headless/calendar-icon.ts +21 -0
- package/src/lib/icon/headless/check-icon.ts +14 -0
- package/src/lib/icon/headless/chevron-icon.ts +14 -0
- package/src/lib/icon/headless/circle-check-icon.ts +14 -0
- package/src/lib/icon/headless/circle-info-icon.ts +14 -0
- package/src/lib/icon/headless/clipboard-check-icon.ts +28 -0
- package/src/lib/icon/headless/clock-icon.ts +21 -0
- package/src/lib/icon/headless/code-block-icon.ts +15 -0
- package/src/lib/icon/headless/code-icon.ts +14 -0
- package/src/lib/icon/headless/ellipsis-icon.ts +13 -0
- package/src/lib/icon/headless/ellipsis-vertical-icon.ts +13 -0
- package/src/lib/icon/headless/eye-icons.ts +27 -0
- package/src/lib/icon/headless/eyedropper-icon.ts +22 -0
- package/src/lib/icon/headless/file-icon.ts +16 -0
- package/src/lib/icon/headless/filter-icon.ts +11 -0
- package/src/lib/icon/headless/floppy-disk-icon.ts +27 -0
- package/src/lib/icon/headless/focus-frame-icon.ts +16 -0
- package/src/lib/icon/headless/grid-2x2-icon.ts +17 -0
- package/src/lib/icon/headless/heading-1-icon.ts +11 -0
- package/src/lib/icon/headless/heading-2-icon.ts +11 -0
- package/src/lib/icon/headless/heading-3-icon.ts +11 -0
- package/src/lib/icon/headless/icon-definition.ts +14 -0
- package/src/lib/icon/headless/image-icon.ts +14 -0
- package/src/lib/icon/headless/italic-icon.ts +19 -0
- package/src/lib/icon/headless/link-icon.ts +17 -0
- package/src/lib/icon/headless/list-bulleted-icon.ts +14 -0
- package/src/lib/icon/headless/list-numbered-icon.ts +14 -0
- package/src/lib/icon/headless/location-icon.ts +21 -0
- package/src/lib/icon/headless/lock-icon.ts +14 -0
- package/src/lib/icon/headless/minus-icon.ts +14 -0
- package/src/lib/icon/headless/paragraph-icon.ts +11 -0
- package/src/lib/icon/headless/pause-icon.ts +11 -0
- package/src/lib/icon/headless/pencil-icon.ts +21 -0
- package/src/lib/icon/headless/play-icon.ts +10 -0
- package/src/lib/icon/headless/plus-icon.ts +21 -0
- package/src/lib/icon/headless/quote-icon.ts +15 -0
- package/src/lib/icon/headless/rotate-right-icon.ts +16 -0
- package/src/lib/icon/headless/star-icon.ts +14 -0
- package/src/lib/icon/headless/strikethrough-icon.ts +18 -0
- package/src/lib/icon/headless/table-icon.ts +15 -0
- package/src/lib/icon/headless/thumbtack-icon.ts +18 -0
- package/src/lib/icon/headless/times-icon.ts +14 -0
- package/src/lib/icon/headless/trash-icon.ts +24 -0
- package/src/lib/icon/headless/triangle-exclamation-icon.ts +14 -0
- package/src/lib/icon/headless/trophy-icon.ts +24 -0
- package/src/lib/icon/headless/underline-icon.ts +12 -0
- package/src/lib/icon/headless/undo-redo-icons.ts +24 -0
- package/src/lib/icon/headless/upload-icon.ts +16 -0
- package/src/lib/tree/tree.component.css +2 -2
- package/types/ethlete-components.d.ts +52 -52
package/CHANGELOG.md
CHANGED
package/design/form-field.ts
CHANGED
|
@@ -5,6 +5,8 @@ import suffixOverlap from '../src/lib/forms/form-field/form-field-suffix-overlap
|
|
|
5
5
|
import label from '../src/lib/forms/form-field/headless/label.directive.css?inline';
|
|
6
6
|
import hint from '../src/lib/forms/form-field/hint.component.css?inline';
|
|
7
7
|
import inputBase from '../src/lib/forms/input/input.component.css?inline';
|
|
8
|
+
import textareaBase from '../src/lib/forms/textarea/textarea.component.css?inline';
|
|
9
|
+
import textareaAutosize from '../src/lib/forms/textarea/textarea-autosize-styles.component.css?inline';
|
|
8
10
|
import iconStyles from '../src/lib/icon/headless/icon-styles.component.css?inline';
|
|
9
11
|
|
|
10
12
|
/** The field state a control draws itself from. */
|
|
@@ -75,7 +77,16 @@ export type InputMockOptions = {
|
|
|
75
77
|
textAlign?: 'start' | 'center' | 'end';
|
|
76
78
|
};
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
export type TextareaMockOptions = {
|
|
81
|
+
value?: string;
|
|
82
|
+
placeholder?: string;
|
|
83
|
+
rows?: number;
|
|
84
|
+
/** Grows with its content, from `minRows` (default `rows`). On by default, like the real textarea. */
|
|
85
|
+
autosize?: boolean;
|
|
86
|
+
minRows?: number;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/** The stylesheets `formField()`, `input()` and `textarea()` draw with: the real `et-form-field` CSS. */
|
|
79
90
|
export const formFieldStyles = /* @__PURE__ */ [
|
|
80
91
|
interactiveStyles,
|
|
81
92
|
iconStyles,
|
|
@@ -85,6 +96,8 @@ export const formFieldStyles = /* @__PURE__ */ [
|
|
|
85
96
|
label,
|
|
86
97
|
hint,
|
|
87
98
|
inputBase,
|
|
99
|
+
textareaBase,
|
|
100
|
+
textareaAutosize,
|
|
88
101
|
`.et-design-panel-anchor { position: relative; }
|
|
89
102
|
.et-design-panel { position: absolute; inset-inline: 0; inset-block-start: calc(100% + 0.3rem); z-index: 1; }`,
|
|
90
103
|
].join('\n');
|
|
@@ -114,6 +127,32 @@ export const input = (options: InputMockOptions = {}): FormFieldControlMock => (
|
|
|
114
127
|
},
|
|
115
128
|
});
|
|
116
129
|
|
|
130
|
+
/** Draws `<et-textarea>` as a control for `formField()`. */
|
|
131
|
+
export const textarea = (options: TextareaMockOptions = {}): FormFieldControlMock => ({
|
|
132
|
+
controlType: 'textarea',
|
|
133
|
+
hasValue: !!options.value,
|
|
134
|
+
html: (state) => {
|
|
135
|
+
const rows = options.rows ?? 3;
|
|
136
|
+
const autosize = options.autosize ?? true;
|
|
137
|
+
const attributes = attributesOf([
|
|
138
|
+
'class="et-textarea-native"',
|
|
139
|
+
`rows="${rows}"`,
|
|
140
|
+
state.disabled && 'disabled',
|
|
141
|
+
state.readonly && 'readonly',
|
|
142
|
+
state.required && 'required',
|
|
143
|
+
options.placeholder && `placeholder="${options.placeholder}"`,
|
|
144
|
+
state.invalid && 'aria-invalid="true"',
|
|
145
|
+
state.describedBy && `aria-describedby="${state.describedBy}"`,
|
|
146
|
+
state.labelId && `aria-labelledby="${state.labelId}"`,
|
|
147
|
+
`data-resize="${autosize ? 'none' : 'vertical'}"`,
|
|
148
|
+
autosize && 'data-et-textarea-autosize=""',
|
|
149
|
+
autosize && `style="--et-textarea-min-rows: ${options.minRows ?? rows}"`,
|
|
150
|
+
]);
|
|
151
|
+
|
|
152
|
+
return `<et-textarea class="et-color-interactive et-textarea"><textarea ${attributes}>${options.value ?? ''}</textarea></et-textarea>`;
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
|
|
117
156
|
/** Draws `<et-form-field>` with a control, its label, affixes and messages, as the component renders them. */
|
|
118
157
|
export const formField = (options: FormFieldMockOptions) => {
|
|
119
158
|
const control: FormFieldControlMock =
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
import { IconDefinition } from '../src/lib/icon/headless/icon-definition';
|
|
3
|
+
|
|
4
|
+
const modules = /* @__PURE__ */ import.meta.glob<Record<string, unknown>>(
|
|
5
|
+
['../src/lib/icon/headless/*-icon.ts', '../src/lib/icon/headless/*-icons.ts'],
|
|
6
|
+
{ eager: true },
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
const isIconDefinition = (value: unknown): value is IconDefinition =>
|
|
10
|
+
!!value &&
|
|
11
|
+
typeof value === 'object' &&
|
|
12
|
+
typeof (value as IconDefinition).name === 'string' &&
|
|
13
|
+
typeof (value as IconDefinition).data === 'string';
|
|
14
|
+
|
|
15
|
+
/** Every icon the SDK ships, read from the icon source files and sorted by name. */
|
|
16
|
+
export const SDK_ICONS: readonly IconDefinition[] = /* @__PURE__ */ Object.values(modules)
|
|
17
|
+
.flatMap((module) => Object.values(module))
|
|
18
|
+
.filter(isIconDefinition)
|
|
19
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
package/design/icon.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IconDefinition } from '../src/lib/icon/headless/icon-definition';
|
|
2
|
+
|
|
3
|
+
/** Draws `<i etIcon>` as the icon directive renders it: the icon's classes around its trimmed SVG. */
|
|
4
|
+
export const iconMarkup = (icon: IconDefinition, className?: string) => {
|
|
5
|
+
const base = `et-icon et-icon--${icon.name}`;
|
|
6
|
+
const classes = [className, base, icon.variant ? `${base}--${icon.variant}` : undefined].filter(Boolean).join(' ');
|
|
7
|
+
|
|
8
|
+
return `<i etIcon="${icon.name}" aria-hidden="true" class="${classes}">${icon.data.trim()}</i>`;
|
|
9
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { button, buttonStyles, ButtonMockOptions } from '@ethlete/components/design/button';
|
|
2
|
+
import { definePart, drawing, forceInteraction, interactionRows } from '@design-system';
|
|
3
|
+
|
|
4
|
+
type ButtonInteraction = 'hover' | 'active' | 'focus-visible';
|
|
5
|
+
|
|
6
|
+
type Props = ButtonMockOptions & { interaction?: ButtonInteraction };
|
|
7
|
+
|
|
8
|
+
const control = ({ interaction, ...options }: Props) => {
|
|
9
|
+
const markup = button(options).replace(/^<(button|a) /, '<$1 data-et-control="button" data-can-animate ');
|
|
10
|
+
|
|
11
|
+
return interaction ? forceInteraction(markup, interaction) : markup;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const { states, grid } = interactionRows<
|
|
15
|
+
Props,
|
|
16
|
+
'filled' | 'outline' | 'tonal' | 'transparent' | 'pressed' | 'danger' | 'small' | 'disabled',
|
|
17
|
+
ButtonInteraction
|
|
18
|
+
>(
|
|
19
|
+
{
|
|
20
|
+
filled: { label: 'Save', variant: 'filled' },
|
|
21
|
+
outline: { label: 'Cancel', variant: 'outline' },
|
|
22
|
+
tonal: { label: 'Filter', variant: 'tonal' },
|
|
23
|
+
transparent: { label: 'More', variant: 'transparent' },
|
|
24
|
+
pressed: { label: 'Grid', variant: 'outline', pressed: true },
|
|
25
|
+
danger: { label: 'Delete', variant: 'filled', color: 'danger' },
|
|
26
|
+
small: { label: 'Save', variant: 'filled', size: 'sm' },
|
|
27
|
+
disabled: { label: 'Save', variant: 'filled', disabled: true },
|
|
28
|
+
},
|
|
29
|
+
{ interactions: ['hover', 'active', 'focus-visible'], force: (props, interaction) => ({ ...props, interaction }) },
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export default definePart({
|
|
33
|
+
note: 'The SDK button, drawn by its mock from @ethlete/components/design.',
|
|
34
|
+
madeBy: ['claude-opus-5-5'],
|
|
35
|
+
states,
|
|
36
|
+
grid,
|
|
37
|
+
controls: { button: { kind: 'button', input: ['pointer', 'keyboard'], disabled: true } },
|
|
38
|
+
render: (props: Props) => drawing({ body: control(props), styles: buttonStyles }),
|
|
39
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formField,
|
|
3
|
+
formFieldStyles,
|
|
4
|
+
input,
|
|
5
|
+
textarea,
|
|
6
|
+
type FormFieldMockOptions,
|
|
7
|
+
} from '@ethlete/components/design/form-field';
|
|
8
|
+
import { definePart, drawing, interactionRows } from '@design-system';
|
|
9
|
+
|
|
10
|
+
type FieldInteraction = 'hover' | 'focus-visible';
|
|
11
|
+
|
|
12
|
+
type FieldControl = 'input' | 'textarea';
|
|
13
|
+
|
|
14
|
+
type Axes = Pick<FormFieldMockOptions, 'appearance' | 'fill' | 'labelMode' | 'size'>;
|
|
15
|
+
|
|
16
|
+
type Props = Axes & {
|
|
17
|
+
control?: FieldControl;
|
|
18
|
+
value?: string;
|
|
19
|
+
hint?: string;
|
|
20
|
+
error?: string;
|
|
21
|
+
focused?: boolean;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
interaction?: FieldInteraction;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const multiLine = 'Ada Lovelace\nAnalytical Engine notes';
|
|
27
|
+
|
|
28
|
+
const axisRow: Props = { value: 'Ada Lovelace' };
|
|
29
|
+
|
|
30
|
+
const AXES = {
|
|
31
|
+
appearance: ['box', 'underline'],
|
|
32
|
+
fill: ['transparent', 'filled'],
|
|
33
|
+
labelMode: ['static', 'inline', 'floating-inside', 'floating-outside'],
|
|
34
|
+
size: ['sm', 'md', 'lg'],
|
|
35
|
+
} as const satisfies { [K in keyof Axes]-?: readonly NonNullable<Axes[K]>[] };
|
|
36
|
+
|
|
37
|
+
const axisRows = Object.fromEntries(
|
|
38
|
+
Object.entries(AXES).flatMap(([axis, values]) =>
|
|
39
|
+
values.map((value) => [`${axis}-${value}`, { ...axisRow, [axis]: value }]),
|
|
40
|
+
),
|
|
41
|
+
) as Record<string, Props>;
|
|
42
|
+
|
|
43
|
+
const { states, grid } = interactionRows(
|
|
44
|
+
{
|
|
45
|
+
empty: { hint: 'Shown on your profile' },
|
|
46
|
+
filled: { value: 'Ada Lovelace' },
|
|
47
|
+
error: { error: 'This field is required' },
|
|
48
|
+
'textarea-empty': { control: 'textarea', hint: 'Shown on your profile' },
|
|
49
|
+
'textarea-filled': { control: 'textarea', value: multiLine },
|
|
50
|
+
'textarea-error': { control: 'textarea', error: 'This field is required' },
|
|
51
|
+
...axisRows,
|
|
52
|
+
} satisfies Record<string, Props>,
|
|
53
|
+
{
|
|
54
|
+
interactions: ['hover', 'focus-visible'],
|
|
55
|
+
force: (props: Props, interaction: FieldInteraction): Props => ({ ...props, interaction }),
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const markControl = (markup: string, control: FieldControl, interaction: FieldInteraction | undefined) => {
|
|
60
|
+
const frame = ['data-et-control-part', interaction && `data-et-force="${interaction}"`].filter(Boolean);
|
|
61
|
+
const native = control === 'input' ? '<input class="et-input-native"' : '<textarea class="et-textarea-native"';
|
|
62
|
+
|
|
63
|
+
return markup
|
|
64
|
+
.replace('<et-form-field ', `<et-form-field data-et-control="${control}" `)
|
|
65
|
+
.replace('<div class="et-form-field-control-frame"', `<div class="et-form-field-control-frame" ${frame.join(' ')}`)
|
|
66
|
+
.replace(native, native.replace(' class=', ' data-et-control-part class='));
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export default definePart<Props>({
|
|
70
|
+
note: 'The SDK form field with a text input and a textarea, drawn by its mocks from @ethlete/components/design.',
|
|
71
|
+
madeBy: ['claude-opus-5-5'],
|
|
72
|
+
states: {
|
|
73
|
+
...states,
|
|
74
|
+
focused: { value: 'Ada', focused: true },
|
|
75
|
+
disabled: { value: 'Ada Lovelace', disabled: true },
|
|
76
|
+
'textarea-focused': { control: 'textarea', value: 'Ada', focused: true },
|
|
77
|
+
'textarea-disabled': { control: 'textarea', value: multiLine, disabled: true },
|
|
78
|
+
},
|
|
79
|
+
grid,
|
|
80
|
+
widths: [320],
|
|
81
|
+
controls: {
|
|
82
|
+
input: { kind: 'field', input: ['pointer', 'keyboard'], disabled: true },
|
|
83
|
+
textarea: { kind: 'field', input: ['pointer', 'keyboard'], disabled: true },
|
|
84
|
+
},
|
|
85
|
+
render: ({ control = 'input', value, interaction, ...field }) =>
|
|
86
|
+
drawing({
|
|
87
|
+
body: markControl(
|
|
88
|
+
formField({
|
|
89
|
+
id: 'name',
|
|
90
|
+
label: 'Name',
|
|
91
|
+
errorColor: 'danger-on-light',
|
|
92
|
+
control: control === 'input' ? input({ value }) : textarea({ value }),
|
|
93
|
+
...field,
|
|
94
|
+
}),
|
|
95
|
+
control,
|
|
96
|
+
interaction,
|
|
97
|
+
),
|
|
98
|
+
styles: formFieldStyles,
|
|
99
|
+
}),
|
|
100
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { selectStyles } from '@ethlete/components/design/select';
|
|
2
|
+
import { definePart, drawing } from '@design-system';
|
|
3
|
+
import styles from './select.css?inline';
|
|
4
|
+
import { grid, moreStates, selectBody, SelectProps, states } from './shared/select-part';
|
|
5
|
+
|
|
6
|
+
export default definePart<SelectProps>({
|
|
7
|
+
note: 'The SDK select inside a form field, drawn by its mock from @ethlete/components/design.',
|
|
8
|
+
madeBy: ['claude-opus-5-5', 'claude-sonnet-5-5'],
|
|
9
|
+
states: { ...states, ...moreStates },
|
|
10
|
+
grid,
|
|
11
|
+
widths: [320],
|
|
12
|
+
controls: {
|
|
13
|
+
select: { kind: 'select', input: ['pointer', 'keyboard'], disabled: true, surfaces: { open: 'open' } },
|
|
14
|
+
},
|
|
15
|
+
render: (props) => drawing({ body: selectBody(props), styles: [selectStyles, styles].join('\n') }),
|
|
16
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { formField } from '@ethlete/components/design/form-field';
|
|
2
|
+
import { select } from '@ethlete/components/design/select';
|
|
3
|
+
import { interactionRows } from '@design-system';
|
|
4
|
+
|
|
5
|
+
type FieldInteraction = 'hover' | 'active' | 'focus-visible';
|
|
6
|
+
|
|
7
|
+
export type SelectProps = {
|
|
8
|
+
value?: string;
|
|
9
|
+
open?: boolean;
|
|
10
|
+
active?: string;
|
|
11
|
+
pointerActive?: boolean;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
interaction?: FieldInteraction;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const OPTIONS = [
|
|
17
|
+
{ value: 'drafts', label: 'Drafts' },
|
|
18
|
+
{ value: 'review', label: 'In review' },
|
|
19
|
+
{ value: 'merged', label: 'Merged' },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const markControl = (markup: string, { interaction, pointerActive }: SelectProps) => {
|
|
23
|
+
const frame = ['data-et-control-part', interaction && `data-et-force="${interaction}"`].filter(Boolean);
|
|
24
|
+
const marked = markup
|
|
25
|
+
.replace('<et-form-field ', '<et-form-field data-et-control="select" ')
|
|
26
|
+
.replace('<div class="et-form-field-control-frame"', `<div class="et-form-field-control-frame" ${frame.join(' ')}`)
|
|
27
|
+
.replace('class="et-select-trigger"', 'data-et-control-part class="et-select-trigger"')
|
|
28
|
+
.replace('<et-select-panel ', '<et-select-panel data-et-surface="select.open" ');
|
|
29
|
+
|
|
30
|
+
return pointerActive
|
|
31
|
+
? marked.replace('data-active-source="keyboard"', 'data-active-source="pointer" data-et-force="hover"')
|
|
32
|
+
: marked;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const { states, grid } = interactionRows<SelectProps, 'placeholder' | 'selected', FieldInteraction>(
|
|
36
|
+
{
|
|
37
|
+
placeholder: {},
|
|
38
|
+
selected: { value: 'review' },
|
|
39
|
+
},
|
|
40
|
+
{ interactions: ['hover', 'active', 'focus-visible'], force: (props, interaction) => ({ ...props, interaction }) },
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export const moreStates = {
|
|
44
|
+
disabled: { value: 'review', disabled: true },
|
|
45
|
+
open: { value: 'review', open: true, active: 'merged' },
|
|
46
|
+
'open-option-hover': { value: 'review', open: true, active: 'drafts', pointerActive: true },
|
|
47
|
+
} satisfies Record<string, SelectProps>;
|
|
48
|
+
|
|
49
|
+
export const selectBody = (props: SelectProps) =>
|
|
50
|
+
markControl(
|
|
51
|
+
formField({
|
|
52
|
+
id: 'status',
|
|
53
|
+
label: 'Status',
|
|
54
|
+
errorColor: 'danger',
|
|
55
|
+
open: props.open,
|
|
56
|
+
disabled: props.disabled,
|
|
57
|
+
control: select({ options: OPTIONS, value: props.value, active: props.active, placeholder: 'Pick a status' }),
|
|
58
|
+
}),
|
|
59
|
+
props,
|
|
60
|
+
);
|
|
File without changes
|