material-components / material-components-web

Modular and customizable Material Design UI components for the web
https://material.io/develop/web
MIT License
17.13k stars 2.15k forks source link

Hard to use compoenents #5143

Closed BSarmady closed 4 years ago

BSarmady commented 4 years ago

A few years back when these components just started, I requested a feature to add compiled versions without any compile requirement from users. This is still not happened.

The way these components are published is like you go buy a can of soup from supermarket and they give you a can of water and instruction saying

We assume you know where to buy your vegetables and chicken and beans and know how to cook them so we provide you a can of water so you can cook them. If you like to cook them in pressure cooker here is the recipe, if you like to cook it in rice cooker use this recipe!

Notice the issue? There is no recipe for cooking in normal soup pan, you need to buy chicken, clean it, cut it, buy vegetables, clean it, wash it, chop it and then cook them all yourself!

If you look at jQuery UI components, you can select version, tick the components you need and download it, usage is as easy as adding a CSS and a JS to your page and the rest is your pure knowledge of CSS, JS, JQuery and JQuery UI components themselves.

With current state of your components, a user (developer) need to know how to use npm, nodejs, webpack and many other tools so the can just compile the components. And this is just the start, you still need to figure out how to put that component in your page. You have covered advanced uses of your components in angular and react. But there is no mention of how to use them with simple pure JavaScript on an HTML page?

I am using these components on one project since last year, and guess what, I couldn't build the package due to compile errors and gave up. Instead downloaded the JS and CSS from your demo pages.

Just a note, a developer working in mission critical and high security industry such as finance, insurance, health or an enterprise, can't just install whatever tools they like, they might be on intranet with no Internet access on all the stations. You can't use CDN as source of your components (Referer headers security).

In an Industry that customers only have basic knowledge of computer, you can't just support last 2 versions of the browser. I still have customers that use Firefox 36 on windows XP. I'm not expecting you to support past 20 version of the browser, that is my job. IMHO, it is lazy to test just for last 2 version of browsers (which makes it like 10 browsers?) I think a component should work on at least latest + LTS versions or alternatively older components should be available for download too, in case support for older browsers are needed.

As others also mentioned, because you need to learn how compile these components too, using them becomes troublesome and learning curve too steep. I rather use bootstrap and jQuery UI instead even though I like to use Material.IO very much.

I appreciate if you could add compiled versions of your code for download (simply a JS and CSS) too. and clear working sample that doesn't require me to open source of pages and track what is running and how is running.

MrSimmmons commented 4 years ago

What i have done is just copied the CSS and JS CDN code into a local file and just named them material.css and material.js respectively. Having fully compiled components just sitting in the repo it kind of not needed. If you really want to have more modularity with the components in your final compiled file instead of doing the CDN way above, then you can just run a quick development instance of the repo, pick out the components that you want and save the compiled file into whatever project you want.

BSarmady commented 4 years ago

Thank you for reply and apologize for long comment before hand.

That is what I did, I have a local copy of the material-components-web.min.css and material-components-web.min.js but I still haven't achieve anything.

lets say I want to put a drawer in my page. For the sake of argument, lets say it is a pure javascript page which doesn't use any frameworks (well it still does use jQuery, vue and a few others)

I look at web catalog and like the look of Modal Drawer and want to use that. No source code is available in that page, and I can't right click and view source to see how you did it, because demo is react application and minified too. I'll try to find that information links provided under Resources,

Now I follow the documentation word by word.

npm install @material/drawer

Don't need this one, I believe the script is already included in the version that I have downloaded from CDN. And anyway, my pure javascript page doesn't use node or npm

Icons

Sure I'll add following to head of my page

<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

Styles

Isn't that already included in the material-components-web.min.css downloaded from CDN?

JavaScript Instantiation

The one I want is other variants, so I add following lines to my HTML page. and because you didn't use document.ready I put the script at the bottom of the page to make sure all elements are loaded.

<script>
import {MDCDrawer} from "@material/drawer";
const drawer = MDCDrawer.attachTo(document.querySelector('.mdc-drawer'));
</script>

variants

Now from under variants section I go and copy the HTML code under Modal Drawer section to my HTML page. rest of the document is about customization. There was a Javascript to allow clicking on the hamburger icon to activate or deactivate the drawer which is under Dismissible Drawer I think I'm gonna need that too even though that script is under different section.

Now my HTML looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <link rel="stylesheet" href="fonts/MaterialIcons.css">
    <title>Material Components Web | Catalog</title>
    <link type="text/css" rel="stylesheet" href="material-components-web.min.css">
    <script type="text/javascript" src="material-components-web.min.js"></script>
</head>
<body class="mdc-typography">
    <aside class="mdc-drawer mdc-drawer--modal">
        <div class="mdc-drawer__content">
            <nav class="mdc-list">
                <a class="mdc-list-item mdc-list-item--activated" href="#" aria-current="page">
                    <i class="material-icons mdc-list-item__graphic" aria-hidden="true">inbox</i>
                    <span class="mdc-list-item__text">Inbox</span>
                </a>
                <a class="mdc-list-item" href="#">
                    <i class="material-icons mdc-list-item__graphic" aria-hidden="true">send</i>
                    <span class="mdc-list-item__text">Outgoing</span>
                </a>
                <a class="mdc-list-item" href="#">
                    <i class="material-icons mdc-list-item__graphic" aria-hidden="true">drafts</i>
                    <span class="mdc-list-item__text">Drafts</span>
                </a>
            </nav>
        </div>
    </aside>

    <div class="mdc-drawer-scrim"></div>
    <div>Main Content</div>
    <script>
        import {MDCList} from "@material/list";
        const list = MDCList.attachTo(document.querySelector('.mdc-list'));
        list.wrapFocus = true;

        import {MDCDrawer} from "@material/drawer";
        const drawer = MDCDrawer.attachTo(document.querySelector('.mdc-drawer'));

        import {MDCTopAppBar} from "@material/top-app-bar";
        const topAppBar = MDCTopAppBar.attachTo(document.getElementById('app-bar'));
        topAppBar.setScrollTarget(document.getElementById('main-content'));
        topAppBar.listen('MDCTopAppBar:nav', () => {
            drawer.open = !drawer.open;
        });
    </script>
</body>
</html>

This page is in my Apache and browsing with Firefox, and .... Nothing on screen! Checking the javascript console:

SyntaxError: import declarations may only appear at top level of a module

Hmmm! ok! I'll add type="module" to script tag and refresh the page, no error this time but still nothing!

Screenshot of what I see running this

This is what I meant when I said, These components are hard to use.

Now let me give you an example of JQueryUI, but this time with no director commentary. Also there is no drawer in jQueryUI so I'm go with Modal Dialog instead.

Go to demo page for dialog, click on view source link below demo frame and copy the whole HTML to your file and browse it (of course from a Web Server) and it already works. and next is just mater of customizing the dialog.

If you inspect the code you'll see that all you need to create the dialog is a DIV to put dialog content in, then call the dialog function ($( "#dlgDiv" ).dialog();) on it. All the styles will be added by JavaScript. I can also pass options to dialog function like $( "#dlgDiv" ).dialog({option1:'somevalue'});

<div id="dlgDiv" title="Basic dialog">
  <p>This is the default dialog which is useful for displaying information.</p>
</div>
<script>
    $("#dlgDiv").dialog();
</script>

In an ideal case for Material components I should have something like this to show the drawer and then call a Javascript function like following to make it operational

<aside id="modal-drawer">
    <div>
        <nav>
        <ul>
            <li data-icon="inbox" data-link="Inbox">text</li>
            ...
        </ul>  
            ...
        </nav>
    </div>
</aside>
<script type="module">
    const drawer = MDCDrawer.attachTo(document.querySelector('#modal-drawer'));
</script>

or even better if those functions are prefixed like jquery, for example:

<script type="module">
    const drawer = MDC.Drawer(document.querySelector('#modal-drawer'));
</script>
MrSimmmons commented 4 years ago

I fully agree that these component are hard to use. If you don't go though the 'normal' dev environment then it takes a bit of set up. It took me like 2 months to properly figure out what I was doing using the CDN version. If you are looking for working drawer code, this is code that I'm using on one of my apps:

const drawer = mdc.drawer.MDCDrawer.attachTo(document.querySelector('.mdc-drawer'));
const topAppBar = mdc.topAppBar.MDCTopAppBar.attachTo(document.getElementById('app-bar'));

topAppBar.setScrollTarget(document.getElementById('main-content'));
topAppBar.listen('MDCTopAppBar:nav', ()=> {
    drawer.open = !drawer.open;
});

If you are going to continue using the CDN version (or the local copied code), then you need to define a variable by going:

const newBtn = mdc.button.MDCButton.attachTo(document.querySelector('.newBtn'));

As is shown in the quick start guide on the main README.md page at the top.

(And no I don't believe that the icons are included as that is maintained by a separate part of google. Not 100% sure about that though)

BSarmady commented 4 years ago

CyborgSemon, thank you for the example.

I'm sure icons are not included in CDN, but styles are.

So from my understanding, if I'm using a components, I will need to call them like mdc.[compoent name in lowercase].MDC[Component name in Camel case].

There are few questions

[EDIT] removed the last question, it was my mistake. latest version does work with Firefox 54 and above.

MrSimmmons commented 4 years ago

In order of your questions:

  1. Yes you do.

  2. No you don't have to make it a constant, or even a variable. You can just call the .attachTo() method to an element and leave it at that. It is just recommenced that you save the attached component to a variable because if you don't, I don't believe you can re-select the component version of the element. (I might be wrong here. But you should just save it as a variable anyway if you plan on using any of the methods / values later.)

  3. You should check out the importing JS documentation. The CDN version imports the JS slightly differently compared to going through the 'normal' dev environment. The way that the docs suggest that you set up the variables for the CDN way is to do it like this.

    const MDCButton = mdc.button.MDCButton;

    That way you then don't have to type out the mdc.button.MDCButton all the time. You can then just do this:

    const newBtn = MDCButton.attachTo(document.querySelector('#newBtn'));
  4. It should be working? You can check the version of the CDN by the url. The supplied one should say @latest somewhere in the URL, that will then change to the version number when you visit the link in your browser. So for example, currently if you were to visit the link it would replace latest with @3.2.0

Hope this helps :)

kurai021 commented 4 years ago

I have tried to use these components because I thought they were much more complete than others like Materialize. But something as trivial as placing grids inside a container and expecting them to be centered without occupying the entire viewport is impossible even though the same documentation uses components that do things like these but are not included in the final package.

the only thing left of this painful experience with packages that you must compile yourself is that I learned Babelify in the painful way ... so thank you?

MrSimmmons commented 4 years ago

@kurai021

But something as trivial as placing grids inside a container and expecting them to be centered without occupying the entire viewport is impossible

Can you provide a codepen example? Because I think I've done exactly what you have described here in a project of mine.

the only thing left of this painful experience with packages that you must compile yourself is that I learned Babelify in the painful way ... so thank you?

Then just use the CDN? It's not that hard to just set up a compiling environment using the getting started guide.

asyncLiz commented 4 years ago

Thanks for your feedback! If you haven't already, I'd also suggest taking a look at Material web components. Our hope is that this will be an easier way to consume Material on the web and address these concerns.