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

vendor specific pseudo selectors #69

Open
aronallen opened this issue Jan 11, 2017 · 9 comments
Open

vendor specific pseudo selectors #69

aronallen opened this issue Jan 11, 2017 · 9 comments

Comments

@aronallen
Copy link

We have run into an issue with vendor specific pseudo selectors.
We are trying to use ::placeholder which is vendor specific as detailed below.

::placeholder
::-webkit-input-placeholder
::-moz-placeholder
:-moz-placeholder
:-ms-placeholder

The problem is that an error is thrown if I attempt to set an incompatible pseudo-selector

@rtsao
Copy link
Member

rtsao commented Jan 11, 2017

Thanks for pointing this out! Yeah, for some reason insertRule throws here for unsupported invalid selectors (though not invalid declarations).

It appears that CSS feature queries (#21) won't solve this either (I think you can only target properties and values, not selectors).

I need to put some more thought into how best to solve this. The simple fix would be to simply wrap in try/catch, but this is going to be bad for performance.

@aronallen
Copy link
Author

An approach could be to try to insert all rules on boot, then cache the result, and remove the test styles. Not super elegant. But it could work.
I think styletron should accept '::placeholder' and automatically do the conversions.

@steida
Copy link

steida commented Jan 29, 2017

@unframework
Copy link

I ran into the same issue. My workaround so far has been to just "brute force" the prefix variations, silently ignore the failures and then just concatenate all the attempts' resulting class name strings.

One problem is that on the above parsing error the rules cache entry for the injection ends up still being set. So the subsequent attempts to inject the unprefixed selector actually succeed, but return a bogus class name that does not actually exist in the stylesheet. If subsequent calls also failed, it would make error handling easier and more consistent.

Great work on the library overall, by the way! 👍

@rtsao
Copy link
Member

rtsao commented Mar 2, 2017

I'll start working for this soon. I'd be happy to review PRs for this as well!

@aronallen
Copy link
Author

A solution could be to export the correct pseudo selector from the lib.

import { placeholder } from styletron

then you can just use that symbol in your js object.

{
  color: 'red',
  [placeholder] : {
    color: 'blue'
  }
}

@rtsao rtsao added the DX label Apr 12, 2017
@Lohann
Copy link

Lohann commented Oct 14, 2017

+1

@c58
Copy link

c58 commented Jan 11, 2018

const PSEUDOELEM_CHECK_CACHE = {};
const IS_BROWSER = typeof document !== 'undefined';


/**
 * Utility function to solve styletron issue with browser
 * specific pseudo elements. Right now it throws an error
 * if you will try to use like `::moz-placeholder` in Chrome.
 * This function check that the given pseudoelem name is valid,
 * and if it is valid it returns an object with given pseudoelem
 * with value. Otherwise returns empty object.
 *
 * @example
 * export const Input = styled('input', () => {
 *   const phStyles = {
 *     color: 'red'
 *   };
 *   return {
 *     ...safePseudoelem('::placeholder', phStyles),
 *     ...safePseudoelem('::-webkit-input-placeholder', phStyles),
 *     ...safePseudoelem('::-moz-placeholder', phStyles),
 *     ...safePseudoelem(':-ms-input-placeholder', phStyles)
 *   };
 * });
 * @param  {string} name  Pseudoelem name
 * @param  {object} value Pseudoelement value
 * @return {object}       Object `{ [name]: value }` if the element is valid
 *                        otherwise empty object.
 */
export const safePseudoelem = (name, value) => {
  if (IS_BROWSER && !(name in PSEUDOELEM_CHECK_CACHE)) {
    const style = document.createElement('style');
    document.head.appendChild(style);
    const sheet = style.sheet;
    try {
      sheet.insertRule(`${name}{}`, 0);
      PSEUDOELEM_CHECK_CACHE[name] = true;
    } catch (e) {
      PSEUDOELEM_CHECK_CACHE[name] = false;
    }
    document.head.removeChild(style);
  }

  if (!IS_BROWSER || PSEUDOELEM_CHECK_CACHE[name]) {
    return { [name]: value };
  }
  return {};
}

Here is a small utility function based on @steida solution that i'm using to solve the issue.

@c58
Copy link

c58 commented Apr 10, 2018

@rtsao is there any agreement how you are going to solve it? I can help with the implementation, but i need some green light on the approach that you @rtsao will agree with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants