Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
6 changes: 6 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
77 changes: 77 additions & 0 deletions packages/core/src/__tests__/localStorage.test.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
});
56 changes: 56 additions & 0 deletions packages/core/src/__tests__/visibility.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
});
35 changes: 35 additions & 0 deletions packages/core/src/localStorage.ts
Original file line number Diff line number Diff line change
@@ -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;
}
}
17 changes: 17 additions & 0 deletions packages/core/src/visibility.ts
Original file line number Diff line number Diff line change
@@ -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);
}
7 changes: 7 additions & 0 deletions packages/react/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down