npm package: @nrg-ui/ember-media
Description: An Ember addon for safe media query handling
Latest version: 0.2.1

# @nrg-ui/ember-media

An Ember addon for safe media query handling.

## Compatibility

- Ember.js v5.12 or above
- Embroider or ember-auto-import v2

## Installation

```sh
ember install @nrg-ui/ember-media
```

## Usage

### Breakpoints

There are 6 breakpoints available, with the following media queries:

| Breakpoint | Media Query                                   |
| ---------- | --------------------------------------------- |
| xsmall     | `(min-width: 0px) and (max-width: 575px)`     |
| small      | `(min-width: 576px) and (max-width: 767px)`   |
| medium     | `(min-width: 768px) and (max-width: 991px)`   |
| large      | `(min-width: 992px) and (max-width: 1199px)`  |
| xlarge     | `(min-width: 1200px) and (max-width: 1399px)` |
| xxlarge    | `(min-width: 1400px)`                         |

There is a corresponding property on the media service for each breakpoint, e.g. `isSmall`, `isMedium`, etc.

The queries can be adjusted via the Embroider build config, if needed:

```js
// ember-cli-build.js
module.exports = function (defaults) {
  let app = new EmberApp(defaults, {
    '@embroider/macros': {
      setConfig: {
        '@nrg-ui/ember-media': {
          breakpoints: {
            small: '(min-width: 600px) and (max-width: 799px)',
            // other breakpoints...
          },
        },
      },
    },
  });

  return app;
};
```

#### Accessing Custom Breakpoints

You can add arbitrary custom breakpoints via the Embroider build config:

```js
// ember-cli-build.js
module.exports = function (defaults) {
  let app = new EmberApp(defaults, {
    '@embroider/macros': {
      setConfig: {
        '@nrg-ui/ember-media': {
          breakpoints: {
            short: '(min-height: 0px) and (max-height: 320px)',
          },
        },
      },
    },
  });

  return app;
};
```

Custom breakpoints like `short` in the example above do not have convenience properties (i.e. there is no `media.isShort`). However, you can use the `media.matches` [`TrackedSet`](https://github.com/tracked-tools/tracked-built-ins) to access custom breakpoints:

```ts
export default class MyComponent extends Component {
  @service
  declare media: MediaService;

  get isShortScreen() {
    return this.media.matches.has('short');
  }
}
```

### Events

The media service emits a `change` event whenever the matched media queries change. You can listen for this event to react to changes in screen size.

```ts
export default class MyComponent extends Component {
  @service
  declare media: MediaService;

  constructor(owner: Owner, args: unknown) {
    super(owner, args);

    this.media.on('change', () => {
      console.log('Matched media queries:', Array.from(this.media.matches));
    });
  }
}
```

### Testing

When testing components or services that depend on the media service, you can use the provided test helpers to simulate different screen sizes.

```ts
import { setupRenderingTest } from 'ember-qunit';
import { module, test } from 'qunit';
import { setBreakpoint } from '@nrg-ui/ember-media/test-support';

module('Integration | Component | my-component', function (hooks) {
  setupRenderingTest(hooks);

  test('my test', async function (assert) {
    const service = this.owner.lookup('service:media');

    await setBreakpoint('small');
    // ...
  });
});
```

### Example

Inject the media service into your component, controller, or route:

```ts
import Component from '@glimmer/component';
import { service } from '@ember/service';

import type { Owner } from '@ember/owner';
import type MediaService from '@nrg-ui/ember-media/services/media';

export default class MyComponent extends Component {
  @service
  declare media: MediaService;

  constructor(owner: unknown, args: unknown) {
    super(owner, args);

    this.media.on('change', this.handleMediaChange);
  }

  onClick = () => {
    if (this.media.isLarge) {
      // Do something for large screens
    }
  };

  handleMediaChange = () => {
    console.log('Matched media queries:', Array.from(this.media.matches));
  };
}
```

## Contributing

See the [Contributing](CONTRIBUTING.md) guide for details.

## License

This project is licensed under the [MIT License](LICENSE.md).