Skip to content
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

feat: support input[type=radio] #581

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 138 additions & 6 deletions webf/lib/src/html/input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,51 @@ const Map<String, dynamic> _checkboxDefaultStyle = {
};

class FlutterInputElement extends WidgetElement
with BaseCheckBoxElement, BaseButtonElement, BaseInputElement, BaseTimeElement {
with
BaseRadioElement,
BaseCheckBoxElement,
BaseButtonElement,
BaseInputElement,
BaseTimeElement {
BindingContext? buildContext;

FlutterInputElement(BindingContext? context) : super(context) {
buildContext = context;
}

@override
void initState() {
super.initState();
switch (type) {
case 'radio':
initRadioState();
break;
default:
initBaseInputState();
break;
}
}

@override
Future<void> dispose() async {
super.dispose();
switch (type) {
case 'radio':
disposeRadio();
break;
default:
disposeBaseInput();
break;
}
}

@override
Map<String, dynamic> get defaultStyle {
switch (type) {
case 'text':
case 'time':
return _inputDefaultStyle;
case 'radio':
case 'checkbox':
return _checkboxDefaultStyle;
}
Expand Down Expand Up @@ -79,6 +111,8 @@ class FlutterInputElement extends WidgetElement
@override
Widget build(BuildContext context, List<Widget> children) {
switch (type) {
case 'radio':
return createRadio(context);
case 'checkbox':
return createCheckBox(context);
case 'button':
Expand Down Expand Up @@ -118,8 +152,7 @@ mixin BaseInputElement on WidgetElement {
hasDirtyValue = true;
}

@override
void initState() {
void initBaseInputState() {
_focusNode ??= FocusNode();
_focusNode!.addListener(handleFocusChange);
}
Expand Down Expand Up @@ -174,6 +207,7 @@ mixin BaseInputElement on WidgetElement {

void resetInputDefaultStyle() {
switch (type) {
case 'radio':
case 'checkbox':
{
_checkboxDefaultStyle.forEach((key, value) {
Expand Down Expand Up @@ -409,9 +443,7 @@ mixin BaseInputElement on WidgetElement {
}
}

@override
Future<void> dispose() async {
super.dispose();
Future<void> disposeBaseInput() async {
_focusNode?.dispose();
}

Expand All @@ -438,6 +470,106 @@ mixin BaseInputElement on WidgetElement {
}
}

/// create a radio widget when input type='radio'

mixin BaseRadioElement on WidgetElement {
static final Map<String, String> _groupValues = <String, String>{};

static final StreamController<Map<String, String>> _streamController =
StreamController<Map<String, String>>.broadcast();

// static final Stream<Map<String, String>> stream = _streamController.stream.asBroadcastStream(onLis);

late StreamSubscription<Map<String, String>> _subscription;

void initRadioState() {
_subscription = _streamController.stream.listen((message) {
setState(() {
for (var entry in message.entries) {
if (entry.key == name) {
groupValue = entry.value;
}
}
});
});
}

void disposeRadio() {
_subscription.cancel();
_groupValues.remove(name);
if (_groupValues.isEmpty) {
_streamController.close();
}
}

String get groupValue => _groupValues[name] ?? name;
set groupValue(String? gv) {
internalSetAttribute('groupValue', gv ?? name);
_groupValues[name] = gv ?? name;
}

bool get disabled => getAttribute('disabled') != null;

String get value => getAttribute('value') ?? '';

String _name = '';
String get name => _name;
set name(String? n) {
if (_groupValues[_name] != null) {
_groupValues.remove(_name);
}
_name = n?.toString() ?? '';
_groupValues[_name] = _name;
}

@override
void initializeProperties(Map<String, BindingObjectProperty> properties) {
super.initializeProperties(properties);

properties['name'] = BindingObjectProperty(
getter: () => name, setter: (value) => name = value);
}

@override
void initializeAttributes(Map<String, ElementAttributeProperty> attributes) {
super.initializeAttributes(attributes);

attributes['name'] = ElementAttributeProperty(
getter: () => name, setter: (value) => name = value);
}

double getRadioSize() {
//TODO support zoom
//width and height
if (renderStyle.width.value != null && renderStyle.height.value != null) {
return renderStyle.width.computedValue / 18.0;
}
return 1.0;
}

Widget createRadio(BuildContext context) {
String singleRadioValue = '$name-$value';
return Transform.scale(
child: Radio<String>(
value: singleRadioValue,
onChanged: disabled
? null
: (String? newValue) {
setState(() {
if (newValue != null) {
Map<String, String> map = <String, String>{};
map[name] = newValue;
_streamController.sink.add(map);
}
dispatchEvent(Event('change'));
});
},
groupValue: groupValue),
scale: getRadioSize(),
);
}
}

/// create a checkBox widget when input type='checkbox'
mixin BaseCheckBoxElement on WidgetElement {
bool checked = false;
Expand Down
2 changes: 1 addition & 1 deletion webf/lib/src/rendering/flow.dart
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,7 @@ class RenderFlowLayout extends RenderLayoutBox {
}
// Should add horizontal margin of child to the main axis auto size of parent.
if (runChild is RenderBoxModel) {
runChildMainSize = runChild.boxSize?.width ?? 0.0;
runChildMainSize = runChild.minContentWidth;
double childMarginLeft = runChild.renderStyle.marginLeft.computedValue;
double childMarginRight = runChild.renderStyle.marginRight.computedValue;
runChildMainSize += childMarginLeft + childMarginRight;
Expand Down
Loading