diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index d4a2a8e..4c9aa36 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -105,4 +105,15 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} with: - publish: pnpm publish + publish: pnpm publish-packages + + - name: Create Git tag + run: | + # Get version from root package.json (or the main package) + VERSION=$(node -p "require('./package.json').version") + echo "Version: $VERSION" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "v$VERSION" -m "Release version $VERSION" + git push origin "v$VERSION" diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index acccd65..5a5a0ff 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,11 @@ # @umah-creative/browser-native +## 0.2.0 + +### Minor Changes + +- added support for localstorage and visibility event listener + ## 0.1.1 ### Patch Changes diff --git a/packages/core/package.json b/packages/core/package.json index f601a58..55209ad 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@umah-creative/browser-native", - "version": "0.1.1", + "version": "0.2.0", "description": "A lightweight, modern TypeScript library that provides a unified interface to browser-native APIs such as Clipboard, Geolocation, Notifications, and more. Fully tree-shakeable, framework-agnostic, and optimized for modern browsers.", "author": "Ummah Creative", "license": "MIT", diff --git a/packages/core/src/__tests__/localStorage.test.ts b/packages/core/src/__tests__/localStorage.test.ts new file mode 100644 index 0000000..aa517b4 --- /dev/null +++ b/packages/core/src/__tests__/localStorage.test.ts @@ -0,0 +1,77 @@ +import { + writeLocalStorage, + readLocalStorage, + removeLocalStorage, +} from '../localStorage'; + +describe('localStorage utilities', () => { + const mockSetItem = jest.fn(); + const mockGetItem = jest.fn(); + const mockRemoveItem = jest.fn(); + + beforeAll(() => { + Object.defineProperty(window, 'localStorage', { + value: { + setItem: mockSetItem, + getItem: mockGetItem, + removeItem: mockRemoveItem, + }, + configurable: true, + }); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('writeLocalStorage', () => { + it('should write a value to localStorage', () => { + writeLocalStorage('myKey', 'myValue'); + expect(mockSetItem).toHaveBeenCalledWith('myKey', 'myValue'); + expect(mockSetItem).toHaveBeenCalledTimes(1); + }); + + it('should throw an error if setItem fails', () => { + mockSetItem.mockImplementationOnce(() => { + throw new Error('Storage error'); + }); + expect(() => writeLocalStorage('key', 'value')).toThrow('Storage error'); + }); + }); + + describe('readLocalStorage', () => { + it('should read a value from localStorage', () => { + mockGetItem.mockReturnValueOnce('storedValue'); + const result = readLocalStorage('myKey'); + expect(result).toBe('storedValue'); + expect(mockGetItem).toHaveBeenCalledWith('myKey'); + }); + + it('should return null if key does not exist', () => { + mockGetItem.mockReturnValueOnce(null); + const result = readLocalStorage('missingKey'); + expect(result).toBeNull(); + }); + + it('should throw an error if getItem fails', () => { + mockGetItem.mockImplementationOnce(() => { + throw new Error('Storage error'); + }); + expect(() => readLocalStorage('key')).toThrow('Storage error'); + }); + }); + + describe('removeLocalStorage', () => { + it('should remove a value from localStorage', () => { + removeLocalStorage('myKey'); + expect(mockRemoveItem).toHaveBeenCalledWith('myKey'); + }); + + it('should throw an error if removeItem fails', () => { + mockRemoveItem.mockImplementationOnce(() => { + throw new Error('Storage error'); + }); + expect(() => removeLocalStorage('key')).toThrow('Storage error'); + }); + }); +}); diff --git a/packages/core/src/__tests__/visibility.test.ts b/packages/core/src/__tests__/visibility.test.ts new file mode 100644 index 0000000..261ff7d --- /dev/null +++ b/packages/core/src/__tests__/visibility.test.ts @@ -0,0 +1,56 @@ +import { isPageVisible, onVisibilityChange } from '../visibility'; + +describe('visibility utilities', () => { + describe('isPageVisible', () => { + it('should return true when document is visible', () => { + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + configurable: true, + }); + + expect(isPageVisible()).toBe(true); + }); + + it('should return false when document is hidden', () => { + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + configurable: true, + }); + + expect(isPageVisible()).toBe(false); + }); + }); + + describe('onVisibilityChange', () => { + it('should call callback when visibility changes', () => { + const callback = jest.fn(); + + // Add listener + const unsubscribe = onVisibilityChange(callback); + + // Simulate a visibility change + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + configurable: true, + }); + document.dispatchEvent(new Event('visibilitychange')); + + expect(callback).toHaveBeenCalledWith(false); + + // Simulate another visibility change + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + configurable: true, + }); + document.dispatchEvent(new Event('visibilitychange')); + + expect(callback).toHaveBeenCalledWith(true); + expect(callback).toHaveBeenCalledTimes(2); + + // Remove listener and ensure it doesn't trigger again + unsubscribe(); + document.dispatchEvent(new Event('visibilitychange')); + expect(callback).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/packages/core/src/localStorage.ts b/packages/core/src/localStorage.ts new file mode 100644 index 0000000..9e23e17 --- /dev/null +++ b/packages/core/src/localStorage.ts @@ -0,0 +1,35 @@ +/** + * Writes a value to localStorage. + */ +export function writeLocalStorage(key: string, value: string): void { + try { + window.localStorage.setItem(key, value); + } catch (err) { + console.error('Failed to write to localStorage:', err); + throw err; + } +} + +/** + * Reads a value from localStorage. + */ +export function readLocalStorage(key: string): string | null { + try { + return window.localStorage.getItem(key); + } catch (err) { + console.error('Failed to read from localStorage:', err); + throw err; + } +} + +/** + * Removes a value from localStorage. + */ +export function removeLocalStorage(key: string): void { + try { + window.localStorage.removeItem(key); + } catch (err) { + console.error('Failed to remove from localStorage:', err); + throw err; + } +} diff --git a/packages/core/src/visibility.ts b/packages/core/src/visibility.ts new file mode 100644 index 0000000..df2681d --- /dev/null +++ b/packages/core/src/visibility.ts @@ -0,0 +1,17 @@ +/** + * Checks if the page is currently visible. + */ +export function isPageVisible(): boolean { + return document.visibilityState === 'visible'; +} + +/** + * Adds an event listener for visibility changes. + */ +export function onVisibilityChange(callback: (visible: boolean) => void) { + const handler = () => callback(document.visibilityState === 'visible'); + + document.addEventListener('visibilitychange', handler); + + return () => document.removeEventListener('visibilitychange', handler); +} diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 5642b32..52bc73c 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,12 @@ # @umah-creative/browser-native-react +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @umah-creative/browser-native@0.2.0 + ## 0.1.1 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 6446d6e..0927029 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@umah-creative/browser-native-react", - "version": "0.1.1", + "version": "0.1.2", "description": "React hooks wrapper for browser-native APIs. Provides idiomatic, composable hooks built on top of the core browser-native library.", "author": "Ummah Creative", "license": "MIT",