responsive-media 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +252 -130
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -4,47 +4,71 @@
4
4
  </h1>
5
5
  <img
6
6
  src="https://s3.twcstorage.ru/c9a2cc89-780f97fd-311d-4a1a-b86f-c25665c9dc46/images/npm/responsive-media.webp"
7
- alt="vue-virtual-scroller-kit"
7
+ alt="responsive-media"
8
8
  style="max-width:100%;width:auto;height:300px;border-radius:12px"
9
9
  />
10
10
  </div>
11
11
 
12
- A utility for creating reactive boolean state from CSS media queries and element dimensions. Useful when you need more than CSSwhen you want to **imperatively react to viewport or container changes** in JavaScript.
12
+ Reactive boolean state from CSS media queries and element dimensions for Vanilla JS, Vue 3, and React 18+ AND/OR conditions, container queries, ordered breakpoint helpers, rich subscription API, CSS vars sync, SSR-safe — with no required peer dependencies.
13
13
 
14
- - **Viewport breakpoints** — backed by `window.matchMedia`
15
- - **Container queries** — backed by `ResizeObserver` (JS-side evaluation)
16
- - **Vue 3** and **React 18+** adapters included
17
- - **SSR-safe** — falls back to `false` on the server
18
- - **Framework-agnostic** core — works with Vanilla JS, signals libraries, or any other framework
14
+ ---
15
+
16
+ ## Contents
17
+
18
+ - [Features](#features)
19
+ - [Installation](#installation)
20
+ - [Quick start](#quick-start)
21
+ - [Config format — MediaQueryConfig](#config-format--mediaqueryconfig)
22
+ - [Global singleton](#global-singleton)
23
+ - [createResponsiveState — isolated instances](#createresponsivestate--isolated-instances)
24
+ - [ContainerState — element container queries](#containerstate--element-container-queries)
25
+ - [Subscription API](#subscription-api)
26
+ - [Ordered breakpoint helpers](#ordered-breakpoint-helpers)
27
+ - [Utilities](#utilities)
28
+ - [Presets](#presets)
29
+ - [Vue 3 integration](#vue-3-integration)
30
+ - [React 18+ integration](#react-18-integration)
31
+ - [TypeScript helpers](#typescript-helpers)
32
+ - [SSR / hydration](#ssr--hydration)
33
+ - [Architecture](#architecture)
34
+ - [Bundle size & peer dependencies](#bundle-size--peer-dependencies)
35
+ - [Exported API reference](#exported-api-reference)
36
+
37
+ ---
38
+
39
+ ## Features
40
+
41
+ - **Framework-agnostic core** — `ReactiveResponsiveState` and `ContainerState` work with Vanilla JS, any signals library, or any framework; Vue and React are optional peer dependencies
42
+ - **Viewport breakpoints** — backed by `window.matchMedia`; conditions combined with AND (flat array) or OR (nested array); raw media type support for `print`, `screen`, etc.
43
+ - **Full condition vocabulary** — `min/max-width`, `min/max-height`, `orientation`, `aspect-ratio`, `prefers-color-scheme`, `prefers-reduced-motion`, `prefers-contrast`, `hover`, `pointer`, `forced-colors`, `resolution`, `display-mode`, and `raw`
44
+ - **Container queries (JS-side)** — `ContainerState` tracks an element's dimensions via `ResizeObserver` and evaluates breakpoint conditions in JavaScript; identical API to viewport state
45
+ - **Rich subscription API** — `subscribe`, `on`, `onEnter`, `onLeave`, `once`, `onNextChange`, `onBreakpointChange`, `waitFor`; optional debounce for `subscribe`; per-key listeners are never debounced
46
+ - **Ordered breakpoint helpers** — `current`, `isAbove()`, `isBelow()`, `between()` for semantic viewport comparisons; order derived from config key insertion or explicit `order` option
47
+ - **Utilities** — `syncCSSVars` (CSS custom properties), `emitDOMEvents` (DOM CustomEvents), `toSignal` (any signals library — Preact, Angular, SolidJS, Vue), `match` (pick value by first active breakpoint), `subscribeMediaQuery` (raw single query)
48
+ - **Vue 3 adapter** — `useResponsive`, `useBreakpoints`, `useMediaQuery`, `useContainerState`; fully reactive in templates and `computed`; `ResponsivePlugin` for global config
49
+ - **React 18+ adapter** — same four hooks; `useSyncExternalStore` for safe concurrent rendering; SSR-safe (`false` on server)
50
+ - **Presets** — `TailwindPreset`, `BootstrapPreset`, `AccessibilityPreset` out of the box; user-preference queries (`dark`, `reducedMotion`, `highContrast`, `print`, …)
51
+ - **SSR-safe** — all APIs check for `window` / `matchMedia` / `ResizeObserver` before use; `hydrate()` prevents layout shift on the client
52
+ - **TypeScript** — full generics; `ConfigToState<T>` infers a boolean-state type from any config object
53
+
54
+ ---
19
55
 
20
56
  ## Installation
21
57
 
22
- ```
58
+ ```bash
23
59
  npm install responsive-media
24
60
  ```
25
61
 
26
- ---
62
+ No required peer dependencies. Vue and React adapters are available automatically when the respective package is installed:
27
63
 
28
- ## Table of Contents
29
-
30
- 1. [Quick Start](#quick-start)
31
- 2. [Config format — MediaQueryConfig](#config-format--mediaqueryconfig)
32
- 3. [Global singleton](#global-singleton)
33
- 4. [createResponsiveState — isolated instances](#createresponsivestate--isolated-instances)
34
- 5. [ContainerState — element container queries](#containerstate--element-container-queries)
35
- 6. [Subscription API](#subscription-api)
36
- 7. [Ordered breakpoint helpers](#ordered-breakpoint-helpers)
37
- 8. [Utilities](#utilities)
38
- 9. [Presets](#presets)
39
- 10. [Vue 3 integration](#vue-3-integration)
40
- 11. [React 18+ integration](#react-18-integration)
41
- 12. [TypeScript helpers](#typescript-helpers)
42
- 13. [SSR / hydration](#ssr--hydration)
43
- 14. [Exported API reference](#exported-api-reference)
64
+ ```bash
65
+ npm install vue@>=3.3 # for Vue composables
66
+ npm install react@>=18 # for React hooks
67
+ ```
44
68
 
45
69
  ---
46
70
 
47
- ## Quick Start
71
+ ## Quick start
48
72
 
49
73
  ```ts
50
74
  import { responsiveState, setResponsiveConfig } from 'responsive-media';
@@ -71,7 +95,7 @@ stop();
71
95
 
72
96
  ## Config format — MediaQueryConfig
73
97
 
74
- Each breakpoint is described by a `MediaQueryConfig` — an array of conditions that are combined with **AND**, or a nested array of groups combined with **OR**.
98
+ Each breakpoint is described by a `MediaQueryConfig` — an array of conditions combined with **AND**, or a nested array of groups combined with **OR**.
75
99
 
76
100
  ### AND (flat array)
77
101
 
@@ -107,24 +131,23 @@ Use `type: 'raw'` to insert a value verbatim — useful for media types like `pr
107
131
 
108
132
  ### Supported condition types
109
133
 
110
- | `type` | Example value | Generated query |
111
- |-------------------------|-------------------|-----------------------------------|
112
- | `min-width` | `768` | `(min-width: 768px)` |
113
- | `max-width` | `1023` | `(max-width: 1023px)` |
114
- | `min-height` | `600` | `(min-height: 600px)` |
115
- | `max-height` | `900` | `(max-height: 900px)` |
116
- | `orientation` | `'portrait'` | `(orientation: portrait)` |
117
- | `aspect-ratio` | `'16/9'` | `(aspect-ratio: 16/9)` |
118
- | `prefers-color-scheme` | `'dark'` | `(prefers-color-scheme: dark)` |
119
- | `prefers-reduced-motion`| `'reduce'` | `(prefers-reduced-motion: reduce)`|
120
- | `prefers-contrast` | `'more'` | `(prefers-contrast: more)` |
121
- | `hover` | `'none'` | `(hover: none)` |
122
- | `pointer` | `'coarse'` | `(pointer: coarse)` |
123
- | `forced-colors` | `'active'` | `(forced-colors: active)` |
124
- | `resolution` | `'2dppx'` | `(resolution: 2dppx)` |
125
- | `display-mode` | `'standalone'` | `(display-mode: standalone)` |
126
- | `raw` | `'print'` | `print` *(verbatim)* |
127
- | … and more | | |
134
+ | `type` | Example value | Generated query |
135
+ |--------------------------|----------------|------------------------------------|
136
+ | `min-width` | `768` | `(min-width: 768px)` |
137
+ | `max-width` | `1023` | `(max-width: 1023px)` |
138
+ | `min-height` | `600` | `(min-height: 600px)` |
139
+ | `max-height` | `900` | `(max-height: 900px)` |
140
+ | `orientation` | `'portrait'` | `(orientation: portrait)` |
141
+ | `aspect-ratio` | `'16/9'` | `(aspect-ratio: 16/9)` |
142
+ | `prefers-color-scheme` | `'dark'` | `(prefers-color-scheme: dark)` |
143
+ | `prefers-reduced-motion` | `'reduce'` | `(prefers-reduced-motion: reduce)` |
144
+ | `prefers-contrast` | `'more'` | `(prefers-contrast: more)` |
145
+ | `hover` | `'none'` | `(hover: none)` |
146
+ | `pointer` | `'coarse'` | `(pointer: coarse)` |
147
+ | `forced-colors` | `'active'` | `(forced-colors: active)` |
148
+ | `resolution` | `'2dppx'` | `(resolution: 2dppx)` |
149
+ | `display-mode` | `'standalone'` | `(display-mode: standalone)` |
150
+ | `raw` | `'print'` | `print` *(verbatim)* |
128
151
 
129
152
  ---
130
153
 
@@ -142,15 +165,15 @@ setResponsiveConfig(
142
165
  lg: [{ type: 'min-width', value: 1024 }],
143
166
  },
144
167
  {
145
- order: ['sm', 'lg'], // for isAbove/isBelow/between
146
- debounce: 50, // ms, throttle subscribe() listeners
168
+ order: ['sm', 'lg'], // for isAbove / isBelow / between
169
+ debounce: 50, // ms throttle subscribe() listeners
147
170
  }
148
171
  );
149
172
 
150
- // Read the current state snapshot
173
+ // Read a stable snapshot
151
174
  const { sm, lg } = responsiveState.getState();
152
175
 
153
- // Direct proxy access (live, non-debounced)
176
+ // Live proxy access (never debounced)
154
177
  console.log(responsiveState.proxy.sm);
155
178
 
156
179
  // Get the generated CSS strings
@@ -370,12 +393,10 @@ const stop = state.syncCSSVars({ element: document.body, prefix: '--bp-' });
370
393
  stop(); // cleanup
371
394
  ```
372
395
 
373
- **Options:**
374
-
375
- | Option | Default | Description |
376
- |-----------|--------------------------|----------------------------------|
377
- | `element` | `document.documentElement` | Target HTML element |
378
- | `prefix` | `'--responsive-'` | CSS custom property name prefix |
396
+ | Option | Default | Description |
397
+ |-----------|----------------------------|----------------------------------|
398
+ | `element` | `document.documentElement` | Target HTML element |
399
+ | `prefix` | `'--responsive-'` | CSS custom property name prefix |
379
400
 
380
401
  ### `emitDOMEvents(target?, options?)` → stop
381
402
 
@@ -395,8 +416,6 @@ document.addEventListener('bp:desktop:leave', () => destroyDesktopChart());
395
416
  stop();
396
417
  ```
397
418
 
398
- **Options:**
399
-
400
419
  | Option | Default | Description |
401
420
  |----------|-----------------|--------------------------|
402
421
  | `prefix` | `'responsive:'` | Custom event name prefix |
@@ -442,7 +461,6 @@ Returns the configured breakpoint order array (or empty array if not set).
442
461
  Sets initial state from a server-side snapshot to prevent layout shift. Only updates keys that exist in the current config.
443
462
 
444
463
  ```ts
445
- // On the server, serialize state and pass to the client:
446
464
  state.hydrate({ mobile: false, tablet: false, desktop: true });
447
465
  ```
448
466
 
@@ -472,9 +490,9 @@ Returns the first value in `map` whose key is `true` in `state`. Priority follow
472
490
  import { match } from 'responsive-media';
473
491
  import { responsiveState } from 'responsive-media';
474
492
 
475
- const cols = match(responsiveState.proxy, { mobile: 1, tablet: 2, desktop: 4 });
476
- const View = match(responsiveState.proxy, { mobile: MobileMenu, desktop: DesktopNav });
477
- const label = match(responsiveState.proxy, { sm: 'Compact', lg: 'Full' }, 'Default');
493
+ const cols = match(responsiveState.proxy, { mobile: 1, tablet: 2, desktop: 4 });
494
+ const View = match(responsiveState.proxy, { mobile: MobileMenu, desktop: DesktopNav });
495
+ const label = match(responsiveState.proxy, { sm: 'Compact', lg: 'Full' }, 'Default');
478
496
  ```
479
497
 
480
498
  ### `subscribeMediaQuery(query, callback)` — standalone utility
@@ -508,14 +526,14 @@ Import from `responsive-media/presets` or from the main entry point.
508
526
 
509
527
  Mutually exclusive Tailwind CSS v3/v4 breakpoints:
510
528
 
511
- | Key | Range |
512
- |-------|----------------|
513
- | `xs` | ≤ 639px |
514
- | `sm` | 640 – 767px |
515
- | `md` | 768 – 1023px |
516
- | `lg` | 1024 – 1279px |
517
- | `xl` | 1280 – 1535px |
518
- | `2xl` | ≥ 1536px |
529
+ | Key | Range |
530
+ |-------|---------------|
531
+ | `xs` | ≤ 639px |
532
+ | `sm` | 640 – 767px |
533
+ | `md` | 768 – 1023px |
534
+ | `lg` | 1024 – 1279px |
535
+ | `xl` | 1280 – 1535px |
536
+ | `2xl` | ≥ 1536px |
519
537
 
520
538
  ```ts
521
539
  import { createResponsiveState, TailwindPreset, TailwindOrder } from 'responsive-media';
@@ -546,17 +564,17 @@ const state = createResponsiveState(BootstrapPreset, { order: [...BootstrapOrder
546
564
 
547
565
  User-preference media queries. Multiple keys can be `true` simultaneously.
548
566
 
549
- | Key | Matches when … |
550
- |-----------------|-----------------------------------------|
551
- | `dark` | `prefers-color-scheme: dark` |
552
- | `light` | `prefers-color-scheme: light` |
553
- | `reducedMotion` | `prefers-reduced-motion: reduce` |
554
- | `highContrast` | `prefers-contrast: more` |
555
- | `lowContrast` | `prefers-contrast: less` |
556
- | `noHover` | `hover: none` (touch / stylus devices) |
557
- | `coarsePointer` | `pointer: coarse` (finger-sized input) |
558
- | `forcedColors` | `forced-colors: active` (Windows HCM) |
559
- | `print` | `print` media type |
567
+ | Key | Matches when … |
568
+ |-----------------|----------------------------------------|
569
+ | `dark` | `prefers-color-scheme: dark` |
570
+ | `light` | `prefers-color-scheme: light` |
571
+ | `reducedMotion` | `prefers-reduced-motion: reduce` |
572
+ | `highContrast` | `prefers-contrast: more` |
573
+ | `lowContrast` | `prefers-contrast: less` |
574
+ | `noHover` | `hover: none` (touch / stylus devices) |
575
+ | `coarsePointer` | `pointer: coarse` (finger-sized input) |
576
+ | `forcedColors` | `forced-colors: active` (Windows HCM) |
577
+ | `print` | `print` media type |
560
578
 
561
579
  ```ts
562
580
  import { createResponsiveState, AccessibilityPreset } from 'responsive-media';
@@ -572,7 +590,7 @@ a11y.onEnter('print', () => hideNonPrintable());
572
590
 
573
591
  ## Vue 3 integration
574
592
 
575
- Import from `responsive-media` (main entry) or `responsive-media` directly Vue composables are included in the main bundle.
593
+ Vue composables are included in the main bundle and are activated when Vue is installed as a peer dependency.
576
594
 
577
595
  ### Plugin registration
578
596
 
@@ -655,7 +673,7 @@ Tracks an element's dimensions and returns a reactive state object. Sets up and
655
673
  import { useTemplateRef } from 'vue';
656
674
  import { useContainerState } from 'responsive-media';
657
675
 
658
- const cardRef = useTemplateRef('card');
676
+ const cardRef = useTemplateRef('card');
659
677
  const cardState = useContainerState(cardRef, {
660
678
  compact: [{ type: 'max-width', value: 300 }],
661
679
  wide: [{ type: 'min-width', value: 600 }],
@@ -791,9 +809,14 @@ const state = useResponsive<AppState>();
791
809
 
792
810
  ## SSR / hydration
793
811
 
794
- All APIs are SSR-safe — they check for `window` and `matchMedia` availability before use and fall back to `false` on the server.
812
+ All APIs are SSR-safe — they check for `window`, `matchMedia`, and `ResizeObserver` availability before use and fall back to `false` on the server.
795
813
 
796
- For hydration (preventing layout shift):
814
+ | Scenario | Behaviour |
815
+ |---|---|
816
+ | `typeof window === 'undefined'` | All listeners skip setup; `proxy` / `getState()` return `false` for all keys |
817
+ | `useCookie` on server (Nuxt) | Not applicable — use `useCookie` from `@vueuse/core` or Nuxt built-ins |
818
+ | React SSR | `useMediaQuery` returns `false`; `useResponsive` returns the server-side snapshot |
819
+ | Hydration mismatch | Call `hydrate()` with the server snapshot before first render |
797
820
 
798
821
  ```ts
799
822
  // Server: serialize the expected initial state
@@ -806,63 +829,146 @@ responsiveState.hydrate(initialState);
806
829
 
807
830
  ---
808
831
 
832
+ ## Architecture
833
+
834
+ ```
835
+ responsive-media
836
+
837
+ ├── BaseResponsiveState (abstract)
838
+ │ Proxy over a plain Record<string, boolean>
839
+ │ Batched updates — all matchMedia/ResizeObserver callbacks collected
840
+ │ before a single notify() fires
841
+ │ Subscription registry: global listeners + per-key listeners
842
+ │ Debounce for subscribe(); key listeners never debounced
843
+ │ Ordered breakpoint helpers: current / isAbove / isBelow / between
844
+ │ Utilities: syncCSSVars / emitDOMEvents / toSignal / hydrate / destroy
845
+
846
+ ├── ReactiveResponsiveState extends BaseResponsiveState
847
+ │ setupSources() → window.matchMedia per config key
848
+ │ Generated media query string stored in mediaQueries map
849
+ │ Batches all MediaQueryList 'change' events, then flushes
850
+ │ setConfig() / destroy() cleanupSources() removes matchMedia handlers
851
+
852
+ ├── ContainerState extends BaseResponsiveState
853
+ │ setupSources() → single ResizeObserver on the target element
854
+ │ Evaluates width/height/orientation/aspect-ratio conditions in JS
855
+ │ Reconnects observer when config changes; teardown on destroy()
856
+
857
+ ├── createResponsiveState(config, options)
858
+ │ Factory — returns a new ReactiveResponsiveState instance
859
+
860
+ ├── responsiveState (global singleton)
861
+ │ Pre-configured with default ResponsiveConfig (mobile/tablet/desktop)
862
+ │ setResponsiveConfig() / getResponsiveState() / getResponsiveMediaQueries()
863
+ │ delegate to this instance
864
+
865
+ ├── toMediaQueryString(conditions)
866
+ │ Converts MediaQueryConfig → CSS string
867
+ │ AND: flat array → joined with ' and '
868
+ │ OR: nested array → groups joined with ', '
869
+ │ Numeric values get 'px' suffix (except raw / orientation / …)
870
+
871
+ ├── match(state, map, fallback?)
872
+ │ First-match lookup — returns mapped value for first true key in map
873
+
874
+ ├── subscribeMediaQuery(query, callback)
875
+ │ Thin wrapper around window.matchMedia + addEventListener('change')
876
+ │ Returns cleanup function
877
+
878
+ ├── Vue adapter (vue-responsive.ts)
879
+ │ ResponsivePlugin — app.use(); calls setResponsiveConfig
880
+ │ useResponsive() — returns shallowReactive mirror; subscribe() syncs it
881
+ │ useBreakpoints() — returns { current, isAbove, isBelow, between }
882
+ │ all methods read from the reactive mirror
883
+ │ useMediaQuery() — wraps subscribeMediaQuery in a ref + onUnmounted
884
+ │ useContainerState() — watchEffect over templateRef; creates/destroys
885
+ │ ContainerState; returns shallowReactive mirror
886
+
887
+ ├── React adapter (react-responsive.ts)
888
+ │ useResponsive() — useSyncExternalStore(subscribe, getState, getState)
889
+ │ useBreakpoints() — useSyncExternalStore + wraps ordered helpers
890
+ │ useMediaQuery() — useSyncExternalStore over subscribeMediaQuery
891
+ │ useContainerState() — useEffect creates ContainerState; useState mirror
892
+
893
+ └── Presets (presets.ts)
894
+ ResponsiveConfig — default mobile/tablet/desktop
895
+ TailwindPreset / TailwindOrder
896
+ BootstrapPreset / BootstrapOrder
897
+ AccessibilityPreset
898
+ ```
899
+
900
+ ---
901
+
902
+ ## Bundle size & peer dependencies
903
+
904
+ | Entry point | Peer deps | Notes |
905
+ |-----------------------------|----------------------|-------|
906
+ | `responsive-media` | *(none required)* | Core + Vue composables (tree-shaken when Vue absent) |
907
+ | `responsive-media/react` | `react ^18` | React hooks only |
908
+ | `responsive-media/presets` | *(none)* | Preset configs only — add to any instance |
909
+ | `responsive-media/container`| *(none)* | `ContainerState` class + factory only |
910
+
911
+ The package ships as tree-shakeable ESM and CommonJS. Vue composables (`ResponsivePlugin`, `useResponsive`, etc.) are included in the main bundle but resolve to no-ops when Vue is not installed, so the core footprint stays minimal in non-Vue projects. The React entry point is code-split and never imported by the main bundle.
912
+
913
+ ---
914
+
809
915
  ## Exported API reference
810
916
 
811
917
  ### Main entry (`responsive-media`)
812
918
 
813
- | Export | Type | Description |
814
- |---------------------------|--------------------------|-------------------------------------------------------|
815
- | `responsiveState` | `ReactiveResponsiveState`| Global singleton, default `ResponsiveConfig` |
816
- | `setResponsiveConfig` | function | Reconfigure the global singleton |
817
- | `getResponsiveState` | function | Get state snapshot from global singleton |
818
- | `getResponsiveMediaQueries` | function | Get CSS query strings from global singleton |
819
- | `createResponsiveState` | function | Create an isolated `ReactiveResponsiveState` instance |
820
- | `createContainerState` | function | Create a `ContainerState` for an element |
821
- | `toMediaQueryString` | function | Convert `MediaQueryConfig` to CSS string |
822
- | `match` | function | Pick a value by first matching breakpoint key |
823
- | `subscribeMediaQuery` | function | Subscribe to a raw CSS media query string |
824
- | `ResponsiveConfig` | const | Default mobile/tablet/desktop breakpoints |
825
- | `BaseResponsiveState` | class | Abstract base (for extension) |
826
- | `ReactiveResponsiveState` | class | Viewport state (matchMedia-backed) |
827
- | `ContainerState` | class | Element container state (ResizeObserver-backed) |
828
- | `ResponsivePlugin` | Vue plugin | Vue app plugin |
829
- | `useResponsive` | Vue composable | Reactive state object |
830
- | `useBreakpoints` | Vue composable | Ordered breakpoint helpers |
831
- | `useMediaQuery` | Vue composable | Single raw media query |
832
- | `useContainerState` | Vue composable | Element container queries |
833
- | `ConfigToState` | type | Derives state type from config |
834
- | `MediaQueryConfig` | type | Config entry type |
835
- | `MediaQueryCondition` | type | Single condition type |
836
- | `ResponsiveState` | type | `Record<string, boolean>` |
837
- | `SetConfigOptions` | type | Options for `setConfig` / `createResponsiveState` |
838
- | `BreakpointHelpers` | type | Return type of `useBreakpoints` |
919
+ | Export | Type | Description |
920
+ |----------------------------|---------------------------|--------------------------------------------------------|
921
+ | `responsiveState` | `ReactiveResponsiveState` | Global singleton, default `ResponsiveConfig` |
922
+ | `setResponsiveConfig` | function | Reconfigure the global singleton |
923
+ | `getResponsiveState` | function | Get state snapshot from global singleton |
924
+ | `getResponsiveMediaQueries`| function | Get CSS query strings from global singleton |
925
+ | `createResponsiveState` | function | Create an isolated `ReactiveResponsiveState` instance |
926
+ | `createContainerState` | function | Create a `ContainerState` for an element |
927
+ | `toMediaQueryString` | function | Convert `MediaQueryConfig` to CSS string |
928
+ | `match` | function | Pick a value by first matching breakpoint key |
929
+ | `subscribeMediaQuery` | function | Subscribe to a raw CSS media query string |
930
+ | `ResponsiveConfig` | const | Default mobile / tablet / desktop breakpoints |
931
+ | `BaseResponsiveState` | class | Abstract base (for extension) |
932
+ | `ReactiveResponsiveState` | class | Viewport state (`matchMedia`-backed) |
933
+ | `ContainerState` | class | Element container state (`ResizeObserver`-backed) |
934
+ | `ResponsivePlugin` | Vue plugin | Vue app plugin |
935
+ | `useResponsive` | Vue composable | Reactive state object |
936
+ | `useBreakpoints` | Vue composable | Ordered breakpoint helpers |
937
+ | `useMediaQuery` | Vue composable | Single raw media query |
938
+ | `useContainerState` | Vue composable | Element container queries |
939
+ | `ConfigToState` | type | Derives state type from config |
940
+ | `MediaQueryConfig` | type | Config entry type |
941
+ | `MediaQueryCondition` | type | Single condition type |
942
+ | `ResponsiveState` | type | `Record<string, boolean>` |
943
+ | `SetConfigOptions` | type | Options for `setConfig` / `createResponsiveState` |
944
+ | `BreakpointHelpers` | type | Return type of `useBreakpoints` |
839
945
 
840
946
  ### React entry (`responsive-media/react`)
841
947
 
842
- | Export | Description |
843
- |---------------------|----------------------------------------------|
844
- | `useResponsive` | State hook (useSyncExternalStore) |
845
- | `useBreakpoints` | Ordered breakpoint helpers hook |
846
- | `useMediaQuery` | Single raw media query hook |
847
- | `useContainerState` | Element container queries hook |
848
- | `BreakpointHelpers` | Type for `useBreakpoints` return value |
948
+ | Export | Description |
949
+ |---------------------|-----------------------------------------------|
950
+ | `useResponsive` | State hook (`useSyncExternalStore`) |
951
+ | `useBreakpoints` | Ordered breakpoint helpers hook |
952
+ | `useMediaQuery` | Single raw media query hook |
953
+ | `useContainerState` | Element container queries hook |
954
+ | `BreakpointHelpers` | Type for `useBreakpoints` return value |
849
955
 
850
956
  ### Presets entry (`responsive-media/presets`)
851
957
 
852
- | Export | Description |
853
- |----------------------|-----------------------------------------|
854
- | `TailwindPreset` | Tailwind CSS v3/v4 breakpoints |
855
- | `TailwindOrder` | Ordered key array for `TailwindPreset` |
856
- | `BootstrapPreset` | Bootstrap 5 breakpoints |
857
- | `BootstrapOrder` | Ordered key array for `BootstrapPreset` |
858
- | `AccessibilityPreset`| User-preference media queries |
958
+ | Export | Description |
959
+ |-----------------------|------------------------------------------|
960
+ | `TailwindPreset` | Tailwind CSS v3/v4 breakpoints |
961
+ | `TailwindOrder` | Ordered key array for `TailwindPreset` |
962
+ | `BootstrapPreset` | Bootstrap 5 breakpoints |
963
+ | `BootstrapOrder` | Ordered key array for `BootstrapPreset` |
964
+ | `AccessibilityPreset` | User-preference media queries |
859
965
 
860
966
  ### Container entry (`responsive-media/container`)
861
967
 
862
- | Export | Description |
863
- |-----------------------|----------------------------------------------|
864
- | `ContainerState` | Class for element container queries |
865
- | `createContainerState`| Factory function |
968
+ | Export | Description |
969
+ |------------------------|------------------------------------------|
970
+ | `ContainerState` | Class for element container queries |
971
+ | `createContainerState` | Factory function |
866
972
 
867
973
  ---
868
974
 
@@ -870,8 +976,24 @@ responsiveState.hydrate(initialState);
870
976
 
871
977
  MIT
872
978
 
979
+ ---
980
+
873
981
  ## Author
874
982
 
875
- Danil Lisin aka Macrulez
983
+ Danil Lisin Vladimirovich aka Macrulez
984
+
985
+ GitHub: [macrulezru](https://github.com/macrulezru) · Website: [macrulez.ru/en](https://macrulez.ru/en)
986
+
987
+ Bugs and questions — [issues](https://github.com/macrulezru/responsive-media/issues)
988
+
989
+ ---
990
+
991
+ ## 💖 Support the project
992
+
993
+ Open source takes time and effort. If my work saves you time or brings value, consider supporting further development.
994
+
995
+ <a href="https://donate.cryptocloud.plus/M6O34NIN" target="_blank">
996
+ <img src="https://img.shields.io/badge/Donate-CryptoCloud-8A2BE2?style=for-the-badge&logo=cryptocurrency&logoColor=white" alt="Donate via CryptoCloud">
997
+ </a>
876
998
 
877
- GitHub: [macrulezru](https://github.com/macrulezru) · Website: [macrulez.ru](https://macrulez.ru/)
999
+ Thank you for being part of this journey. ❤️
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "responsive-media",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "A utility for reactive state based on CSS media queries. Includes integration with Vue 3 (Composition API) and React 18+.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",