Git Product home page Git Product logo

patternfly-yew's Introduction

PatternFly components for Yew

crates.io docs.rs Matrix

Yew components, based on PatternFly:

PatternFly is an open source design system built to drive consistency and unify teams.

Yew is a framework for creating reliable and efficient web applications.

Screenshot of an example


Getting started

Take a look at the demo, which shows various features of the project: https://patternfly-yew.github.io/patternfly-yew-quickstart

The code of the demo is also intended to be a quickstart/template project, to get you started with just a few commands: https://github.com/patternfly-yew/patternfly-yew-quickstart

patternfly-yew's People

Contributors

adogcalledspot avatar antifuchs avatar carlosthe19916 avatar ctron avatar deathbreakfast avatar jbtrystram avatar koa avatar marcopio72 avatar phill-85 avatar pmsanford avatar rick-gnous avatar uzytkownik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

patternfly-yew's Issues

Release 0.5.0

Tracking issue for ToDo's before a 0.5.0 release … and I come up empty.

So time to speak up now!

Callback/event handler signatures

Currently callbacks carry the actual information, but not the original event. Like:

onchange: Callback<bool>

PR #86 added the event information to that:

onchange: Callback<(Event, bool)>

The led to a number of quite verbose callback definitions:

let cb = Callback::from(|(_, state) : (Event, CheckboxState)| {}) 

I think we need a better way. Let's gather ideas.

Is it possible to modify the Toast position?

I want to show the toasts at the bottom right corner. Is it possible?

match result {
          Ok(_) => {
            toaster.toast(Toast {
              title: "Success".into(),
              body: "Exercise created".into(),
              timeout: Some(Duration::from_millis(2000)),
              ..Default::default()
            });

            navigator.back()
          }
          Err(_) => {
            toaster.toast(Toast {
              title: "Error".into(),
              body: "All of fields are necessary".into(),
              timeout: Some(Duration::from_millis(2000)),
              r#type: patternfly_yew::Type::Danger,
              ..Default::default()
            });
          }
        }

`Pagination` Component `navigation_callback` does not allow navigation to next/last/previous/page(x)

...
 // let onset_per_page =
    let limit_callback ={
        use_callback(move |number, limit|{
            limit.set(number)
        }, limit.clone())
    };

    let nav = use_state(|| Navigation::First);
    let nav_callback = {
        use_callback(move |_page: Navigation, nav|{
            gloo::console::log!("clicked next page");
            nav.set(Navigation::Page(2));
        }, nav.clone())
    };
    html!{
        <div>
            <Pagination
                total_entries={Some(raw_elemets.len() as u32)}
                offset={offset.deref()}
                entries_per_page_choices={vec![5, 10, 25,50,100]}
                selected_choice={*limit.deref()}
                limit_callback={limit_callback}
                navigation_callback={nav_callback}
                    />
            <Table<SharedTableModel<NumbersTable>>
                header={table_headers}
                entries={entries}
                mode={TableMode::Compact}/>
        </div>
    }
}

so I would click the arrows to indicate the next page but I wouldn't go to the next page

image

[Discussion] New Table implementation

The current Table implementation is convenient but limiting in a few ways. I would like to discuss expectations we have for a more ergonomic/powerful implementation so we can gather requirements and see how it works.

I think the biggest issue is that Table only gives control at the level of an entire Vec of entries. There is a lot happening at the level of individual rows so for me it would make sense to move the abstraction to the row level.

I could imagine an interface similar to the following:

enum Columns {
    First,
    Second,
    Third,
}

struct Entry {
    id: String,
} 

#[function_component(MyTable)]
fn table() -> Html {
    let entries = use_memo((), |_| get_entries());
    let header = html_nested!(<TableHeader<Columns>> ...); // same as before
    html! {
        <Table<Columns> {header}>
            <TableBody>
                {
                    for entries.iter().map(|entry| {
                         html!(<MyRow key={entry.id.clone()} entry={entry.clone()}/>)
                    }
                }
            </TableBody>
        </Table<Columns>>
    }
}

#[derive(Debug, Clone, PartialEq, Properties)]
struct MyRowProperties {
    entry: Entry,
}

#[function_component(MyRow)]
fn row(props: &MyRowProperties) -> Html {
    let count = use_state(|| 0);
    let onclick = use_callback(count.clone(), |_, count| count.set((*count) + 1));
    let render_cell = use_callback(
        (count.clone(), onclick.clone(), props.entry.clone()),
        |col, (count, onclick, entry)| {
            match col {
                Columns::First => html!({entry.id.clone()}),
                Columns::Second => html!({*count}),
                Columns::Third => html!(<Button label="Increment" {onclick} />),
            }
        }
     );
     let expand_content = use_memo((), |_| html!({"foo"}));
     let onrowexpand = use_callback(expand_content.clone(), |_, expand_content| (*expand_content).clone());
     // Similar callback for oncolumnexpand that matches by column and returns OptionalHtml
     
     // Callback for onrowclick
     // Selected is just a prop
     html! {
         <TableRow<Columns> {render_cell} {onrowexpand} />
     }
}

Drawbacks

  • No way to enforce that a TableRow<Column> is used within the TableBody. Trying to use any sort of ChildrenWithProps would be much too painful if the goal is to let users have state within the row.
  • This still may not be sufficient for every use case but I think it's fine to let ComposableTable handle those cases

Rethink keys in tables

TableModel has a generic Key type that can be used for supplying better keys but MemoizedTableModel and UseStateTableModel simply assign usize and use the index in the entry vector.

This causes issues for when the data changes as the indices don't match the data anymore.
One example is if you render a cell with state inside, the state will actually be cached from the entry that was previously in that position leading to some surprising behaviour.

Since keys should really always be used for lists, I would propose letting the user assign keys and I've come up with two options that would work.

Option 1: Get the key from a Option<Callback<EntryType, KeyType>>

which is called on every row. If no callback is specified, then we can fall back to using the index.
The good thing about this approach is that it wouldn't even be a breaking change.

Option 2: Get the key from a function in TableEntryRenderer

This would be a breaking change but it would force users to come up with proper keys and is a lot nicer to read in the code.

Selectable cards always select the first one

I'm not sure if I'm forgetting a property somewhere or if it's really not working, but I can't make selectable Cards working.
The simplest example I can reproduce is:

use {patternfly_yew::prelude::*, yew::prelude::*};

#[function_component(App)]
fn app() -> Html {
    html! {
        <>
            <Card title={html!{"1"}} selectable=true>
                <CardBody>
                    {"card 1"}
                </CardBody>
            </ Card>
            <Card title={html!{"2"}}  selectable=true>
                <CardBody>
                {"card 2"}
                </CardBody>
            </ Card>
            <Card title={html!{"3"}}  selectable=true>
                <CardBody>
                {"card 3"}
                </CardBody>
            </ Card>
        </>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}

Clicking on any card always toggle the first one.

[discussion] More advanced icon support

patternfly-react uses svg-based icons whereas we use font-based icons. This causes some differences in behavior.

patternfly-react's svg images have a fixed width and height of 1em (link). Our fonts have variable widths between characters so lists of icons don't appear as uniform.

Example - dual list selector

no width set:
image

The single angle brackets at the top and bottom aren't aligned because they have a width of 46px whereas the double angle brackets have a width of 48px

width of all icons set to 1em using debugger:
image

The icons all have the exact same width causing the single angle bracket to be nicely centered.

Questions

  • What are the advantages to having icons that aren't fixed width?
  • If we decide to provide fixed width icons would we:
    • fix the width of the <i> by adding style props?
    • or rather use fixed width fa characters?
  • Do we want to offer support for svg-based icons?

Related: #53

I am not able to pass the iterator to Select's children

I am getting the error "the trait From<VNode> is not implemented for SelectChildVariant<std::string::String>" when I try to do the following: What could I be missing?

image

#[function_component(AddItem)]
pub fn _view() -> Html{
    let brand_vec = vec!["Nike".to_string(), "Puma".to_string(), "Sonny".to_string(), "Adidas".to_string()];
    let nike = &brand_vec[0];
    let puma = &brand_vec[1];
    let adidas = &brand_vec[3];

    let options = brand_vec.iter().map(|brand| {
        let brand = brand.clone();
        html!{
            <select class="form-control">
                <option value="{&brand}">{brand}</option>
            </select>
        }
    }).collect::<Html>();

    html!{
        <>
            <div>
                <Select<String>  placeholder="Select Brand">
                    // <SelectOption<String> value={nike.clone()} />
                    // <SelectOption<String> value={puma.clone()} />
                    // <SelectOption<String> value={adidas.clone()} />
                    {options}
                </Select<String>>
            </div>
        </>
    }
}

Upgrade to PatternFly 5

There is a new, upcoming, major release of PatternFly called v5.

I think right now it is too early to migrate, but we should track it and be ready for it at some point.


The question is on how to go forward. There are a few upcoming (next) breaking things in the main branch. And I do believe that migrating to PatternFly 5 would mean a breaking version change.

So my proposal would be the keep the current main (with the "next" stuff) and merge this all into main (without next stuff), migrating to PF5 in the process. Releasing this as 0.5 once it's ready. Keeping 0.4 around for PF4, but focusing on PF5 from then on.

Hover effects for clickable Cards

You can currently create a click callback on cards with the onclick prop. However, it isn't communicated to the user. The Patternfly docs show that the cards are dimmed when hovering them and that the cursor becomes a pointer.

I tried adding pf-m-clickable to the classes but that doesn't seem to do anything by itself.

Am using pf-m-selectable-raised as a workaround for now.

`Select` component: `SubmitEvent` triggered instead of `OnSelect` for ` <Select<String> ... variant={SelectVariant::Multiple(onchange_category)}>...`

...
    let onchange_category = {
        let state = state.clone();
        use_callback(move|category: Vec<String>, state|{
            gloo::console::log!(category.clone().join(","));
            let mut data = state.deref().clone();
            data.categories = category.join(",");
            state.set(data)
        }, state)
    };
    
   html!{
....
                <FormSection>
                    <FormGroup label="Select Categories">
                        <Select<String> chip={ChipVariant::Values} variant={SelectVariant::Multiple(onchange_category)}>
                                {
                                    for categories_vec.iter().map(|category|{
                                        html_nested!{<SelectOption<String> value={category.to_string()}/>}
                                    })
                                }
                        </Select<String>>
                    </FormGroup>
                    ....
}
Screencast.from.06-26-2023.12.38.47.PM.webm

As you can see every time, an item is selected, it is treated as SubmitEvent and a request will be sent to the backend.

Info: Implemented components

[ Please note, this is an information issue only, not a real roadmap ]

This is based on components only (no charts, and other patternfly features):

  • About modal
  • Accordion
  • Action list
  • Alert
  • Avatar
  • Back to top
  • Backdrop
  • Background image
  • Badge
  • Banner
  • Brand
  • Breadcrumb
  • Button
  • Card
  • Chip
  • Clipboard copy
  • Code block
  • Code editor
  • Data list
  • Date and time
    • Calendar month
    • Date and time picker
    • Date picker
    • Time picker
  • Description list
  • Divider
  • Drag and drop
  • Drawer
  • Dual list selector
  • Empty state
  • Expandable section
  • File upload
    • Multiple file upload
    • Simple file upload
  • Forms
    • Checkbox
    • Form
    • Form control
    • Form select
    • Radio
    • Text area
    • Text input
  • Helper text
  • Hint
  • Icon
  • Inline edit
  • Input group
  • Jump links
  • Label
  • List
  • Login page
  • Masthead
  • Menus
    • Custom menus
    • Dropdown
    • Menu
    • Menu toggle
    • Select
  • Modal
  • Navigation
  • Notification badge
  • Notification drawer
  • Number input
  • Overflow menu
  • Page
  • Pagination
  • Panel
  • Password generator
  • Password strength
  • Popover
  • Progress
  • Progress stepper
  • Search input
  • Sidebar
  • Simple list
  • Skeleton
  • Skip to content
  • Slider
  • Spinner
  • Switch
  • Tab content
  • Table
  • Tabs
  • Text
  • Text input group
  • Tile
  • Timestamp
  • Title
  • Toggle group
  • Toolbar
  • Tooltip
  • Tree view
  • Truncate
  • Wizard

PF5 Component Review

This issue is for tracking the upgrade to PF5.

Components:

  • about
  • alert
  • app_launcher
  • avatar
  • backdrop
  • background - This has changed quite abit, not sure what to do here
  • badge
  • brand
  • breadcrumb - done, but #51
  • button
  • card
  • chip
    Done, but:
    - PFY allows icon to be set PF only allows icon for drag & drop
    - Badge component in chip cannot be set to unread. Consider supplying Badge component as Attr, or including as child elemet (As PFReact does)
  • chip_group
  • clipboard
  • code_block
  • content - Should rename to Text
  • context_selector
  • divider
  • dl
  • dropdown - there seems to be a descrepency between the html version and the react version. The react decreciated version appears to be more similar.
  • empty - title markup needs looking at.
  • expandable_section - pf-m-limit-width not supported.
  • file_upload
  • form - in progress. Done: TextArea, TextInput, Section, select -- Form Helper text could be refactored to use the Helper text component underneath
  • helper_text
  • hint
  • input_group
  • label
  • list
  • login_page
  • modal
  • nav
  • page
    • this has been rewritten in pf5 with the old implementation deprecated. Done a quick rewrite, to use current html/css
    • pf5 react treats each variant as a separate component.
  • pagination
  • panel
  • popover
  • select - toggle button doesn't include pf-v5-c-button in example source, but we use the Button component which does.
  • slider
  • spinner
  • switch
  • table - issue with icon positioning when expanding
  • tabs
  • text - Depreciated, replace with content component
  • text_input_group
  • title
  • toast
  • toolbar
  • tooltip
  • tree - disabled due to incompatibility with next::Table component - e2e3d3a

Layouts:

  • bulseye
  • flex - Flex item does not support all modifiers (in the flex modifiers) that flex does
  • gallery
  • grid
  • split
  • stack

Misc:

  • Icons - Some missing. Need input on PF5 icons

AB Comparison:

  • Before and after compared for all existing examples
  • New samples should be created

[Discussion] `data-test` property on components

For end-to-end testing, there needs to be a good way to select a component. I think the best way to do this would be to add a data-test property to components.

This means in particular that in components that use composition, there should be meaningful names given to the data-test attribute.

Page Masthead and horizontal navigation

I would have liked a horizontal navigation page as described in Patternfly but I see that I can't eliminate the bars button.
From what I could see in the code there is no way to do this with the Page component. Or is there a way?

Marco

Component id requirements

I have noticed several components using the aria-labelledby attribute.

The aria-labelledby property enables authors to reference other elements on the page to define an accessible name. - aria-labelledby - Accessibility | MDN

I see a lot of the following in the PF5 docs (in this case I made up an example):

<Component id="foo" aria-labelledby="foo-title">
    <div id="foo-title">Title</div>
    <p>Some content</p>
</Component>

It seems that the id for foo-title is derived from the id of the main component + title. The problem is that we seem to follow the HTML pattern that the id is optional, but if we follow this, and several instanced of the above component are created then we would end up with several elements with the same id for example <div id="-title"> this may cause accessibility issues.

As I see it we have two options here:

  1. Force the user to use an id
  2. Generate a random id if no id is supplied

My choice would be 2. We could create our own IdRequired type which implement a Default using something like Nano ID if an id is not provided.

Collapsing tree component inside a form crashes and reloads the page

I want to make a tree with checkboxes as part of a form. I used the tree code from the quickstart (no checkboxes for now) and realized that collapsing part of the tree briefly looks correct but then crashes. Moving the component outside of the form lets everything work correctly:

Example code:

#[function_component(AddChannelForm)]
pub fn add_channel() -> Html {
    html! {
        <Form>
            <FormGroup label="Name">
                <next::TextInput
                required=true/>
            </FormGroup>
            <FormGroup>
                <ComponentSelector/>
            </FormGroup>
            <ActionGroup>
                <Button variant={ButtonVariant::Primary} label="Submit" r#type={ButtonType::Submit}/>
            </ActionGroup>
        </Form>
    }
}

// !!!! This is just the tree example code from the quickstart
#[function_component(ComponentSelector)]
pub fn component_selector() -> Html {
    let header = html_nested! {
        <TreeTableHeader>
            <TableColumn label="foo" width={ColumnWidth::Percent(40)}/>
            <TableColumn label="L1" width={ColumnWidth::Percent(20)}/>
            <TableColumn label="L2" width={ColumnWidth::Percent(20)}/>
            <TableColumn label="L3" width={ColumnWidth::Percent(20)}/>
        </TreeTableHeader>
    };

    #[derive(PartialEq)]
    struct Root {
        root: Rc<Node>,
    }

    #[derive(PartialEq)]
    enum Node {
        Branch(Vec<String>, Vec<Rc<Node>>),
        Leaf(Vec<String>)
    }

    impl TreeTableModel for Root {
        fn children(&self) -> Vec<Rc<dyn TreeNode>> {
            self.root.children()
        }
    }

    impl TreeNode for Node {
        fn render_main(&self) -> Cell {
            match self {
                Self::Branch(name, _) => html!({name.join(" / ")}),
                Self::Leaf(name) => html!({name.join(" / ")}),
            }.into()
        }

        fn render_cell(&self, context: CellContext) -> Cell {
            let name = match self {
                Self::Branch(name, _) | Self::Leaf(name) => name,
            };

            // quick alternative to: match context.column { 0=> {}, … }
            name.get(context.column)
                .map(Html::from)
                .unwrap_or_default()
                .into()
        }

        fn children(&self) -> Vec<Rc<dyn TreeNode>> {
            match self {
                Self::Branch(_, children) => children.iter().map(|c|c.clone() as Rc<dyn TreeNode>).collect(),
                Self::Leaf(_) => vec![],
            }
        }
    }

    let mut root = vec![];
    for a in ["I", "II", "III"] {
        let mut folders = vec![];
        for b in [1,2,3] {
            let mut leaves = vec![];
            for c in ["a", "b", "c"] {
                leaves.push(Rc::new(Node::Leaf(vec![a.to_string(), b.to_string(), c.to_string()])));
            }
            folders.push(Rc::new(Node::Branch(vec![a.to_string(), b.to_string()], leaves)));
        }
        root.push(Rc::new(Node::Branch(vec![a.to_string()], folders)));
    }

    let root = Rc::new(Root {root: Rc::new(Node::Branch(vec![], root))});

    html!{
        <TreeTable<Root>
            mode={TreeTableMode::Compact}
            header={header}
            model={root}
        />
    }
}

If using a tree here isn't intended, then there should maybe be some trait bounds, so it isn't usable here.

Menu/MenuToggle doesn't close when clicking on toggle

Having a new (PF5/FC based) menu, it is currently not possible to close the menu by clicking again on the menu toggle.

The reason is that that this is an "outside" click, which should (and does) close the drop down content. However, the event
cannot be canceled, and so it also counts as a "toggle" action, which will then re-open the menu.

When closing chips in a select, the menu toggles

With a select component, clicking away chips with the X, makes the menu open and close.

The click event of the close button must not bubble up to the actual component (if handled by the click).

Components missing class

The only component that has a class / className prop is the Button. Would be helpful for additional classes.

I can throw up a PR for this tomorrow.

NavRouterItem not working with yew_nested_router

I can't figure out what I'm doing wrong, but the compiler keeps complaining about a not implemented trait (Target), when I thought I had indeed implemented it using the derive macro. I've also tried to replace the derive macro with the generated code (using cargo macro expand), but the issue is exactly the same.
I'm using

	yew = { version = "0.21", features = ["csr"] }
	yew-nested-router = "0.6.1"
	patternfly-yew = { version = "0.5.5" }

My minimum reproducible example is:

 use {
    patternfly_yew::prelude::*,
    yew::prelude::*,
    yew_nested_router::{Router, Switch as RouterSwitch, Target},
};

fn main() {
    yew::Renderer::<App>::new().render();
}

#[function_component(App)]
pub(crate) fn app() -> Html {
    html! {
        <Router<AppRoutes> default={AppRoutes::Home}>
            <Page
                sidebar={
                    html_nested! {
                        <PageSidebar>
                            <Nav>
                                <NavRouterItem<AppRoutes> to={AppRoutes::Home}>{"Home"}</NavRouterItem<AppRoutes>>
                            </Nav>
                        </PageSidebar>
                    }
                }
            >
                <RouterSwitch<AppRoutes> render={switch}/>
            </Page>
        </Router<AppRoutes>>
    }
}

#[derive(Debug, Default, Clone, PartialEq, Eq, Target)]
pub enum AppRoutes {
    #[default]
    Home,
}

pub(crate) fn switch(routes: AppRoutes) -> Html {
    match routes {
        AppRoutes::Home => {
            html! {<h1>{ "Home" }</h1>}
        }
    }
}

Any help would be greatly appreciated ! Thanks

autofocus=true focuses the field when other form fields are edited

I have a form component like the following:

#[function_component(FillBookmark)]
fn fill_bookmark() -> Html {
    let tags = use_state(|| vec![]);
    let title = use_state_eq(|| String::default());
    let set_title = use_callback(title.clone(), |new_title, title| title.set(new_title));
    let description = use_state_eq(|| String::default());
    let set_description = use_callback(description.clone(), |new_desc, desc| desc.set(new_desc));
    let notes = use_state_eq(|| String::default());
    let set_notes = use_callback(notes.clone(), |new_notes, notes| notes.set(new_notes));

    html! {
        <>
            <Form>
                <FormGroup required=true label="Title">
                    <TextInput
                        required=true
                        autofocus=true
                        onchange={set_title}
                        value={(*title).clone()}
                    />
                </FormGroup>
                <FormGroup label="Description">
                    <TextArea onchange={set_description} value={(*description).clone()} />
                </FormGroup>
                <FormGroup label="Notes">
                    <TextArea onchange={set_notes} value={(*notes).clone()} />
                </FormGroup>
            </Form>
        </>
    }
}

This results in a pretty form! But whenever I enter any character in the "description" or "notes" fields, the component gets re-rendered and input focus jumps back into the "title" field.

Is there a way to prevent this from happening, outside making a state value for autofocus that gets reset when any non-title value gets edited?

[Discussion] Specification of SearchInput advanced search attribute parsing

I'm working on the search input and have the key functionality down but need some feedback on how the advanced search should work.

There doesn't seem to be much specification. The component documentation merely states:

The values used in the attribute-value form fields may contain spaces. The values containing spaces should be wrapped with quotes inside the summary search string in the input field.

I checked the TS code and you can find it here.

It uses an undocumented regex and does some operations without really specifying what the aims are, or the limitations.

I've played around with it a bit and it exhibits the following behavior (the delimiter is variable in the component but I'm just using : here for now):

  1. foo bar => [foo, bar]
  2. "foo bar" => ["foo bar"]
  3. foo:bar => [(foo, bar)]
  4. foo:"bar baz" => [(foo, bar baz)]
  5. "foo bar":"a b" => [(foo bar, a b)]
  6. "foo:bar" => [(foo, bar)]
  7. All of the above with single quotes instead of double quotes

Thoughts:

  • The first four are clear and go without saying.
  • Number 5 has me questioning whether keys really need to have a space. It seems like a rather poor practice.
  • Number 6 is a bug in my opinion. There is no way to use the delimiter as a value otherwise.
  • Number 7 is simple enough to implement so I would just keep it.

If we have these rules it's pretty easy to build an iterator that just returns slices of the input string. No extra dependencies, no time for compiling a regex (and then either cache it or recompile everytime the input changes), no heap allocations, every character visited exactly once.

Let me know your thoughts

Constant ID updates

I think we have a problem with the generated IDs that we must fix.

2024-02-16.12-44-53.mp4

[Disucssion] handling the "middle" truncation option

Continuing from patternfly-yew/patternfly-yew-quickstart#36 (comment):

Looks good to me, it might be worth adding a comment in the docs saying that the truncate doesn't necessarily truncate num grapheme clusters but rather rounds down to the next unicode codepoint after num bytes.

I'm not sure if adding any extra complexity to the code is worth it though. At best you could maybe trim off num unicode codepoints by using s.char_indices().rev().nth(num) which will still look weird in a lot of cases and anything better than that will require an extra dependency. So a comment would probably be good, just so people aren't surprised that there are only 5 characters visible when they wanted to keep 10.

The Divider does not work correctly in lists or flex layouts

The following code:

<List r#type={ListType::Inline}>
    {"Using DividerType::Li"}
    <Divider r#type={DividerType::Li} orientation={DividerOrientation::Vertical.all()} />
    {"Creates a list item divider."}
</List>

Generates this html:

<ul class="pf-c-list pf-m-inline">
    <li>Using DividerType::Li</li>
    <li><li role="separator" class="pf-c-divider pf-m-vertical"></li></li>
    <li>Creates a list item divider.</li>
</ul>

FlexChild does not implement From
Using a version of this example https://patternfly-react-v5.surge.sh/components/divider#vertical-in-flex-layout-inset-at-various-breakpoints :

<Flex>
    <FlexItem>{"first item"}</FlexItem>
    <Divider orientation={DividerOrientation::Vertical.lg()}/>
    <FlexItem>{"second item"}</FlexItem>
</Flex>

Doesn't compile and gives this error!

error[E0277]: the trait bound `FlexChild: From<DividerProperties>` is not satisfied
  --> src/components/divider/mod.rs:33:14
   |
33 |             <Divider orientation={DividerOrientation::Vertical.lg()}/>
   |              ^^^^^^^ the trait `From<DividerProperties>` is not implemented for `FlexChild`

Dropdown menu doesn't close when clicking item

When clicking on the item of a dropdown menu the expectation is that the menu closes again. Currently it doesn't.

This is a regression coming from the PF5/Menu migration.

I think the proper solution is to:

  • Introduce a new MenuContext
  • Have some root-level/menu controlling component inject it
  • Giving any child component the ability to "request close" the menu

Get selected value(s) from a `select` component

I my not quite sure, but I don't see the ability to get a reference to a patternfly-yew::Select<K>
eg. there is no ref / r#ref or something similar to used with use_node() hook.

setup is something like:

#[derive(Debug, Clone, PartialEq)]
struct Foobar {
    id: u32,
    name: String,
}

impl Display for Foobar {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.name)
    }
}

#[function_component(Edit)]
pub fn edit(props: &Props) -> Html {
    let onsubmit ={
        Callback::from(move |e: SubmitEvent| {
          // get selected element
        }
    }
  }

  html! {
    <Form>
      <Select<Foobar>>
          ....
      </Select<Foobar>>
   </Form>
  }
}

how can I access the data from the Select component?

`UseStateHandle` created outside of a backdrop does not trigger a rerender inside the backdrop

I want to fetch data from the backend in a component. Pressing a button inside the component will open a backdrop which shows some more of the fetched data.

Ideally, I would like to have a UseStateHandle for the data, so I can check in the backdrop if all the data is already loaded.

However, once the data is there, it only reloads the data in the outside component (which you can sort of see in the background) and the component inside backdrop doesn't change.

Closing and reopening the backdrop view shows the correct data.

You can view a minimal example here.

error[E0277]: the trait bound `Bullseye: yew::Component` is not satisfied

= help: the trait yew::Component is implemented for ContextProvider<T>
= note: required for Bullseye to implement BaseComponent

use patternfly_yew::prelude::*;
use yew::prelude::*;

#[function_component]
fn App() -> Html {
    html! {
        <Bullseye>
            <div>{"Item #1"}</div>
        </Bullseye>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.