@fieldia/viewer 0.8.0 → 0.9.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.
Files changed (58) hide show
  1. package/README.md +10 -1
  2. package/bundle/fieldia.js +4 -609
  3. package/bundle/fieldia.js.map +4 -4
  4. package/package.json +3 -3
  5. package/src/lib/custom-filter.d.mts +16 -0
  6. package/src/lib/custom-filter.d.ts +16 -0
  7. package/src/lib/custom-filter.js +112 -0
  8. package/src/lib/custom-filter.js.map +1 -0
  9. package/src/lib/custom-filter.mjs +109 -0
  10. package/src/lib/custom-filter.mjs.map +1 -0
  11. package/src/lib/dom.d.mts +2 -0
  12. package/src/lib/dom.d.ts +2 -0
  13. package/src/lib/dom.js +3 -0
  14. package/src/lib/dom.js.map +1 -0
  15. package/src/lib/dom.mjs +2 -0
  16. package/src/lib/dom.mjs.map +1 -0
  17. package/src/lib/favourites.d.mts +32 -0
  18. package/src/lib/favourites.d.ts +32 -0
  19. package/src/lib/favourites.js +74 -0
  20. package/src/lib/favourites.js.map +1 -0
  21. package/src/lib/favourites.mjs +69 -0
  22. package/src/lib/favourites.mjs.map +1 -0
  23. package/src/lib/labels.d.mts +46 -0
  24. package/src/lib/labels.d.ts +46 -0
  25. package/src/lib/labels.js +156 -0
  26. package/src/lib/labels.js.map +1 -1
  27. package/src/lib/labels.mjs +156 -0
  28. package/src/lib/labels.mjs.map +1 -1
  29. package/src/lib/list-groups.d.mts +29 -0
  30. package/src/lib/list-groups.d.ts +29 -0
  31. package/src/lib/list-groups.js +86 -0
  32. package/src/lib/list-groups.js.map +1 -0
  33. package/src/lib/list-groups.mjs +83 -0
  34. package/src/lib/list-groups.mjs.map +1 -0
  35. package/src/lib/list-styles.d.mts +4 -0
  36. package/src/lib/list-styles.d.ts +4 -0
  37. package/src/lib/list-styles.js +108 -0
  38. package/src/lib/list-styles.js.map +1 -0
  39. package/src/lib/list-styles.mjs +104 -0
  40. package/src/lib/list-styles.mjs.map +1 -0
  41. package/src/lib/list.d.mts +34 -0
  42. package/src/lib/list.d.ts +34 -0
  43. package/src/lib/list.js +282 -0
  44. package/src/lib/list.js.map +1 -0
  45. package/src/lib/list.mjs +279 -0
  46. package/src/lib/list.mjs.map +1 -0
  47. package/src/lib/search-bar.d.mts +30 -0
  48. package/src/lib/search-bar.d.ts +30 -0
  49. package/src/lib/search-bar.js +205 -0
  50. package/src/lib/search-bar.js.map +1 -0
  51. package/src/lib/search-bar.mjs +201 -0
  52. package/src/lib/search-bar.mjs.map +1 -0
  53. package/src/lib/viewer.d.mts +3 -1
  54. package/src/lib/viewer.d.ts +3 -1
  55. package/src/lib/viewer.js +26 -1
  56. package/src/lib/viewer.js.map +1 -1
  57. package/src/lib/viewer.mjs +26 -1
  58. package/src/lib/viewer.mjs.map +1 -1
@@ -0,0 +1,30 @@
1
+ import { type Facet, type ListNode, type Page } from '@fieldia/core';
2
+ import { type IconSet, type PreferenceStore } from '@fieldia/widgets';
3
+ import type { El } from './dom';
4
+ import type { ViewerLabels } from './labels';
5
+ export interface SearchContext {
6
+ page: Page;
7
+ node: ListNode;
8
+ doc: Document;
9
+ el: El;
10
+ labels: ViewerLabels;
11
+ fill: (template: string, values: Record<string, string | number>) => string;
12
+ uid: (id: string) => string;
13
+ icons?: IconSet;
14
+ preferences: PreferenceStore;
15
+ /** What the list starts with. */
16
+ facets: Facet[];
17
+ onChange: (facets: Facet[]) => void;
18
+ }
19
+ /** A chip's words: a field and the values looked for in it, filters any of which apply, or the fields grouped by. */
20
+ export declare function facetText(facet: Facet, labels: Pick<ViewerLabels, 'or'>): string;
21
+ /**
22
+ * A list's search bar: what is typed becomes a search in one of the list's
23
+ * fields, chosen from suggestions; the menu turns the list's filters on and
24
+ * off, groups by its fields, builds a filter, and keeps searches as
25
+ * favourites. Everything chosen shows as a chip, and all of it applies.
26
+ */
27
+ export declare function searchBar(context: SearchContext): {
28
+ element: HTMLDivElement;
29
+ destroy: () => void;
30
+ };
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.facetText = facetText;
4
+ exports.searchBar = searchBar;
5
+ const core_1 = require("@fieldia/core");
6
+ const widgets_1 = require("@fieldia/widgets");
7
+ const custom_filter_1 = require("./custom-filter");
8
+ const favourites_1 = require("./favourites");
9
+ /** A chip's words: a field and the values looked for in it, filters any of which apply, or the fields grouped by. */
10
+ function facetText(facet, labels) {
11
+ const or = ` ${labels.or} `;
12
+ switch (facet.kind) {
13
+ case 'field':
14
+ return `${facet.label}: ${facet.values.map((v) => v.label).join(or)}`;
15
+ case 'filters':
16
+ return facet.labels.join(or);
17
+ case 'groupBy':
18
+ return facet.labels.join(' > ');
19
+ case 'custom':
20
+ return facet.label;
21
+ }
22
+ }
23
+ /**
24
+ * A list's search bar: what is typed becomes a search in one of the list's
25
+ * fields, chosen from suggestions; the menu turns the list's filters on and
26
+ * off, groups by its fields, builds a filter, and keeps searches as
27
+ * favourites. Everything chosen shows as a chip, and all of it applies.
28
+ */
29
+ function searchBar(context) {
30
+ const { page, node, doc, el, labels, fill, uid } = context;
31
+ let facets = context.facets;
32
+ const icon = (name) => {
33
+ const drawn = (0, widgets_1.drawIcon)(doc, name, context.icons);
34
+ drawn?.setAttribute('aria-hidden', 'true');
35
+ return drawn ? [drawn] : [];
36
+ };
37
+ function change(next) {
38
+ facets = next;
39
+ drawChips();
40
+ drawPanel();
41
+ context.onChange(facets);
42
+ }
43
+ // ---- the box, its chips and its suggestions -----------------------------------------
44
+ const listId = uid(`${node.id}-suggestions`);
45
+ const panelId = uid(`${node.id}-search-panel`);
46
+ const input = el('input', {
47
+ class: 'fd-search-input',
48
+ role: 'combobox',
49
+ autocomplete: 'off',
50
+ placeholder: labels.search,
51
+ 'aria-label': labels.searchLabel,
52
+ 'aria-autocomplete': 'list',
53
+ 'aria-expanded': 'false',
54
+ 'aria-controls': listId,
55
+ });
56
+ const chips = el('div', { class: 'fd-facets' });
57
+ const offeredList = el('ul', { class: 'fd-search-suggestions', role: 'listbox', id: listId, 'aria-label': labels.searchLabel, hidden: '' });
58
+ const toggle = el('button', { type: 'button', class: 'fd-search-toggle', 'aria-label': labels.searchOptions, 'aria-expanded': 'false', 'aria-controls': panelId });
59
+ let offered = [];
60
+ let active = 0;
61
+ function drawChips() {
62
+ chips.replaceChildren(...facets.map((facet, index) => {
63
+ const text = facetText(facet, labels);
64
+ const remove = el('button', { type: 'button', class: 'fd-facet-remove', 'aria-label': fill(labels.removeFacet, { label: text }) }, '×');
65
+ remove.addEventListener('click', () => {
66
+ change(facets.filter((_, i) => i !== index));
67
+ input.focus();
68
+ });
69
+ const kind = facet.kind === 'groupBy' ? 'layers' : facet.kind === 'field' ? '' : 'filter';
70
+ return el('span', { class: 'fd-facet', 'data-kind': facet.kind }, ...(kind ? icon(kind) : []), el('span', { class: 'fd-facet-text' }, text), remove);
71
+ }));
72
+ }
73
+ function drawOffered() {
74
+ offeredList.replaceChildren(...offered.map((suggestion, index) => {
75
+ const option = el('li', { role: 'option', id: `${listId}-${index}`, 'aria-selected': String(index === active) }, suggestion.label);
76
+ // The box keeps the focus while a suggestion is clicked.
77
+ option.addEventListener('mousedown', (event) => event.preventDefault());
78
+ option.addEventListener('click', () => pick(suggestion));
79
+ return option;
80
+ }));
81
+ offeredList.hidden = offered.length === 0;
82
+ input.setAttribute('aria-expanded', String(!offeredList.hidden));
83
+ if (offeredList.hidden)
84
+ input.removeAttribute('aria-activedescendant');
85
+ else
86
+ input.setAttribute('aria-activedescendant', `${listId}-${active}`);
87
+ }
88
+ function closeOffered() {
89
+ offered = [];
90
+ drawOffered();
91
+ }
92
+ /** A search in a field joins the field's chip, any of its values; the same value twice is once. */
93
+ function pick(suggestion) {
94
+ const value = { op: suggestion.op, value: suggestion.value, label: suggestion.valueLabel };
95
+ const at = facets.findIndex((f) => f.kind === 'field' && f.field === suggestion.field);
96
+ const next = [...facets];
97
+ if (at < 0)
98
+ next.push({ kind: 'field', field: suggestion.field, label: suggestion.fieldLabel, values: [value] });
99
+ else {
100
+ const facet = next[at];
101
+ const known = facet.values.some((v) => v.op === value.op && JSON.stringify(v.value) === JSON.stringify(value.value));
102
+ if (!known)
103
+ next[at] = { ...facet, values: [...facet.values, value] };
104
+ }
105
+ input.value = '';
106
+ closeOffered();
107
+ change(next);
108
+ }
109
+ input.addEventListener('input', () => {
110
+ offered = (0, core_1.suggestions)(input.value, page, node, { searchFor: labels.searchFor });
111
+ active = 0;
112
+ drawOffered();
113
+ });
114
+ input.addEventListener('blur', closeOffered);
115
+ input.addEventListener('keydown', (event) => {
116
+ if (event.isComposing)
117
+ return;
118
+ if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && offered.length) {
119
+ event.preventDefault();
120
+ active = (active + (event.key === 'ArrowDown' ? 1 : offered.length - 1)) % offered.length;
121
+ drawOffered();
122
+ }
123
+ else if (event.key === 'Enter') {
124
+ // Never the form's Enter: a list has nothing to send.
125
+ event.preventDefault();
126
+ if (offered.length)
127
+ pick(offered[active]);
128
+ }
129
+ else if (event.key === 'Backspace' && !input.value && facets.length) {
130
+ change(facets.slice(0, -1));
131
+ }
132
+ else if (event.key === 'Escape' && !offeredList.hidden) {
133
+ event.preventDefault();
134
+ closeOffered();
135
+ }
136
+ });
137
+ // ---- the menu: filters, group by, favourites ---------------------------------------
138
+ const heading = (iconName, text, id) => el('div', { class: 'fd-search-heading', id }, ...icon(iconName), text);
139
+ const toggleIn = (kind, key) => {
140
+ const at = facets.findIndex((f) => f.kind === kind);
141
+ const now = at < 0 ? [] : kind === 'filters' ? facets[at].ids : facets[at].fields;
142
+ const keys = now.includes(key) ? now.filter((k) => k !== key) : [...now, key];
143
+ const facet = kind === 'filters'
144
+ ? { kind, ids: keys, labels: keys.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }
145
+ : { kind, fields: keys, labels: keys.map((field) => page.fields[field]?.label ?? field) };
146
+ const next = [...facets];
147
+ if (at < 0)
148
+ next.push(facet);
149
+ else if (keys.length)
150
+ next[at] = facet;
151
+ else
152
+ next.splice(at, 1);
153
+ change(next);
154
+ };
155
+ const filterButtons = (node.filters ?? []).map((filter) => {
156
+ const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-filter': filter.id }, filter.label);
157
+ button.addEventListener('click', () => toggleIn('filters', filter.id));
158
+ return button;
159
+ });
160
+ const groupButtons = (node.groupBy ?? []).map((field) => {
161
+ const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-group': field }, page.fields[field].label);
162
+ button.addEventListener('click', () => toggleIn('groupBy', field));
163
+ return button;
164
+ });
165
+ const custom = (0, custom_filter_1.customFilterPart)({ page, el, labels, add: (facet) => change([...facets, facet]) });
166
+ const favourites = (0, favourites_1.favouritesPart)({ page, el, labels, fill, preferences: context.preferences, current: () => facets, apply: change });
167
+ const group = (kind, iconName, title, ...parts) => el('div', { class: 'fd-search-group', 'data-group-kind': kind, role: 'group', 'aria-labelledby': `${panelId}-${kind}` }, heading(iconName, title, `${panelId}-${kind}`), ...parts);
168
+ const panel = el('div', { class: 'fd-search-panel', id: panelId, hidden: '' }, group('filters', 'filter', labels.filters, ...filterButtons, custom.button, custom.form), ...(groupButtons.length ? [group('groupBy', 'layers', labels.groupBy, ...groupButtons)] : []), group('favourites', 'star', labels.favourites, favourites.list, favourites.none, favourites.open, favourites.form));
169
+ function drawPanel() {
170
+ const ids = facets.find((f) => f.kind === 'filters')?.ids ?? [];
171
+ const fields = facets.find((f) => f.kind === 'groupBy')?.fields ?? [];
172
+ for (const button of filterButtons)
173
+ button.setAttribute('aria-pressed', String(ids.includes(button.dataset['filter'] ?? '')));
174
+ for (const button of groupButtons)
175
+ button.setAttribute('aria-pressed', String(fields.includes(button.dataset['group'] ?? '')));
176
+ }
177
+ function showPanel(open) {
178
+ panel.hidden = !open;
179
+ toggle.setAttribute('aria-expanded', String(open));
180
+ if (open)
181
+ closeOffered();
182
+ }
183
+ toggle.addEventListener('click', () => showPanel(panel.hidden));
184
+ panel.addEventListener('keydown', (event) => {
185
+ if (event.key !== 'Escape')
186
+ return;
187
+ event.preventDefault();
188
+ showPanel(false);
189
+ toggle.focus();
190
+ });
191
+ const element = el('div', { class: 'fd-search' }, el('div', { class: 'fd-search-field' }, ...icon('search'), chips, input, toggle), offeredList, panel);
192
+ // A press anywhere else closes the menu.
193
+ const outside = (event) => {
194
+ if (!panel.hidden && !element.contains(event.target))
195
+ showPanel(false);
196
+ };
197
+ doc.addEventListener('pointerdown', outside);
198
+ drawChips();
199
+ drawPanel();
200
+ return {
201
+ element,
202
+ destroy: () => doc.removeEventListener('pointerdown', outside),
203
+ };
204
+ }
205
+ //# sourceMappingURL=search-bar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-bar.js","sourceRoot":"","sources":["../../../../../libs/viewer/src/lib/search-bar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,201 @@
1
+ import { suggestions } from '@fieldia/core';
2
+ import { drawIcon } from '@fieldia/widgets';
3
+ import { customFilterPart } from './custom-filter.mjs';
4
+ import { favouritesPart } from './favourites.mjs';
5
+ /** A chip's words: a field and the values looked for in it, filters any of which apply, or the fields grouped by. */
6
+ export function facetText(facet, labels) {
7
+ const or = ` ${labels.or} `;
8
+ switch (facet.kind) {
9
+ case 'field':
10
+ return `${facet.label}: ${facet.values.map((v) => v.label).join(or)}`;
11
+ case 'filters':
12
+ return facet.labels.join(or);
13
+ case 'groupBy':
14
+ return facet.labels.join(' > ');
15
+ case 'custom':
16
+ return facet.label;
17
+ }
18
+ }
19
+ /**
20
+ * A list's search bar: what is typed becomes a search in one of the list's
21
+ * fields, chosen from suggestions; the menu turns the list's filters on and
22
+ * off, groups by its fields, builds a filter, and keeps searches as
23
+ * favourites. Everything chosen shows as a chip, and all of it applies.
24
+ */
25
+ export function searchBar(context) {
26
+ const { page, node, doc, el, labels, fill, uid } = context;
27
+ let facets = context.facets;
28
+ const icon = (name) => {
29
+ const drawn = drawIcon(doc, name, context.icons);
30
+ drawn?.setAttribute('aria-hidden', 'true');
31
+ return drawn ? [drawn] : [];
32
+ };
33
+ function change(next) {
34
+ facets = next;
35
+ drawChips();
36
+ drawPanel();
37
+ context.onChange(facets);
38
+ }
39
+ // ---- the box, its chips and its suggestions -----------------------------------------
40
+ const listId = uid(`${node.id}-suggestions`);
41
+ const panelId = uid(`${node.id}-search-panel`);
42
+ const input = el('input', {
43
+ class: 'fd-search-input',
44
+ role: 'combobox',
45
+ autocomplete: 'off',
46
+ placeholder: labels.search,
47
+ 'aria-label': labels.searchLabel,
48
+ 'aria-autocomplete': 'list',
49
+ 'aria-expanded': 'false',
50
+ 'aria-controls': listId,
51
+ });
52
+ const chips = el('div', { class: 'fd-facets' });
53
+ const offeredList = el('ul', { class: 'fd-search-suggestions', role: 'listbox', id: listId, 'aria-label': labels.searchLabel, hidden: '' });
54
+ const toggle = el('button', { type: 'button', class: 'fd-search-toggle', 'aria-label': labels.searchOptions, 'aria-expanded': 'false', 'aria-controls': panelId });
55
+ let offered = [];
56
+ let active = 0;
57
+ function drawChips() {
58
+ chips.replaceChildren(...facets.map((facet, index) => {
59
+ const text = facetText(facet, labels);
60
+ const remove = el('button', { type: 'button', class: 'fd-facet-remove', 'aria-label': fill(labels.removeFacet, { label: text }) }, '×');
61
+ remove.addEventListener('click', () => {
62
+ change(facets.filter((_, i) => i !== index));
63
+ input.focus();
64
+ });
65
+ const kind = facet.kind === 'groupBy' ? 'layers' : facet.kind === 'field' ? '' : 'filter';
66
+ return el('span', { class: 'fd-facet', 'data-kind': facet.kind }, ...(kind ? icon(kind) : []), el('span', { class: 'fd-facet-text' }, text), remove);
67
+ }));
68
+ }
69
+ function drawOffered() {
70
+ offeredList.replaceChildren(...offered.map((suggestion, index) => {
71
+ const option = el('li', { role: 'option', id: `${listId}-${index}`, 'aria-selected': String(index === active) }, suggestion.label);
72
+ // The box keeps the focus while a suggestion is clicked.
73
+ option.addEventListener('mousedown', (event) => event.preventDefault());
74
+ option.addEventListener('click', () => pick(suggestion));
75
+ return option;
76
+ }));
77
+ offeredList.hidden = offered.length === 0;
78
+ input.setAttribute('aria-expanded', String(!offeredList.hidden));
79
+ if (offeredList.hidden)
80
+ input.removeAttribute('aria-activedescendant');
81
+ else
82
+ input.setAttribute('aria-activedescendant', `${listId}-${active}`);
83
+ }
84
+ function closeOffered() {
85
+ offered = [];
86
+ drawOffered();
87
+ }
88
+ /** A search in a field joins the field's chip, any of its values; the same value twice is once. */
89
+ function pick(suggestion) {
90
+ const value = { op: suggestion.op, value: suggestion.value, label: suggestion.valueLabel };
91
+ const at = facets.findIndex((f) => f.kind === 'field' && f.field === suggestion.field);
92
+ const next = [...facets];
93
+ if (at < 0)
94
+ next.push({ kind: 'field', field: suggestion.field, label: suggestion.fieldLabel, values: [value] });
95
+ else {
96
+ const facet = next[at];
97
+ const known = facet.values.some((v) => v.op === value.op && JSON.stringify(v.value) === JSON.stringify(value.value));
98
+ if (!known)
99
+ next[at] = { ...facet, values: [...facet.values, value] };
100
+ }
101
+ input.value = '';
102
+ closeOffered();
103
+ change(next);
104
+ }
105
+ input.addEventListener('input', () => {
106
+ offered = suggestions(input.value, page, node, { searchFor: labels.searchFor });
107
+ active = 0;
108
+ drawOffered();
109
+ });
110
+ input.addEventListener('blur', closeOffered);
111
+ input.addEventListener('keydown', (event) => {
112
+ if (event.isComposing)
113
+ return;
114
+ if ((event.key === 'ArrowDown' || event.key === 'ArrowUp') && offered.length) {
115
+ event.preventDefault();
116
+ active = (active + (event.key === 'ArrowDown' ? 1 : offered.length - 1)) % offered.length;
117
+ drawOffered();
118
+ }
119
+ else if (event.key === 'Enter') {
120
+ // Never the form's Enter: a list has nothing to send.
121
+ event.preventDefault();
122
+ if (offered.length)
123
+ pick(offered[active]);
124
+ }
125
+ else if (event.key === 'Backspace' && !input.value && facets.length) {
126
+ change(facets.slice(0, -1));
127
+ }
128
+ else if (event.key === 'Escape' && !offeredList.hidden) {
129
+ event.preventDefault();
130
+ closeOffered();
131
+ }
132
+ });
133
+ // ---- the menu: filters, group by, favourites ---------------------------------------
134
+ const heading = (iconName, text, id) => el('div', { class: 'fd-search-heading', id }, ...icon(iconName), text);
135
+ const toggleIn = (kind, key) => {
136
+ const at = facets.findIndex((f) => f.kind === kind);
137
+ const now = at < 0 ? [] : kind === 'filters' ? facets[at].ids : facets[at].fields;
138
+ const keys = now.includes(key) ? now.filter((k) => k !== key) : [...now, key];
139
+ const facet = kind === 'filters'
140
+ ? { kind, ids: keys, labels: keys.map((id) => node.filters?.find((f) => f.id === id)?.label ?? id) }
141
+ : { kind, fields: keys, labels: keys.map((field) => page.fields[field]?.label ?? field) };
142
+ const next = [...facets];
143
+ if (at < 0)
144
+ next.push(facet);
145
+ else if (keys.length)
146
+ next[at] = facet;
147
+ else
148
+ next.splice(at, 1);
149
+ change(next);
150
+ };
151
+ const filterButtons = (node.filters ?? []).map((filter) => {
152
+ const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-filter': filter.id }, filter.label);
153
+ button.addEventListener('click', () => toggleIn('filters', filter.id));
154
+ return button;
155
+ });
156
+ const groupButtons = (node.groupBy ?? []).map((field) => {
157
+ const button = el('button', { type: 'button', class: 'fd-search-option', 'aria-pressed': 'false', 'data-group': field }, page.fields[field].label);
158
+ button.addEventListener('click', () => toggleIn('groupBy', field));
159
+ return button;
160
+ });
161
+ const custom = customFilterPart({ page, el, labels, add: (facet) => change([...facets, facet]) });
162
+ const favourites = favouritesPart({ page, el, labels, fill, preferences: context.preferences, current: () => facets, apply: change });
163
+ const group = (kind, iconName, title, ...parts) => el('div', { class: 'fd-search-group', 'data-group-kind': kind, role: 'group', 'aria-labelledby': `${panelId}-${kind}` }, heading(iconName, title, `${panelId}-${kind}`), ...parts);
164
+ const panel = el('div', { class: 'fd-search-panel', id: panelId, hidden: '' }, group('filters', 'filter', labels.filters, ...filterButtons, custom.button, custom.form), ...(groupButtons.length ? [group('groupBy', 'layers', labels.groupBy, ...groupButtons)] : []), group('favourites', 'star', labels.favourites, favourites.list, favourites.none, favourites.open, favourites.form));
165
+ function drawPanel() {
166
+ const ids = facets.find((f) => f.kind === 'filters')?.ids ?? [];
167
+ const fields = facets.find((f) => f.kind === 'groupBy')?.fields ?? [];
168
+ for (const button of filterButtons)
169
+ button.setAttribute('aria-pressed', String(ids.includes(button.dataset['filter'] ?? '')));
170
+ for (const button of groupButtons)
171
+ button.setAttribute('aria-pressed', String(fields.includes(button.dataset['group'] ?? '')));
172
+ }
173
+ function showPanel(open) {
174
+ panel.hidden = !open;
175
+ toggle.setAttribute('aria-expanded', String(open));
176
+ if (open)
177
+ closeOffered();
178
+ }
179
+ toggle.addEventListener('click', () => showPanel(panel.hidden));
180
+ panel.addEventListener('keydown', (event) => {
181
+ if (event.key !== 'Escape')
182
+ return;
183
+ event.preventDefault();
184
+ showPanel(false);
185
+ toggle.focus();
186
+ });
187
+ const element = el('div', { class: 'fd-search' }, el('div', { class: 'fd-search-field' }, ...icon('search'), chips, input, toggle), offeredList, panel);
188
+ // A press anywhere else closes the menu.
189
+ const outside = (event) => {
190
+ if (!panel.hidden && !element.contains(event.target))
191
+ showPanel(false);
192
+ };
193
+ doc.addEventListener('pointerdown', outside);
194
+ drawChips();
195
+ drawPanel();
196
+ return {
197
+ element,
198
+ destroy: () => doc.removeEventListener('pointerdown', outside),
199
+ };
200
+ }
201
+ //# sourceMappingURL=search-bar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-bar.mjs","sourceRoot":"","sources":["../../../../../libs/viewer/src/lib/search-bar.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type Form, type FormOptions, type Page, type Locale } from '@fieldia/core';
1
+ import { type Form, type FormOptions, type Page, type RecordId, type Locale } from '@fieldia/core';
2
2
  import { type IconSet, type PreferenceStore, type WidgetFactory } from '@fieldia/widgets';
3
3
  export type Skin = 'underline' | 'outlined';
4
4
  import { type ViewerLabels } from './labels.mjs';
@@ -59,6 +59,8 @@ export interface ViewerOptions extends Omit<FormOptions, 'page'> {
59
59
  * key: every word of the page goes through it. Record data never does.
60
60
  */
61
61
  translate?: (text: string) => string;
62
+ /** A list page: a row was opened, by a click or by Enter. The app shows the record. */
63
+ onOpenRecord?: (id: RecordId) => void;
62
64
  }
63
65
  export interface ViewerHandle {
64
66
  readonly form: Form;
@@ -1,4 +1,4 @@
1
- import { type Form, type FormOptions, type Page, type Locale } from '@fieldia/core';
1
+ import { type Form, type FormOptions, type Page, type RecordId, type Locale } from '@fieldia/core';
2
2
  import { type IconSet, type PreferenceStore, type WidgetFactory } from '@fieldia/widgets';
3
3
  export type Skin = 'underline' | 'outlined';
4
4
  import { type ViewerLabels } from './labels';
@@ -59,6 +59,8 @@ export interface ViewerOptions extends Omit<FormOptions, 'page'> {
59
59
  * key: every word of the page goes through it. Record data never does.
60
60
  */
61
61
  translate?: (text: string) => string;
62
+ /** A list page: a row was opened, by a click or by Enter. The app shows the record. */
63
+ onOpenRecord?: (id: RecordId) => void;
62
64
  }
63
65
  export interface ViewerHandle {
64
66
  readonly form: Form;
package/src/lib/viewer.js CHANGED
@@ -5,6 +5,7 @@ exports.mountViewer = mountViewer;
5
5
  const core_1 = require("@fieldia/core");
6
6
  const widgets_1 = require("@fieldia/widgets");
7
7
  const related_1 = require("./related");
8
+ const list_1 = require("./list");
8
9
  const labels_1 = require("./labels");
9
10
  var labels_2 = require("./labels");
10
11
  Object.defineProperty(exports, "VIEWER_LABELS", { enumerable: true, get: function () { return labels_2.VIEWER_LABELS; } });
@@ -660,6 +661,27 @@ function mountViewer(host, options) {
660
661
  body = wizardLayout(layout);
661
662
  else if (layout.type === 'tabs')
662
663
  body = sectionsLayout({ id: `${layout.id}-page`, children: [layout] });
664
+ else if (layout.type === 'list') {
665
+ const list = (0, list_1.listView)({
666
+ page,
667
+ node: layout,
668
+ form,
669
+ dataSource: options.dataSource,
670
+ doc,
671
+ el,
672
+ labels,
673
+ locale,
674
+ fill,
675
+ confirm,
676
+ withIcon,
677
+ uid,
678
+ icons: options.icons,
679
+ preferences,
680
+ onOpenRecord: options.onOpenRecord,
681
+ });
682
+ cleanups.push(list.destroy);
683
+ body = list.element;
684
+ }
663
685
  else
664
686
  body = sectionsLayout(layout);
665
687
  const head = layout.type === 'sheet' ? null : pageHead();
@@ -676,6 +698,8 @@ function mountViewer(host, options) {
676
698
  }
677
699
  root.addEventListener('submit', (event) => {
678
700
  event.preventDefault();
701
+ if (layout.type === 'list')
702
+ return;
679
703
  if (wizardForward)
680
704
  void wizardForward();
681
705
  else
@@ -702,7 +726,8 @@ function mountViewer(host, options) {
702
726
  return null;
703
727
  }
704
728
  root.addEventListener('keydown', (event) => {
705
- if (event.isComposing || event.key !== 'Enter')
729
+ // A list has nothing to save, and its rows keep their own keys.
730
+ if (event.isComposing || event.key !== 'Enter' || layout.type === 'list')
706
731
  return;
707
732
  // An app's own content in a slot, such as a chatter's composer, keeps its keys.
708
733
  if (event.target.closest('.fd-slot'))