Skip to content

Commit a6cee20

Browse files
committed
chore: update preview
1 parent 2bf337a commit a6cee20

File tree

16 files changed

+163
-191
lines changed

16 files changed

+163
-191
lines changed

packages/pluggableWidgets/selection-controls-web/src/SelectionControls.editorConfig.ts

Lines changed: 45 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ import {
44
StructurePreviewProps,
55
structurePreviewPalette,
66
dropzone,
7-
container
7+
container,
8+
rowLayout,
9+
text,
10+
svgImage
811
} from "@mendix/widget-plugin-platform/preview/structure-preview-api";
912
import { SelectionControlsPreviewProps } from "../typings/SelectionControlsProps";
13+
import { getCustomCaption } from "./helpers/utils";
14+
import IconRadioButtonSVG from "./assets/radiobutton.svg";
15+
import IconCheckboxSVG from "./assets/checkbox.svg";
1016

1117
const DATABASE_SOURCE_CONFIG: Array<keyof SelectionControlsPreviewProps> = [
1218
"optionsSourceDatabaseCaptionAttribute",
@@ -127,43 +133,40 @@ export function getProperties(
127133
return defaultProperties;
128134
}
129135

130-
function getIconPreview(_isDarkMode: boolean): ContainerProps {
131-
return {
132-
type: "Container",
133-
children: [
134-
container({ padding: 1 })(),
135-
{
136-
type: "Text",
137-
content: "☑",
138-
fontSize: 16
139-
}
140-
]
141-
};
136+
function getIconPreview(isMultiSelect: boolean): ContainerProps {
137+
return container({ grow: 0 })(
138+
container({ padding: 3 })(),
139+
svgImage({ width: 16, height: 16, grow: 0 })(
140+
decodeURIComponent(
141+
(isMultiSelect ? IconCheckboxSVG : IconRadioButtonSVG).replace("data:image/svg+xml,", "")
142+
)
143+
)
144+
);
142145
}
143146

144-
export function getPreview(_values: SelectionControlsPreviewProps, isDarkMode: boolean): StructurePreviewProps {
147+
export function getPreview(values: SelectionControlsPreviewProps, isDarkMode: boolean): StructurePreviewProps {
145148
const palette = structurePreviewPalette[isDarkMode ? "dark" : "light"];
146149
const structurePreviewChildren: StructurePreviewProps[] = [];
147-
let readOnly = _values.readOnly;
150+
let readOnly = values.readOnly;
148151

149152
// Handle custom content dropzones when enabled
150-
if (_values.optionsSourceCustomContentType !== "no") {
151-
if (_values.source === "context" && _values.optionsSourceType === "association") {
153+
if (values.optionsSourceCustomContentType !== "no") {
154+
if (values.source === "context" && values.optionsSourceType === "association") {
152155
structurePreviewChildren.push(
153156
dropzone(
154157
dropzone.placeholder("Configure the selection controls: Place widgets here"),
155158
dropzone.hideDataSourceHeaderIf(false)
156-
)(_values.optionsSourceAssociationCustomContent)
159+
)(values.optionsSourceAssociationCustomContent)
157160
);
158-
} else if (_values.source === "database") {
161+
} else if (values.source === "database") {
159162
structurePreviewChildren.push(
160163
dropzone(
161164
dropzone.placeholder("Configure the selection controls: Place widgets here"),
162165
dropzone.hideDataSourceHeaderIf(false)
163-
)(_values.optionsSourceDatabaseCustomContent)
166+
)(values.optionsSourceDatabaseCustomContent)
164167
);
165-
} else if (_values.source === "static") {
166-
_values.optionsSourceStaticDataSource.forEach(value => {
168+
} else if (values.source === "static") {
169+
values.optionsSourceStaticDataSource.forEach(value => {
167170
structurePreviewChildren.push(
168171
container({
169172
borders: true,
@@ -183,76 +186,31 @@ export function getPreview(_values: SelectionControlsPreviewProps, isDarkMode: b
183186
}
184187

185188
// Handle database-specific read-only logic
186-
if (_values.source === "database" && _values.databaseAttributeString.length === 0) {
187-
readOnly = _values.customEditability === "never";
189+
if (values.source === "database" && values.databaseAttributeString.length === 0) {
190+
readOnly = values.customEditability === "never";
188191
}
189192

190193
// If no custom content dropzones, show default preview
191194
if (structurePreviewChildren.length === 0) {
192-
return {
193-
type: "RowLayout",
194-
columnSize: "fixed",
195-
backgroundColor: readOnly ? palette.background.containerDisabled : palette.background.containerFill,
196-
children: [
197-
{
198-
type: "RowLayout",
199-
columnSize: "grow",
200-
children: [
201-
getIconPreview(isDarkMode),
202-
{
203-
type: "Container",
204-
padding: 4,
205-
children: [
206-
{
207-
type: "Text",
208-
content: "Selection Controls",
209-
fontColor: palette.text.primary,
210-
fontSize: 10
211-
}
212-
]
213-
}
214-
]
215-
}
216-
]
217-
};
195+
const isMultiSelect = values.optionsSourceDatabaseItemSelection === "Multi";
196+
return container()(
197+
rowLayout({
198+
columnSize: "grow",
199+
backgroundColor: palette.background.container
200+
})(
201+
getIconPreview(isMultiSelect),
202+
container()(container({ padding: 3 })(), text()(getCustomCaption(values)))
203+
)
204+
);
218205
}
219206

220207
// Return container with dropzones
221-
return {
222-
type: "Container",
223-
children: [
224-
{
225-
type: "RowLayout",
226-
columnSize: "grow",
227-
borders: true,
228-
borderWidth: 1,
229-
borderRadius: 2,
230-
backgroundColor: readOnly ? palette.background.containerDisabled : palette.background.container,
231-
children: [
232-
{
233-
type: "Container",
234-
grow: 1,
235-
padding: 4,
236-
children: structurePreviewChildren
237-
},
238-
readOnly && _values.readOnlyStyle === "text"
239-
? container({ grow: 0, padding: 4 })()
240-
: {
241-
...getIconPreview(isDarkMode),
242-
...{ grow: 0, padding: 4 }
243-
}
244-
]
245-
}
246-
]
247-
};
248-
}
249-
250-
export function getCustomCaption(values: SelectionControlsPreviewProps): string {
251-
if (values.source === "static" && values.optionsSourceStaticDataSource.length > 0) {
252-
return "Selection Controls (Static)";
253-
}
254-
if (values.source === "database") {
255-
return "Selection Controls (Database)";
256-
}
257-
return "Selection Controls";
208+
return container()(
209+
rowLayout({
210+
columnSize: "grow",
211+
borders: true,
212+
borderWidth: 1,
213+
borderRadius: 2
214+
})(container({ grow: 1, padding: 4 })(...structurePreviewChildren))
215+
);
258216
}

packages/pluggableWidgets/selection-controls-web/src/SelectionControls.editorPreview.tsx

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ import { ReactElement, createElement, useMemo } from "react";
33
import { SelectionControlsPreviewProps } from "../typings/SelectionControlsProps";
44
import { RadioSelection } from "./components/RadioSelection/RadioSelection";
55
import { dynamic } from "@mendix/widget-plugin-test-utils";
6-
import { SingleSelector, SelectionBaseProps } from "./helpers/types";
6+
import { SingleSelector, SelectionBaseProps, MultiSelector } from "./helpers/types";
77
import { StaticPreviewSelector } from "./helpers/Static/Preview/StaticPreviewSelector";
8-
import { DatabasePreviewSelector } from "./helpers/Database/Preview/DatabasePreviewSelector";
8+
import {
9+
DatabaseMultiPreviewSelector,
10+
DatabasePreviewSelector
11+
} from "./helpers/Database/Preview/DatabasePreviewSelector";
912
import { AssociationPreviewSelector } from "./helpers/Association/Preview/AssociationPreviewSelector";
1013
import "./ui/SelectionControls.scss";
14+
import { CheckboxSelection } from "./components/CheckboxSelection/CheckboxSelection";
1115

1216
export const preview = (props: SelectionControlsPreviewProps): ReactElement => {
1317
const id = generateUUID().toString();
@@ -16,30 +20,31 @@ export const preview = (props: SelectionControlsPreviewProps): ReactElement => {
1620
inputId: id,
1721
labelId: `${id}-label`,
1822
readOnlyStyle: props.readOnlyStyle,
19-
ariaRequired: dynamic(false),
20-
a11yConfig: {
21-
a11yStatusMessage: {
22-
a11ySelectedValue: props.a11ySelectedValue,
23-
a11yOptionsAvailable: props.a11yOptionsAvailable,
24-
a11yInstructions: props.a11yInstructions
25-
}
26-
}
23+
ariaRequired: dynamic(false)
2724
};
2825

2926
// eslint-disable-next-line react-hooks/rules-of-hooks
30-
const selector: SingleSelector = useMemo(() => {
27+
const selector: SingleSelector | MultiSelector = useMemo(() => {
3128
if (props.source === "static") {
3229
return new StaticPreviewSelector(props);
3330
}
3431
if (props.source === "database") {
35-
return new DatabasePreviewSelector(props);
32+
if (props.optionsSourceDatabaseItemSelection === "Multi") {
33+
return new DatabaseMultiPreviewSelector(props);
34+
} else {
35+
return new DatabasePreviewSelector(props);
36+
}
3637
}
3738
return new AssociationPreviewSelector(props);
3839
}, [props]);
3940

4041
return (
4142
<div className="widget-selection-controls widget-selection-controls-editor-preview">
42-
<RadioSelection selector={selector} {...commonProps} />
43+
{selector.type === "single" ? (
44+
<RadioSelection selector={selector} {...commonProps} />
45+
) : (
46+
<CheckboxSelection selector={selector} {...commonProps} />
47+
)}
4348
</div>
4449
);
4550
};

packages/pluggableWidgets/selection-controls-web/src/SelectionControls.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,7 @@ export default function SelectionControls(props: SelectionControlsContainerProps
1717
inputId: props.id,
1818
labelId: `${props.id}-label`,
1919
readOnlyStyle: props.readOnlyStyle,
20-
ariaRequired: props.ariaRequired,
21-
a11yConfig: {
22-
a11yStatusMessage: {
23-
a11ySelectedValue: props.a11ySelectedValue?.value ?? "",
24-
a11yOptionsAvailable: props.a11yOptionsAvailable?.value ?? "",
25-
a11yInstructions: props.a11yInstructions?.value ?? ""
26-
}
27-
}
20+
ariaRequired: props.ariaRequired
2821
};
2922

3023
return (

packages/pluggableWidgets/selection-controls-web/src/SelectionControls.xml

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -256,32 +256,6 @@
256256
<returnType type="Boolean" />
257257
</property>
258258
</propertyGroup>
259-
<propertyGroup caption="Accessibility status message ">
260-
<property key="a11ySelectedValue" type="textTemplate" required="false">
261-
<caption>Selected value</caption>
262-
<description>Output example: "Selected value: Avocado, Apple, Banana."</description>
263-
<translations>
264-
<translation lang="en_US">Selected value:</translation>
265-
<translation lang="nl_NL">Geselecteerde waarde:</translation>
266-
</translations>
267-
</property>
268-
<property key="a11yOptionsAvailable" type="textTemplate" required="false">
269-
<caption>Options available</caption>
270-
<description>Output example: "Number of options available: 1"</description>
271-
<translations>
272-
<translation lang="en_US">Number of options available:</translation>
273-
<translation lang="nl_NL">Aantal beschikbare opties:</translation>
274-
</translations>
275-
</property>
276-
<property key="a11yInstructions" type="textTemplate" required="false">
277-
<caption>Instructions</caption>
278-
<description>Instructions to be read after announcing the status.</description>
279-
<translations>
280-
<translation lang="en_US">Use up and down arrow keys to navigate. Press Enter or Space Bar keys to select.</translation>
281-
<translation lang="nl_NL">Gebruik de pijltjestoetsen (omhoog en omlaag) om te navigeren. Druk op Enter of de spatiebalk om de waarde te selecteren.</translation>
282-
</translations>
283-
</property>
284-
</propertyGroup>
285259
</propertyGroup>
286260
</properties>
287261
</widget>
Lines changed: 7 additions & 0 deletions
Loading
Lines changed: 4 additions & 0 deletions
Loading

packages/pluggableWidgets/selection-controls-web/src/components/CheckboxSelection/CheckboxSelection.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,6 @@ export function CheckboxSelection({
2121
}
2222
};
2323

24-
if (selector.status === "unavailable") {
25-
return (
26-
<div className="widget-selection-controls-checkbox">
27-
<div className="widget-selection-controls-checkbox-loading">Loading...</div>
28-
</div>
29-
);
30-
}
31-
3224
return (
3325
<div
3426
className={classNames("widget-selection-controls-checkbox", {
@@ -45,6 +37,7 @@ export function CheckboxSelection({
4537
{options.map((optionId, index) => {
4638
const isSelected = currentIds.includes(optionId);
4739
const checkboxId = `${inputId}-checkbox-${index}`;
40+
const name = selector.caption.get(optionId);
4841

4942
return (
5043
<div
@@ -56,12 +49,12 @@ export function CheckboxSelection({
5649
<input
5750
type="checkbox"
5851
id={checkboxId}
52+
name={name && name.length > 0 ? name : inputId}
5953
value={optionId}
6054
checked={isSelected}
6155
disabled={isReadOnly}
6256
tabIndex={tabIndex}
6357
onChange={e => handleChange(optionId, e.target.checked)}
64-
aria-describedby={`${inputId}-description`}
6558
/>
6659
<CaptionContent htmlFor={checkboxId}>{selector.caption.render(optionId)}</CaptionContent>
6760
</div>

packages/pluggableWidgets/selection-controls-web/src/components/Placeholder.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,3 @@ export function Placeholder(): ReactElement {
77
</div>
88
);
99
}
10-
11-
export function NoOptionsPlaceholder(): ReactElement {
12-
return <div className="widget-selection-controls-no-options">No options available</div>;
13-
}

packages/pluggableWidgets/selection-controls-web/src/components/RadioSelection/RadioSelection.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,6 @@ export function RadioSelection({
2020
}
2121
};
2222

23-
if (selector.status === "unavailable") {
24-
return (
25-
<div className="widget-selection-controls-radio">
26-
<div className="widget-selection-controls-radio-loading">Loading...</div>
27-
</div>
28-
);
29-
}
30-
3123
return (
3224
<div
3325
className={classNames("widget-selection-controls-radio", {
@@ -44,6 +36,7 @@ export function RadioSelection({
4436
{options.map((optionId, index) => {
4537
const isSelected = currentId === optionId;
4638
const radioId = `${inputId}-radio-${index}`;
39+
const name = selector.caption.get(optionId);
4740

4841
return (
4942
<div
@@ -55,13 +48,12 @@ export function RadioSelection({
5548
<input
5649
type="radio"
5750
id={radioId}
58-
name={inputId}
51+
name={name && name.length > 0 ? name : inputId}
5952
value={optionId}
6053
checked={isSelected}
6154
disabled={isReadOnly}
6255
tabIndex={tabIndex}
6356
onChange={() => handleChange(optionId)}
64-
aria-describedby={`${inputId}-description`}
6557
/>
6658
<CaptionContent htmlFor={radioId}>{selector.caption.render(optionId)}</CaptionContent>
6759
</div>

packages/pluggableWidgets/selection-controls-web/src/helpers/Association/Preview/AssociationPreviewSelector.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
77
import { PreviewCaptionsProvider } from "../../Preview/PreviewCaptionsProvider";
88
import { PreviewOptionsProvider } from "../../Preview/PreviewOptionsProvider";
9+
import { getCustomCaption } from "../../utils";
910

1011
export class AssociationPreviewSelector implements SingleSelector {
1112
type = "single" as const;
@@ -26,7 +27,7 @@ export class AssociationPreviewSelector implements SingleSelector {
2627
this.currentId = `single-${generateUUID()}`;
2728
this.customContentType = props.optionsSourceCustomContentType;
2829
this.readOnly = props.readOnly;
29-
this.caption = new PreviewCaptionsProvider(new Map());
30+
this.caption = new PreviewCaptionsProvider(new Map(), getCustomCaption(props));
3031
this.options = new PreviewOptionsProvider(this.caption, new Map());
3132
(this.caption as PreviewCaptionsProvider).updatePreviewProps({
3233
customContentRenderer: props.optionsSourceAssociationCustomContent?.renderer,

0 commit comments

Comments
 (0)