-
-
Notifications
You must be signed in to change notification settings - Fork 742
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve color widget picker and types #5948
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Split widgets type definitions into their own interfaces so they are extendable @sneridagh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,95 +1,112 @@ | ||
export interface WidgetsConfigById { | ||
schema: React.ComponentType; | ||
subjects: React.ComponentType; | ||
query: React.ComponentType; | ||
recurrence: React.ComponentType; | ||
remoteUrl: React.ComponentType; | ||
id: React.ComponentType; | ||
site_logo: React.ComponentType; | ||
} | ||
|
||
export interface WidgetsConfigByWidget { | ||
textarea: React.ComponentType; | ||
datetime: React.ComponentType; | ||
date: React.ComponentType; | ||
password: React.ComponentType; | ||
file: React.ComponentType; | ||
align: React.ComponentType; | ||
buttons: React.ComponentType; | ||
url: React.ComponentType; | ||
internal_url: React.ComponentType; | ||
email: React.ComponentType; | ||
array: React.ComponentType; | ||
token: React.ComponentType; | ||
query: React.ComponentType; | ||
query_sort_on: React.ComponentType; | ||
querystring: React.ComponentType; | ||
object_browser: React.ComponentType; | ||
object: React.ComponentType; | ||
object_list: React.ComponentType; | ||
vocabularyterms: React.ComponentType; | ||
image_size: React.ComponentType; | ||
select_querystring_field: React.ComponentType; | ||
autocomplete: React.ComponentType; | ||
color_picker: React.ComponentType; | ||
select: React.ComponentType; | ||
} | ||
|
||
export interface WidgetsConfigByVocabulary { | ||
'plone.app.vocabularies.Catalog': React.ComponentType; | ||
} | ||
|
||
export interface WidgetsConfigByFactory { | ||
'Relation List': React.ComponentType; | ||
'Relation Choice': React.ComponentType; | ||
} | ||
|
||
export interface WidgetsConfigByType { | ||
boolean: React.ComponentType; | ||
array: React.ComponentType; | ||
object: React.ComponentType; | ||
datetime: React.ComponentType; | ||
date: React.ComponentType; | ||
password: React.ComponentType; | ||
number: React.ComponentType; | ||
integer: React.ComponentType; | ||
id: React.ComponentType; | ||
} | ||
|
||
export interface WidgetsConfigViewById { | ||
file: React.ComponentType; | ||
image: React.ComponentType; | ||
relatedItems: React.ComponentType; | ||
subjects: React.ComponentType; | ||
} | ||
|
||
export interface WidgetsConfigViewByWidget { | ||
array: React.ComponentType; | ||
boolean: React.ComponentType; | ||
choices: React.ComponentType; | ||
date: React.ComponentType; | ||
datetime: React.ComponentType; | ||
description: React.ComponentType; | ||
email: React.ComponentType; | ||
file: React.ComponentType; | ||
image: React.ComponentType; | ||
password: React.ComponentType; | ||
relation: React.ComponentType; | ||
richtext: React.ComponentType; | ||
string: React.ComponentType; | ||
tags: React.ComponentType; | ||
textarea: React.ComponentType; | ||
title: React.ComponentType; | ||
url: React.ComponentType; | ||
internal_url: React.ComponentType; | ||
object: React.ComponentType; | ||
} | ||
|
||
export interface WidgetsConfigViewByType { | ||
array: React.ComponentType; | ||
boolean: React.ComponentType; | ||
} | ||
|
||
export interface WidgetsConfigViews { | ||
getWidget: React.ComponentType; | ||
default: React.ComponentType; | ||
id: WidgetsConfigViewById; | ||
widget: WidgetsConfigViewByWidget; | ||
vocabulary: {}; | ||
choices: React.ComponentType; | ||
type: WidgetsConfigViewByType; | ||
} | ||
|
||
export interface WidgetsConfig { | ||
default: React.ComponentType; | ||
id: { | ||
schema: React.ComponentType; | ||
subjects: React.ComponentType; | ||
query: React.ComponentType; | ||
recurrence: React.ComponentType; | ||
remoteUrl: React.ComponentType; | ||
id: React.ComponentType; | ||
site_logo: React.ComponentType; | ||
}; | ||
widget: { | ||
textarea: React.ComponentType; | ||
datetime: React.ComponentType; | ||
date: React.ComponentType; | ||
password: React.ComponentType; | ||
file: React.ComponentType; | ||
align: React.ComponentType; | ||
buttons: React.ComponentType; | ||
url: React.ComponentType; | ||
internal_url: React.ComponentType; | ||
email: React.ComponentType; | ||
array: React.ComponentType; | ||
token: React.ComponentType; | ||
query: React.ComponentType; | ||
query_sort_on: React.ComponentType; | ||
querystring: React.ComponentType; | ||
object_browser: React.ComponentType; | ||
object: React.ComponentType; | ||
object_list: React.ComponentType; | ||
vocabularyterms: React.ComponentType; | ||
image_size: React.ComponentType; | ||
select_querystring_field: React.ComponentType; | ||
autocomplete: React.ComponentType; | ||
color_picker: React.ComponentType; | ||
select: React.ComponentType; | ||
}; | ||
vocabulary: { | ||
'plone.app.vocabularies.Catalog': React.ComponentType; | ||
}; | ||
factory: { | ||
'Relation List': React.ComponentType; | ||
'Relation Choice': React.ComponentType; | ||
}; | ||
id: WidgetsConfigById; | ||
widget: WidgetsConfigByWidget; | ||
vocabulary: WidgetsConfigByVocabulary; | ||
factory: WidgetsConfigByFactory; | ||
choices: React.ComponentType; | ||
type: { | ||
boolean: React.ComponentType; | ||
array: React.ComponentType; | ||
object: React.ComponentType; | ||
datetime: React.ComponentType; | ||
date: React.ComponentType; | ||
password: React.ComponentType; | ||
number: React.ComponentType; | ||
integer: React.ComponentType; | ||
id: React.ComponentType; | ||
}; | ||
views: { | ||
getWidget: React.ComponentType; | ||
default: React.ComponentType; | ||
id: { | ||
file: React.ComponentType; | ||
image: React.ComponentType; | ||
relatedItems: React.ComponentType; | ||
subjects: React.ComponentType; | ||
}; | ||
widget: { | ||
array: React.ComponentType; | ||
boolean: React.ComponentType; | ||
choices: React.ComponentType; | ||
date: React.ComponentType; | ||
datetime: React.ComponentType; | ||
description: React.ComponentType; | ||
email: React.ComponentType; | ||
file: React.ComponentType; | ||
image: React.ComponentType; | ||
password: React.ComponentType; | ||
relation: React.ComponentType; | ||
relations: React.ComponentType; | ||
richtext: React.ComponentType; | ||
string: React.ComponentType; | ||
tags: React.ComponentType; | ||
textarea: React.ComponentType; | ||
title: React.ComponentType; | ||
url: React.ComponentType; | ||
internal_url: React.ComponentType; | ||
object: React.ComponentType; | ||
}; | ||
vocabulary: {}; | ||
choices: React.ComponentType; | ||
type: { | ||
array: React.ComponentType; | ||
boolean: React.ComponentType; | ||
}; | ||
}; | ||
type: WidgetsConfigByType; | ||
views: WidgetsConfigViews; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Improve `ColorPickerWidget` typings @sneridagh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sneridagh This doesn't seem right to me. These are not interfaces with a fixed set of keys. They are mappings which can take an arbitrary number of string: React.ComponentType entries, to register new widget types. Isn't there some way we can express that in a type without needing to list all these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The beauty of a TS interface is that you can extend them as in:
anywhere, eg. in your add-on.
https://github.com/kitconcept/kitconcept.com/blob/main/frontend/src/addons/volto-kitconcept_com/src/index.ts#L50-L53
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sneridagh Yeah but it seems ridiculous if I have to update an interface just to declare that there is a new type of widget that I'd like to register, and then also actually register it.
I think these types should be declared as
Record<string, React.ComponentType<any>
-- https://dmitripavlutin.com/typescript-record/There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@davisagli You are right, in this one makes sense, because all have the same shape (They are all Record<string, React.ComponentType), in others is not that easy, and TS is not that smart when all the records do not have the same shape, or if you have to start writing complex unions.
I'd like also to standardize and make people know and use the extending interfaces pattern, so my reasoning path went in that way too. But it's true that as much as we can prevent people from writing code, we should.
Let me try it out how well it works and I will make a PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@davisagli Trying it out, I remembered why :) So it's all about autocompletion too. With a generic record you cannot have both. Also this is not allowed:
And you can't do:
Since Interfaces can't declare both static and dynamic keys:
https://ts-error-translator.vercel.app/?error=IIAgtghgDlCmAmIAuBPO4IpAOwPZJHlgGMAbCAJ1hCgtzgqQEtYBnEXC8WJAC13isAdEA
Since interfaces don't work like this, so you have to fall back to types, then they are not extendable.
So we can only have both extensibility and autocompletion using this pattern.
Let's talk about this on Monday!