Skip to content

Commit 61c73a0

Browse files
committed
feat: StyledSchemaFormInPlace schema component
1 parent 6a10475 commit 61c73a0

File tree

5 files changed

+141
-10
lines changed

5 files changed

+141
-10
lines changed

packages/webui/src/client/lib/Components/DropdownInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export function DropdownInputControl<TValue>({
112112
const newOptions = [
113113
...options,
114114
{
115-
name: 'Value: ' + value,
115+
name: String(value),
116116
value: value,
117117
i: options.length,
118118
},
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// This styling has a lot of force added, and should be seen as a workaround
2+
// to get styling on the current Sofie UI schema/overrides components
3+
// without changing current look and behavior in other places of Sofie
4+
.styled-schema-form {
5+
width: 100%;
6+
7+
// Force the base input-l class
8+
.input-l {
9+
width: 100% !important;
10+
max-width: none !important;
11+
margin-left: 0px;
12+
border: none;
13+
}
14+
15+
// Force the select/text-input defaults
16+
.select,
17+
.inline-select,
18+
.text-input {
19+
display: block !important;
20+
position: relative;
21+
width: 100% !important;
22+
}
23+
24+
.input {
25+
border: 1px solid #e5e7eb;
26+
border-radius: 0.375rem;
27+
padding: 0.5rem 0.75rem;
28+
width: 100%;
29+
30+
&:focus {
31+
outline: none;
32+
border-color: #3b82f6;
33+
box-shadow: 0 0 0 1px #3b82f6;
34+
}
35+
}
36+
37+
.label-text {
38+
&:before {
39+
content: none !important;
40+
}
41+
}
42+
43+
.dropdown {
44+
background: white;
45+
border: 1px solid #e5e7eb;
46+
border-radius: 0.375rem;
47+
width: 100%;
48+
max-width: 100%;
49+
50+
.input,
51+
.input-l {
52+
border: none;
53+
outline: none;
54+
box-shadow: none;
55+
}
56+
57+
&:focus-within {
58+
border-color: #3b82f6;
59+
box-shadow: 0 0 0 1px #3b82f6;
60+
}
61+
}
62+
63+
// Force the label over selector
64+
.label-actual {
65+
margin-bottom: 0.5rem !important; // Increased spacing between label and selector
66+
}
67+
68+
.label {
69+
font-size: 0.875rem;
70+
font-weight: 500;
71+
color: #374151;
72+
display: block;
73+
}
74+
75+
76+
}

packages/webui/src/client/lib/forms/SchemaFormInPlace.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
} from '../../ui/Settings/util/OverrideOpHelper'
77
import { SchemaFormCommonProps } from './schemaFormUtil'
88
import { SchemaFormWithOverrides } from './SchemaFormWithOverrides'
9+
import './SchemaFormInPlace.scss'
910

1011
interface SchemaFormInPlaceProps extends Omit<SchemaFormCommonProps, 'isRequired'> {
1112
/** The object to be modified in place */
@@ -33,6 +34,58 @@ export function SchemaFormInPlace({ object, ...commonProps }: Readonly<SchemaFor
3334
return <SchemaFormWithOverrides {...commonProps} attr={''} item={wrappedItem} overrideHelper={helper} isRequired />
3435
}
3536

37+
interface StyledSchemaFormInPlaceProps extends Omit<SchemaFormCommonProps, 'isRequired'> {
38+
/** The object to be modified in place */
39+
object: any
40+
/** Optional CSS class to apply to the form wrapper */
41+
/** This may or may not work, as there's different styling in the sub components */
42+
className?: string
43+
/** Whether to use compact styling */
44+
compact?: boolean
45+
/** Width for the form (e.g., '300px', '100%') */
46+
width?: string
47+
}
48+
49+
export function StyledSchemaFormInPlace({
50+
object,
51+
className = '',
52+
compact = false,
53+
width = '',
54+
...commonProps
55+
}: Readonly<StyledSchemaFormInPlaceProps>): JSX.Element {
56+
// This is a hack to avoid issues with the UI re-rendering as 'nothing' changed
57+
const [editCount, setEditCount] = useState(0)
58+
const forceRender = useCallback(() => setEditCount((v) => v + 1), [])
59+
60+
const helper = useCallback(() => new OverrideOpHelperInPlace(object, forceRender), [object, forceRender])
61+
62+
const wrappedItem = useMemo(
63+
() =>
64+
literal<WrappedOverridableItemNormal<any>>({
65+
type: 'normal',
66+
id: 'not-used' + editCount,
67+
computed: object,
68+
defaults: undefined,
69+
overrideOps: [],
70+
}),
71+
[object, editCount]
72+
)
73+
74+
const style = {
75+
width: width || '300px',
76+
maxWidth: width || '300px',
77+
minWidth: width || '300px',
78+
}
79+
80+
const formClasses = ['styled-schema-form', compact ? 'space-y-2' : 'space-y-4', className].filter(Boolean).join(' ')
81+
82+
return (
83+
<div className={formClasses} style={style}>
84+
<SchemaFormWithOverrides {...commonProps} attr={''} item={wrappedItem} overrideHelper={helper} isRequired />
85+
</div>
86+
)
87+
}
88+
3689
/**
3790
* An alternate OverrideOpHelper designed to directly mutate an object, instead of using the `ObjectWithOverrides` system.
3891
* This allows us to have one SchemaForm implementation that can handle working with `ObjectWithOverrides`, and simpler options

packages/webui/src/client/lib/forms/SchemaFormWithOverrides.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ interface FormComponentProps {
5757

5858
function useChildPropsForFormComponent(props: Readonly<SchemaFormWithOverridesProps>): FormComponentProps {
5959
return useMemo(() => {
60-
const title = getSchemaUIField(props.schema, SchemaFormUIField.Title) || props.attr
60+
// If a tittle is added to the Schema use that if not use the props.attr instead
61+
const title = props.schema.title || getSchemaUIField(props.schema, SchemaFormUIField.Title) || props.attr
6162
const description = getSchemaUIField(props.schema, SchemaFormUIField.Description)
6263

6364
return {

packages/webui/src/client/ui/UserEditOperations/PropertiesPanel.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { useSelection } from '../RundownView/SelectedElementsContext'
2626
import { DBSegment } from '@sofie-automation/corelib/dist/dataModel/Segment'
2727
import { DBPart } from '@sofie-automation/corelib/dist/dataModel/Part'
2828
import { RundownId } from '@sofie-automation/corelib/dist/dataModel/Ids'
29-
import { SchemaFormInPlace } from '../../lib/forms/SchemaFormInPlace'
29+
import { StyledSchemaFormInPlace } from '../../lib/forms/SchemaFormInPlace'
3030
import { RundownUtils } from '../../lib/rundown'
3131
import * as CoreIcon from '@nrk/core-icons/jsx'
3232
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
@@ -453,12 +453,6 @@ function EditingTypeChangeSourceLayerSource(props: {
453453
getPendingState() !== undefined && getPendingState() !== props.userEditOperation.currentValues.value
454454
)
455455

456-
React.useEffect(() => {
457-
setHasBeenEdited(
458-
getPendingState() !== undefined && getPendingState() !== props.userEditOperation.currentValues.value
459-
)
460-
}, [props.userEditOperation.id, props.pendingChanges])
461-
462456
const jsonSchema = Object.values<UserEditingSourceLayer>(props.userEditOperation.schemas).find(
463457
(layer) => layer.sourceLayerType === selectedSourceGroup
464458
)?.schema
@@ -470,6 +464,10 @@ function EditingTypeChangeSourceLayerSource(props: {
470464
setSelectedSourceButton(pendingChange?.sourceLayerType || props.userEditOperation.currentValues.type)
471465

472466
setSelectedValues(pendingChange?.value || props.userEditOperation.currentValues.value)
467+
468+
setHasBeenEdited(
469+
getPendingState() !== undefined && getPendingState() !== props.userEditOperation.currentValues.value
470+
)
473471
}, [props.userEditOperation.id, props.pendingChanges])
474472

475473
const handleSourceChange = () => {
@@ -541,10 +539,13 @@ function EditingTypeChangeSourceLayerSource(props: {
541539
onChange={handleSourceChange}
542540
>
543541
{hasBeenEdited && <FontAwesomeIcon icon="pencil-alt" />}
544-
<SchemaFormInPlace
542+
<StyledSchemaFormInPlace
545543
schema={selectedGroupSchema}
546544
object={selectedValues}
547545
translationNamespaces={props.userEditOperation.translationNamespaces}
546+
compact={false}
547+
className="custom-class"
548+
width="100%"
548549
/>
549550
</div>
550551
</div>

0 commit comments

Comments
 (0)