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: add fieldset widget #3255 #3867

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions packages/controls/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ export * from './widget_tagsinput';
export * from './widget_string';
export * from './widget_description';
export * from './widget_upload';
export * from './widget_fieldset';

export const version = (require('../package.json') as any).version;
127 changes: 127 additions & 0 deletions packages/controls/src/widget_fieldset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import {
DOMWidgetView,
unpack_models,
ViewList,
JupyterLuminoPanelWidget,
reject,
WidgetModel,
WidgetView,
} from '@jupyter-widgets/base';

import { CoreDOMWidgetModel } from './widget_core';

import { ArrayExt } from '@lumino/algorithm';

import { MessageLoop } from '@lumino/messaging';

import { Widget } from '@lumino/widgets';

import $ from 'jquery';

export class FieldsetModel extends CoreDOMWidgetModel {
defaults(): Backbone.ObjectHash {
return {
...super.defaults(),
_view_name: 'FieldsetView',
_model_name: 'FieldsetModel',
children: [],
box_style: '',
};
}

static serializers = {
...CoreDOMWidgetModel.serializers,
children: { deserialize: unpack_models },
};
}


export class FieldsetView extends DOMWidgetView {
_createElement(tagName: string): HTMLElement {
this.luminoWidget = new JupyterLuminoPanelWidget({ view: this });
return this.luminoWidget.node;
}

_setElement(el: HTMLElement): void {
if (this.el || el !== this.luminoWidget.node) {
// Boxes don't allow setting the element beyond the initial creation.
throw new Error('Cannot reset the DOM element.');
}

this.el = this.luminoWidget.node;
this.$el = $(this.luminoWidget.node);
}

initialize(parameters: WidgetView.IInitializeParameters): void {
super.initialize(parameters);
this.children_views = new ViewList(this.add_child_model, null, this);
this.listenTo(this.model, 'change:children', this.update_children);
this.listenTo(this.model, 'change:fieldset_style', this.update_fieldset_style);

this.luminoWidget.addClass('jupyter-widgets');
this.luminoWidget.addClass('widget-container');
}

render(): void {
super.render();
this.update_children();
this.set_fieldset_style();
}

update_children(): void {
this.children_views
?.update(this.model.get('children'))
.then((views: DOMWidgetView[]) => {
// Notify all children that their sizes may have changed.
views.forEach((view) => {
MessageLoop.postMessage(
view.luminoWidget,
Widget.ResizeMessage.UnknownSize
);
});
});
}

update_fieldset_style(): void {
this.update_mapped_classes(FieldsetView.class_map, 'fieldset_style');
}

set_fieldset_style(): void {
this.set_mapped_classes(FieldsetView.class_map, 'fieldset_style');
}

add_child_model(model: WidgetModel): Promise<DOMWidgetView> {
// we insert a dummy element so the order is preserved when we add
// the rendered content later.
const dummy = new Widget();
this.luminoWidget.addWidget(dummy);

return this.create_child_view(model)
.then((view: DOMWidgetView) => {
// replace the dummy widget with the new one.
const i = ArrayExt.firstIndexOf(this.luminoWidget.widgets, dummy);
this.luminoWidget.insertWidget(i, view.luminoWidget);
dummy.dispose();
return view;
})
.catch(reject('Could not add child view to fieldset', true));
}

remove(): void {
this.children_views = null;
super.remove();
}

children_views: ViewList<DOMWidgetView> | null;
luminoWidget: JupyterLuminoPanelWidget;

static class_map = {
success: ['alert', 'alert-success'],
info: ['alert', 'alert-info'],
warning: ['alert', 'alert-warning'],
danger: ['alert', 'alert-danger'],
};
}
41 changes: 36 additions & 5 deletions python/ipywidgets/ipywidgets/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,53 @@
from .widget_bool import Checkbox, ToggleButton, Valid
from .widget_button import Button, ButtonStyle
from .widget_box import Box, HBox, VBox, GridBox
from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgress, FloatRangeSlider, FloatLogSlider
from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress, IntRangeSlider, Play, SliderStyle
from .widget_float import (
FloatText,
BoundedFloatText,
FloatSlider,
FloatProgress,
FloatRangeSlider,
FloatLogSlider,
)
from .widget_int import (
IntText,
BoundedIntText,
IntSlider,
IntProgress,
IntRangeSlider,
Play,
SliderStyle,
)
from .widget_color import ColorPicker
from .widget_date import DatePicker
from .widget_datetime import DatetimePicker, NaiveDatetimePicker
from .widget_time import TimePicker
from .widget_output import Output
from .widget_selection import RadioButtons, ToggleButtons, ToggleButtonsStyle, Dropdown, Select, SelectionSlider, SelectMultiple, SelectionRangeSlider
from .widget_selectioncontainer import Tab, Accordion, Stack
from .widget_selection import (
RadioButtons,
ToggleButtons,
ToggleButtonsStyle,
Dropdown,
Select,
SelectionSlider,
SelectMultiple,
SelectionRangeSlider,
)
from .....branches.widget_selectioncontainer import Tab, Accordion, Stack
from .widget_string import HTML, HTMLMath, Label, Text, Textarea, Password, Combobox
from .widget_controller import Controller
from .interaction import interact, interactive, fixed, interact_manual, interactive_output
from .interaction import (
interact,
interactive,
fixed,
interact_manual,
interactive_output,
)
from .widget_link import jslink, jsdlink
from .widget_layout import Layout
from .widget_media import Image, Video, Audio
from .widget_tagsinput import TagsInput, ColorsInput, FloatsInput, IntsInput
from .widget_style import Style
from .widget_templates import TwoByTwoLayout, AppLayout, GridspecLayout
from .widget_upload import FileUpload
from .widget_fieldset import Fieldset
68 changes: 68 additions & 0 deletions python/ipywidgets/ipywidgets/widgets/widget_fieldset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

"""Fieldset widget.
This widget is used to group other control widgets into a fieldset.
"""

from .widget import register, widget_serialization, Widget
from .domwidget import DOMWidget
from .widget_core import CoreWidget
from .docutils import doc_subst
from .trait_types import TypedTuple
from traitlets import Unicode, CaselessStrEnum, Instance


_doc_snippets = {}
_doc_snippets[
"box_params"
] = """
children: iterable of Widget instances
list of widgets to display
box_style: str
one of 'success', 'info', 'warning' or 'danger', or ''.
Applies a predefined style to the box. Defaults to '',
which applies no pre-defined style.
"""


@register
@doc_subst(_doc_snippets)
class Fieldset(DOMWidget, CoreWidget):
"""Displays controls grouped together, optionally with a caption.
The widgets are laid out horizontally.
Parameters
----------
{box_params}
Examples
--------
>>> import ipywidgets as widgets
>>> slider = widgets.IntSlider()
>>> widgets.Fieldset(legend="Fieldset Example", children=[slider])
"""

_model_name = Unicode("FieldsetModel").tag(sync=True)
_view_name = Unicode("FieldsetView").tag(sync=True)

# Child widgets in the container.
# Using a tuple here to force reassignment to update the list.
# When a proper notifying-list trait exists, use that instead.
children = TypedTuple(trait=Instance(Widget), help="List of widget children").tag(
sync=True, **widget_serialization
)

box_style = CaselessStrEnum(
values=["success", "info", "warning", "danger", ""],
default_value="",
help="""Use a predefined styling for the box.""",
).tag(sync=True)

def __init__(self, legend="", children=(), **kwargs):
kwargs["legend"] = legend
kwargs["children"] = children
super().__init__(**kwargs)
Loading