@nyaruka/temba-components 0.164.0 → 0.165.0
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.
- package/CHANGELOG.md +13 -0
- package/DEV_DATA.md +11 -11
- package/README.md +4 -4
- package/TEST_OPTIMIZATION.md +8 -11
- package/dist/locales/es.js +4 -0
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/fr.js +4 -0
- package/dist/locales/fr.js.map +1 -1
- package/dist/locales/pt.js +4 -0
- package/dist/locales/pt.js.map +1 -1
- package/dist/static/svg/index.svg +1 -1
- package/dist/temba-components.js +1555 -484
- package/dist/temba-components.js.map +1 -1
- package/orca/setup.sh +2 -2
- package/package.json +13 -18
- package/scripts/dev-data-sync.mjs +4 -4
- package/src/Icons.ts +3 -2
- package/src/display/ProgressBar.ts +15 -2
- package/src/form/Compose.ts +31 -1
- package/src/form/ContactSearch.ts +229 -126
- package/src/interfaces.ts +52 -0
- package/src/layout/Card.ts +25 -0
- package/src/layout/CardLayout.ts +3 -3
- package/src/layout/HeaderBar.ts +4 -1
- package/src/list/BroadcastList.ts +912 -0
- package/src/list/ContentList.ts +46 -10
- package/src/list/FieldList.ts +1057 -0
- package/src/list/SortableList.ts +7 -2
- package/src/list/TembaList.ts +8 -0
- package/src/list/TembaMenu.ts +5 -38
- package/src/live/CampaignEvents.ts +33 -19
- package/src/live/ContactChat.ts +7 -1
- package/src/live/ContactDetails.ts +20 -13
- package/src/live/ContactFieldEditor.ts +7 -3
- package/src/live/ContactStoreElement.ts +3 -1
- package/src/live/ContactTimeline.ts +28 -7
- package/src/locales/es.ts +4 -0
- package/src/locales/fr.ts +4 -0
- package/src/locales/pt.ts +4 -0
- package/static/svg/index.svg +1 -1
- package/static/svg/packs/2-temba/star-filled.svg +3 -0
- package/static/svg/work/traced/star-filled.svg +1 -0
- package/static/svg/work/used/star-filled.svg +3 -0
- package/stress-test.js +3 -3
- package/temba-modules.ts +4 -0
- package/web-test-runner.config.mjs +1 -1
- package/xliff/es.xlf +12 -0
- package/xliff/fr.xlf +12 -0
- package/xliff/pt.xlf +12 -0
package/src/list/ContentList.ts
CHANGED
|
@@ -1151,12 +1151,19 @@ export class ContentList<T = any> extends RapidElement {
|
|
|
1151
1151
|
* page-header attribute to this (rather than the raw endpoint) makes
|
|
1152
1152
|
* the menu re-fetch whenever the committed search changes. */
|
|
1153
1153
|
private contentMenuEndpointWithSearch(): string {
|
|
1154
|
-
if (!this.contentMenuEndpoint
|
|
1154
|
+
if (!this.contentMenuEndpoint) {
|
|
1155
1155
|
return this.contentMenuEndpoint;
|
|
1156
1156
|
}
|
|
1157
1157
|
try {
|
|
1158
1158
|
const url = new URL(this.contentMenuEndpoint, window.location.origin);
|
|
1159
|
-
|
|
1159
|
+
// With no committed search, *strip* any search param rather than
|
|
1160
|
+
// passing the endpoint through — hosts typically bake the
|
|
1161
|
+
// original request's query string into the attribute (so a
|
|
1162
|
+
// deep-linked search seeds the menu), and clearing the search in
|
|
1163
|
+
// the list must also clear it from the menu fetch or
|
|
1164
|
+
// search-dependent items (e.g. "Create Smart Group") linger.
|
|
1165
|
+
if (this.search) url.searchParams.set('search', this.search);
|
|
1166
|
+
else url.searchParams.delete('search');
|
|
1160
1167
|
return url.pathname + url.search;
|
|
1161
1168
|
} catch {
|
|
1162
1169
|
return this.contentMenuEndpoint;
|
|
@@ -1589,6 +1596,20 @@ export class ContentList<T = any> extends RapidElement {
|
|
|
1589
1596
|
private writeUrlState(replace = false): void {
|
|
1590
1597
|
this.bubbleHistoryState(replace);
|
|
1591
1598
|
if (!this.urlState) return;
|
|
1599
|
+
const url = this.buildBrowserUrl();
|
|
1600
|
+
if (replace) {
|
|
1601
|
+
window.history.replaceState({}, '', url);
|
|
1602
|
+
} else {
|
|
1603
|
+
window.history.pushState({}, '', url);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
/** The address-bar URL reflecting the current list state: the
|
|
1608
|
+
* page's path with the list's search/sort/page params folded into
|
|
1609
|
+
* the existing query string (set when active, removed when not —
|
|
1610
|
+
* so a cleared search drops its param). Params the list doesn't
|
|
1611
|
+
* own are preserved. */
|
|
1612
|
+
private buildBrowserUrl(): string {
|
|
1592
1613
|
const params = new URLSearchParams(window.location.search);
|
|
1593
1614
|
const k = (name: string) =>
|
|
1594
1615
|
this.urlParamPrefix ? `${this.urlParamPrefix}_${name}` : name;
|
|
@@ -1602,12 +1623,7 @@ export class ContentList<T = any> extends RapidElement {
|
|
|
1602
1623
|
setOrDelete(k('page'), this.page > 1 ? String(this.page) : '');
|
|
1603
1624
|
|
|
1604
1625
|
const qs = params.toString();
|
|
1605
|
-
|
|
1606
|
-
if (replace) {
|
|
1607
|
-
window.history.replaceState({}, '', url);
|
|
1608
|
-
} else {
|
|
1609
|
-
window.history.pushState({}, '', url);
|
|
1610
|
-
}
|
|
1626
|
+
return window.location.pathname + (qs ? '?' + qs : '');
|
|
1611
1627
|
}
|
|
1612
1628
|
|
|
1613
1629
|
/** Read saved list state out of the host's history entry under
|
|
@@ -1620,7 +1636,19 @@ export class ContentList<T = any> extends RapidElement {
|
|
|
1620
1636
|
private readHistoryState(): void {
|
|
1621
1637
|
const key = this.historyStateKey;
|
|
1622
1638
|
if (!key) return;
|
|
1623
|
-
const
|
|
1639
|
+
const state = window.history.state || {};
|
|
1640
|
+
// A fresh navigation has no stash for this list yet, but the link
|
|
1641
|
+
// itself may deep-link a query (e.g. /contact/?search=age%3E10) —
|
|
1642
|
+
// fall back to the URL params so the list initializes on them.
|
|
1643
|
+
// Once the list has bubbled state for this entry the stash exists
|
|
1644
|
+
// (even with an empty search) and takes precedence, so a cleared
|
|
1645
|
+
// search isn't resurrected by a stale query string.
|
|
1646
|
+
if (!(key in state)) {
|
|
1647
|
+
this.restoreUrl = '';
|
|
1648
|
+
this.readUrlState();
|
|
1649
|
+
return;
|
|
1650
|
+
}
|
|
1651
|
+
const stash = state[key] || {};
|
|
1624
1652
|
const previousSearch = this.search;
|
|
1625
1653
|
this.search = typeof stash.search === 'string' ? stash.search : '';
|
|
1626
1654
|
this.sort = typeof stash.sort === 'string' ? stash.sort : '';
|
|
@@ -1670,10 +1698,18 @@ export class ContentList<T = any> extends RapidElement {
|
|
|
1670
1698
|
if (this.cursorMode && this.currentUrl) {
|
|
1671
1699
|
state.url = this.currentUrl;
|
|
1672
1700
|
}
|
|
1701
|
+
// `url` (distinct from `state.url`, the fetch cursor) is the
|
|
1702
|
+
// address-bar URL for this list state — the host should pass it
|
|
1703
|
+
// as the url argument of its pushState/replaceState so a
|
|
1704
|
+
// committed or cleared search is reflected in the address bar,
|
|
1705
|
+
// while keeping its own stashed page URL (frame.js's
|
|
1706
|
+
// `state.url`) stable so in-list back/forward isn't mistaken
|
|
1707
|
+
// for a cross-page navigation.
|
|
1673
1708
|
this.fireCustomEvent(CustomEventType.HistoryChange, {
|
|
1674
1709
|
key: this.historyStateKey,
|
|
1675
1710
|
state,
|
|
1676
|
-
replace
|
|
1711
|
+
replace,
|
|
1712
|
+
url: this.buildBrowserUrl()
|
|
1677
1713
|
});
|
|
1678
1714
|
}
|
|
1679
1715
|
|