Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
eb01913
feat: Add RCS message support with redesigned docs UI
thinkingserious Feb 25, 2026
eb669a7
fix: Resolve all eslint errors in new source files
thinkingserious Feb 25, 2026
12464de
feat: Make SMS and RCS sections collapsible with toggle indicator
thinkingserious Feb 25, 2026
4b3c845
fix: Address Copilot review feedback
thinkingserious Feb 25, 2026
78f6371
chore(deps-dev): Fix 6 Dependabot vulnerabilities
thinkingserious Feb 25, 2026
9250b24
feat: Add Twilio brand logo and favicon to docs site
thinkingserious Feb 25, 2026
8005f87
fix: Add legacy runtime fallbacks for TextEncoder and globalThis
thinkingserious Feb 25, 2026
51a0c47
fix: Address remaining Copilot review comments
thinkingserious Feb 25, 2026
13fbac3
chore: Rebuild dist and browser bundles
thinkingserious Feb 25, 2026
41dd87f
feat: Add 1,600-character API limit warning for RCS messages
thinkingserious Feb 25, 2026
450767a
fix: Use actual byte count as capacity for international RCS segments
thinkingserious Feb 26, 2026
077b3fc
fix: Hide segment tape for international RCS messages
thinkingserious Feb 26, 2026
5657573
feat: Add 1,600-character API limit warning to SMS section
thinkingserious Feb 26, 2026
684ad5a
test: Harden RCS and UTF-8 byte counting test coverage
thinkingserious Feb 26, 2026
bbf6198
fix: Address code review feedback
thinkingserious Feb 27, 2026
cab25de
fix: Validate RCS region input at runtime
thinkingserious Feb 27, 2026
8ec3e99
fix(deps): Downgrade chalk from v5 to v4 for CommonJS compatibility
thinkingserious Feb 27, 2026
42c047c
chore: Remove PR review logs
thinkingserious Feb 27, 2026
43ea1ee
fix: Remove shell prompt prefix from README command example
thinkingserious Feb 27, 2026
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ typings/
# dotenv environment variables file
.env

.DS_Store
.DS_Store

# Context files (not for commits)
.context/
47 changes: 39 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SMS Segment Calculator
# Messaging Segment Calculator (SMS + RCS)

This repo contains a package for an SMS segments calculator. The package is released as a nodeJS package as well as a browser script.
This repo contains a package for SMS and RCS segment calculations. The package is released as a nodeJS package as well as a browser script.
A browser demo for this package can be accessed [here](https://twiliodeved.github.io/message-segment-calculator/)

## Usage
Expand All @@ -13,32 +13,38 @@ The package can be installed using:
npm install --save sms-segments-calculator
```

Sample usage:
Sample usage:

```javascript
const { SegmentedMessage } = require('sms-segments-calculator');
const { SegmentedMessage, RcsSegmentedMessage } = require('sms-segments-calculator');

const segmentedMessage = new SegmentedMessage('Hello World');

console.log(segmentedMessage.encodingName); // "GSM-7"
console.log(segmentedMessage.segmentsCount); // "1"

const rcsMessage = new RcsSegmentedMessage('Hello RCS', 'us');
console.log(rcsMessage.messageType); // "Rich"
console.log(rcsMessage.segmentsCount); // "1"
```

### Browser

You can add the library to your page using the CDN file:
You can add the library to your page using the CDN file:

```html
<script src="https://cdn.jsdelivr.net/gh/TwilioDevEd/message-segment-calculator/docs/scripts/segmentsCalculator.js" integrity="sha256-wXuHVlXNhEWNzRKozzB87Qyi9/3p6LKskjDXFHIMInw=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/TwilioDevEd/message-segment-calculator/docs/scripts/segmentsCalculator.js" integrity="sha256-e2498331ca98c0d43952423be7ff75944f7f29d201da4ee466bd06e59e8054cb" crossorigin="anonymous"></script>
```

Alternatively you can add the library to your page using the file [`segmentsCalculator.js`](https://github.com/TwilioDevEd/message-segment-calculator/blob/main/docs/scripts/segmentsCalculator.js) provided in `docs/scripts/` and adding it to your page:
Alternatively you can add the library to your page using the file [`segmentsCalculator.js`](https://github.com/TwilioDevEd/message-segment-calculator/blob/main/docs/scripts/segmentsCalculator.js) provided in `docs/scripts/` and adding it to your page:

```html
<script type="text/javascript" src="scripts/segmentsCalculator.js"></script>
```

And example of usage can be find in [`docs/index.html`](https://github.com/TwilioDevEd/message-segment-calculator/blob/main/docs/index.html)
Once loaded, the browser bundle exposes `SegmentedMessage` and `RcsSegmentedMessage` as globals.

An example of usage can be find in [`docs/index.html`](https://github.com/TwilioDevEd/message-segment-calculator/blob/main/docs/index.html)

## Documentation
### `SegmentedMessage` class
Expand Down Expand Up @@ -70,6 +76,19 @@ Number of segment(s)

Return an array with the non GSM-7 characters in the body. It can be used to replace character and reduce the number of segments

### `RcsSegmentedMessage` class

RCS always uses UTF-8. For US destinations, messages are billed per 160 UTF-8 byte “Rich” segment. For international destinations, there is no segmentation: `<=160` bytes is billed as `Basic`, and `>160` bytes is billed as `Single`.

#### `constructor(message, region)`
Arguments:
* `message`: Body of the RCS message
* `region`: `us` or `international` (default: `us`)

##### `messageType`

Returns `Rich`, `Basic`, or `Single` based on the region and UTF-8 length.

Comment thread
thinkingserious marked this conversation as resolved.
## Try the library

If you want to test the library you can use the script provided in `playground/index.js`. Install the dependencies (`npm install`) and then run:
Comment thread
thinkingserious marked this conversation as resolved.
Expand All @@ -89,6 +108,18 @@ The source code for the library is all contained in the `src` folder. Before sub
* Execute the test using `npm test` and make sure all tests pass
* Transpile the code using `npm run webpack` and test the web page in `docs/index.html`

## Accessibility

The docs UI follows Paste-aligned accessibility guidelines:
* All color meaning includes a text label (encoding, fill state)
* Stats updates use `aria-live="polite"` for screen reader announcements
* Inputs include visible focus styles and associated labels
* Segment bars use `role=\"meter\"` with value attributes

## Design Inspiration

We used the Kimoby SMS Segment Counter as visual inspiration: https://www.kimoby.com/calculators/sms-segment-counter

## License

[MIT](http://www.opensource.org/licenses/mit-license.html)
Expand Down
1 change: 1 addition & 0 deletions dist/browser/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
7 changes: 7 additions & 0 deletions dist/browser/global.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/browser/global.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/browser/main.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
86 changes: 86 additions & 0 deletions dist/browser/main.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dist/browser/main.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions dist/browser/renderer.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { SmsAnalysis, RcsAnalysis } from './types';
export interface SmsRenderTargets {
encodingBadge: HTMLElement;
encodingValue: HTMLElement;
characters: HTMLElement;
segments: HTMLElement;
remaining: HTMLElement;
segmentTape: HTMLElement;
encodingSummary: HTMLElement;
messageSize: HTMLElement;
totalSize: HTMLElement;
unicodeScalars: HTMLElement;
nonGsmEmpty: HTMLElement;
nonGsmTable: HTMLTableElement;
nonGsmTableBody: HTMLElement;
warnings: HTMLElement;
error: HTMLElement;
}
export interface RcsRenderTargets {
encodingBadge: HTMLElement;
encodingValue: HTMLElement;
characters: HTMLElement;
segments: HTMLElement;
messageType: HTMLElement;
remaining: HTMLElement;
size: HTMLElement;
segmentTape: HTMLElement;
detailsText: HTMLElement;
detailSize: HTMLElement;
detailBytes: HTMLElement;
detailBilling: HTMLElement;
}
export declare const renderSms: (analysis: SmsAnalysis, targets: SmsRenderTargets, errorMessage?: string) => void;
export declare const renderRcs: (analysis: RcsAnalysis, targets: RcsRenderTargets) => void;
Loading
Loading