Skip to content

Instantly share code, notes, and snippets.

@joelcoxokc
Created January 11, 2014 07:07
Show Gist options
  • Save joelcoxokc/8367994 to your computer and use it in GitHub Desktop.
Save joelcoxokc/8367994 to your computer and use it in GitHub Desktop.
From http://localhost/repos/trackcom/public/umessages
@joelcoxokc
Copy link
Author

@Class ScreenSize

This is a Javascript MediaQuery Helper

Here is Sass Variables and mixin to go with the Class

// ---- BREAKPOINTS -------------------------------------->
$breakpoint-xs: 0;
$breakpoint-sm: 34em;
$breakpoint-md: 48em;
$breakpoint-lg: 62em;
$breakpoint-xl: 75em;

$breakpoints: (
  xs: $breakpoint-xs,
  sm: $breakpoint-sm,
  md: $breakpoint-md,
  lg: $breakpoint-lg,
  xl: $breakpoint-xl,
) !default;

@mixin breakpoint($label:xs) {
  $media: map-get($breakpoints, $label);
  @media (min-width:$media) {
    @content;
  }
}

@each $label, $query in $breakpoints {
  @include breakpoint($label) {
     // Do something on each breakpoint
  }
}

@include breakpoint(md) {
  // DO something on medium screen
}

@method onChange

Example Return value


   /**
    * @Prototype(): onChange
    * @return {Object} Query
    */
   Query = {
     media: {Object} {max: "47em" min: "34em" name: "sm"}
     screen: {Object} window.Screen
   };

Example Usage

  /**
   * @Prototype(): onChange
   * @usage
   */
  class MyViewModel {
    static inject = [ScreenSize];
    constructor(screenSize){

      screenSize.onChange(query => {
        // Do something with the Query
      })
    }
  }

@method from | to | fromTo

Exactly what you would expect. Simply pass the Query Name as Parameters.
Returns Value{Boolean} on whether the screen is the specified size or not.

  /**
   * @Prototype():  from | to | fromTo
   * @params {String} [xs | sm | md | lg | xl]
   * @usage;
   */
  class MyViewModel {
    static inject = [ScreenSize];
    constructor(screenSize){
      if (screenSize.from('md')) {
        // Do something when Screen Size is larger than 'md';
      }

      if (ScreenSize.to('md')) {
       // Do something when Screen Size smaller than 'md'; 
      }

      if (ScreenSize.fromTo('sm', 'md')) {
       // Do something when Screen Size is between medium or small;
      }
    }
  }
/**
 * @class ScreenSize
 */
export class ScreenSize {

  queries = [
    {name: 'xs', min: '0px', max: '33em'},
    {name: 'sm', min: '34em', max: '47em'},
    {name: 'md', min: '48em', max: '61em'},
    {name: 'lg', min: '62em', max: '74em'},
    {name: 'xl', min: '75em', max: '1000em'}
  ];
  indexOF = {xs: 0, sm: 1, md: 2, lg: 3, xl: 4};
  screen = {};
  eventListeners = [];
  constructor(channel) {
    this.currentScreen = this.checkSize();
  }

  onChange(cb) {
    this.eventListeners.push(cb);
    if (!this.listener) {
      this.createListener();
    }
  }

  checkSize() {
    let current = this.currentScreen;
    for (let q in this.queries) {
      if (this.queries[q + 1]) {
        this.screen[q] = this.fromTo(this.queries[q].name, this.queries[q + 1].name);
      } else {
        this.screen[q] = this.from(this.queries[q].name);
      }
      if (this.screen[q]) {
        current = q;
      }
    }

    if (current !== this.currentScreen) {
      this.currentScreen = current;
      return this.currentScreen;
    }
    return false;
  }

  createQuery(min, max) {
    let query = '';
    if (min) {
      let minIndex = this.indexOF[min];
      min = this.queries[minIndex].min;
      query += `(min-width: ${min})`;
    }
    query = max ? (query + ' and ') : query;

    if (max) {
      let maxIndex = this.indexOF[max];
      maxIndex = maxIndex - 1;

      max = this.queries[maxIndex].max;
      query += `(max-width: ${max})`;
    }
    return query;
  }

  from(min) {
    let match = window.matchMedia(this.createQuery(min));
    return match && match.matches;
  }

  to(max) {
    let match = window.matchMedia(this.createQuery(null, max));
    return match && match.matches;
  }

  fromTo(min, max) {
    let match = window.matchMedia(this.createQuery(min, max));
    return match && match.matches;
  }

  createListener() {
    let self = this;
    window.addEventListener('resize', debounce(update, 200));

    function update() {
      let current = self.checkSize();
      if (current) {
        let media = self.queries[current];
        let screen = window.screen;
        self.eventListeners.forEach(cb => cb({media, screen}));
      }
    }
  }
}

function debounce(func, wait, immediate) {
  let timeout;
  return function() {
    let context = this;
    let args = arguments;
    let later = function() {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    let callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

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