@fieldia/widgets 0.9.1 → 0.10.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 (211) hide show
  1. package/package.json +2 -2
  2. package/src/index.d.mts +2 -0
  3. package/src/index.d.ts +2 -0
  4. package/src/index.js +4 -0
  5. package/src/index.js.map +1 -1
  6. package/src/index.mjs +2 -0
  7. package/src/index.mjs.map +1 -1
  8. package/src/lib/address.d.mts +4 -0
  9. package/src/lib/address.d.ts +4 -0
  10. package/src/lib/address.js +105 -0
  11. package/src/lib/address.js.map +1 -0
  12. package/src/lib/address.mjs +100 -0
  13. package/src/lib/address.mjs.map +1 -0
  14. package/src/lib/cards.d.mts +2 -0
  15. package/src/lib/cards.d.ts +2 -0
  16. package/src/lib/cards.js +152 -0
  17. package/src/lib/cards.js.map +1 -0
  18. package/src/lib/cards.mjs +148 -0
  19. package/src/lib/cards.mjs.map +1 -0
  20. package/src/lib/choice-images.d.mts +2 -0
  21. package/src/lib/choice-images.d.ts +2 -0
  22. package/src/lib/choice-images.js +99 -0
  23. package/src/lib/choice-images.js.map +1 -0
  24. package/src/lib/choice-images.mjs +95 -0
  25. package/src/lib/choice-images.mjs.map +1 -0
  26. package/src/lib/choice-rules.d.mts +22 -0
  27. package/src/lib/choice-rules.d.ts +22 -0
  28. package/src/lib/choice-rules.js +46 -0
  29. package/src/lib/choice-rules.js.map +1 -0
  30. package/src/lib/choice-rules.mjs +41 -0
  31. package/src/lib/choice-rules.mjs.map +1 -0
  32. package/src/lib/choice-tags.d.mts +17 -0
  33. package/src/lib/choice-tags.d.ts +17 -0
  34. package/src/lib/choice-tags.js +187 -0
  35. package/src/lib/choice-tags.js.map +1 -0
  36. package/src/lib/choice-tags.mjs +182 -0
  37. package/src/lib/choice-tags.mjs.map +1 -0
  38. package/src/lib/choices-from.d.mts +8 -0
  39. package/src/lib/choices-from.d.ts +8 -0
  40. package/src/lib/choices-from.js +63 -0
  41. package/src/lib/choices-from.js.map +1 -0
  42. package/src/lib/choices-from.mjs +60 -0
  43. package/src/lib/choices-from.mjs.map +1 -0
  44. package/src/lib/display.js +4 -3
  45. package/src/lib/display.js.map +1 -1
  46. package/src/lib/display.mjs +5 -4
  47. package/src/lib/display.mjs.map +1 -1
  48. package/src/lib/extras.js +8 -4
  49. package/src/lib/extras.js.map +1 -1
  50. package/src/lib/extras.mjs +8 -4
  51. package/src/lib/extras.mjs.map +1 -1
  52. package/src/lib/files.d.mts +2 -0
  53. package/src/lib/files.d.ts +2 -0
  54. package/src/lib/files.js +180 -80
  55. package/src/lib/files.js.map +1 -1
  56. package/src/lib/files.mjs +179 -80
  57. package/src/lib/files.mjs.map +1 -1
  58. package/src/lib/focus-trap.d.mts +7 -0
  59. package/src/lib/focus-trap.d.ts +7 -0
  60. package/src/lib/focus-trap.js +26 -0
  61. package/src/lib/focus-trap.js.map +1 -0
  62. package/src/lib/focus-trap.mjs +23 -0
  63. package/src/lib/focus-trap.mjs.map +1 -0
  64. package/src/lib/icons.js +1 -0
  65. package/src/lib/icons.js.map +1 -1
  66. package/src/lib/icons.mjs +1 -0
  67. package/src/lib/icons.mjs.map +1 -1
  68. package/src/lib/kind-parts.d.mts +56 -0
  69. package/src/lib/kind-parts.d.ts +56 -0
  70. package/src/lib/kind-parts.js +121 -0
  71. package/src/lib/kind-parts.js.map +1 -0
  72. package/src/lib/kind-parts.mjs +107 -0
  73. package/src/lib/kind-parts.mjs.map +1 -0
  74. package/src/lib/labels.d.mts +80 -0
  75. package/src/lib/labels.d.ts +80 -0
  76. package/src/lib/labels.js +107 -189
  77. package/src/lib/labels.js.map +1 -1
  78. package/src/lib/labels.mjs +107 -189
  79. package/src/lib/labels.mjs.map +1 -1
  80. package/src/lib/layout-styles.d.mts +11 -0
  81. package/src/lib/layout-styles.d.ts +11 -0
  82. package/src/lib/layout-styles.js +176 -0
  83. package/src/lib/layout-styles.js.map +1 -0
  84. package/src/lib/layout-styles.mjs +173 -0
  85. package/src/lib/layout-styles.mjs.map +1 -0
  86. package/src/lib/limits.d.mts +20 -0
  87. package/src/lib/limits.d.ts +20 -0
  88. package/src/lib/limits.js +71 -0
  89. package/src/lib/limits.js.map +1 -0
  90. package/src/lib/limits.mjs +66 -0
  91. package/src/lib/limits.mjs.map +1 -0
  92. package/src/lib/line-moves.d.mts +8 -0
  93. package/src/lib/line-moves.d.ts +8 -0
  94. package/src/lib/line-moves.js +20 -0
  95. package/src/lib/line-moves.js.map +1 -0
  96. package/src/lib/line-moves.mjs +17 -0
  97. package/src/lib/line-moves.mjs.map +1 -0
  98. package/src/lib/lines.js +85 -7
  99. package/src/lib/lines.js.map +1 -1
  100. package/src/lib/lines.mjs +86 -8
  101. package/src/lib/lines.mjs.map +1 -1
  102. package/src/lib/locales/all.d.mts +8 -0
  103. package/src/lib/locales/all.d.ts +8 -0
  104. package/src/lib/locales/all.js +13 -0
  105. package/src/lib/locales/all.js.map +1 -0
  106. package/src/lib/locales/all.mjs +10 -0
  107. package/src/lib/locales/all.mjs.map +1 -0
  108. package/src/lib/locales/ar.d.mts +3 -0
  109. package/src/lib/locales/ar.d.ts +3 -0
  110. package/src/lib/locales/ar.js +104 -0
  111. package/src/lib/locales/ar.js.map +1 -0
  112. package/src/lib/locales/ar.mjs +101 -0
  113. package/src/lib/locales/ar.mjs.map +1 -0
  114. package/src/lib/locales/de.d.mts +3 -0
  115. package/src/lib/locales/de.d.ts +3 -0
  116. package/src/lib/locales/de.js +104 -0
  117. package/src/lib/locales/de.js.map +1 -0
  118. package/src/lib/locales/de.mjs +101 -0
  119. package/src/lib/locales/de.mjs.map +1 -0
  120. package/src/lib/locales/fr.d.mts +3 -0
  121. package/src/lib/locales/fr.d.ts +3 -0
  122. package/src/lib/locales/fr.js +104 -0
  123. package/src/lib/locales/fr.js.map +1 -0
  124. package/src/lib/locales/fr.mjs +101 -0
  125. package/src/lib/locales/fr.mjs.map +1 -0
  126. package/src/lib/matrix.d.mts +10 -0
  127. package/src/lib/matrix.d.ts +10 -0
  128. package/src/lib/matrix.js +86 -0
  129. package/src/lib/matrix.js.map +1 -0
  130. package/src/lib/matrix.mjs +82 -0
  131. package/src/lib/matrix.mjs.map +1 -0
  132. package/src/lib/numbers.d.mts +7 -0
  133. package/src/lib/numbers.d.ts +7 -0
  134. package/src/lib/numbers.js +15 -0
  135. package/src/lib/numbers.js.map +1 -1
  136. package/src/lib/numbers.mjs +14 -0
  137. package/src/lib/numbers.mjs.map +1 -1
  138. package/src/lib/progress.js +8 -4
  139. package/src/lib/progress.js.map +1 -1
  140. package/src/lib/progress.mjs +8 -4
  141. package/src/lib/progress.mjs.map +1 -1
  142. package/src/lib/ranking.d.mts +2 -0
  143. package/src/lib/ranking.d.ts +2 -0
  144. package/src/lib/ranking.js +172 -0
  145. package/src/lib/ranking.js.map +1 -0
  146. package/src/lib/ranking.mjs +168 -0
  147. package/src/lib/ranking.mjs.map +1 -0
  148. package/src/lib/relations.d.mts +1 -1
  149. package/src/lib/relations.d.ts +1 -1
  150. package/src/lib/relations.js +43 -18
  151. package/src/lib/relations.js.map +1 -1
  152. package/src/lib/relations.mjs +43 -18
  153. package/src/lib/relations.mjs.map +1 -1
  154. package/src/lib/shuffle.d.mts +7 -0
  155. package/src/lib/shuffle.d.ts +7 -0
  156. package/src/lib/shuffle.js +60 -0
  157. package/src/lib/shuffle.js.map +1 -0
  158. package/src/lib/shuffle.mjs +57 -0
  159. package/src/lib/shuffle.mjs.map +1 -0
  160. package/src/lib/signature.d.mts +2 -0
  161. package/src/lib/signature.d.ts +2 -0
  162. package/src/lib/signature.js +223 -0
  163. package/src/lib/signature.js.map +1 -0
  164. package/src/lib/signature.mjs +219 -0
  165. package/src/lib/signature.mjs.map +1 -0
  166. package/src/lib/slider.d.mts +10 -0
  167. package/src/lib/slider.d.ts +10 -0
  168. package/src/lib/slider.js +57 -0
  169. package/src/lib/slider.js.map +1 -0
  170. package/src/lib/slider.mjs +53 -0
  171. package/src/lib/slider.mjs.map +1 -0
  172. package/src/lib/styles-choices.d.mts +7 -0
  173. package/src/lib/styles-choices.d.ts +7 -0
  174. package/src/lib/styles-choices.js +47 -0
  175. package/src/lib/styles-choices.js.map +1 -0
  176. package/src/lib/styles-choices.mjs +44 -0
  177. package/src/lib/styles-choices.mjs.map +1 -0
  178. package/src/lib/styles-inputs.d.mts +9 -0
  179. package/src/lib/styles-inputs.d.ts +9 -0
  180. package/src/lib/styles-inputs.js +41 -0
  181. package/src/lib/styles-inputs.js.map +1 -0
  182. package/src/lib/styles-inputs.mjs +38 -0
  183. package/src/lib/styles-inputs.mjs.map +1 -0
  184. package/src/lib/styles-kinds.d.mts +7 -0
  185. package/src/lib/styles-kinds.d.ts +7 -0
  186. package/src/lib/styles-kinds.js +119 -0
  187. package/src/lib/styles-kinds.js.map +1 -0
  188. package/src/lib/styles-kinds.mjs +116 -0
  189. package/src/lib/styles-kinds.mjs.map +1 -0
  190. package/src/lib/styles.d.mts +2 -14
  191. package/src/lib/styles.d.ts +2 -14
  192. package/src/lib/styles.js +180 -66
  193. package/src/lib/styles.js.map +1 -1
  194. package/src/lib/styles.mjs +180 -66
  195. package/src/lib/styles.mjs.map +1 -1
  196. package/src/lib/units.d.mts +10 -0
  197. package/src/lib/units.d.ts +10 -0
  198. package/src/lib/units.js +19 -0
  199. package/src/lib/units.js.map +1 -0
  200. package/src/lib/units.mjs +16 -0
  201. package/src/lib/units.mjs.map +1 -0
  202. package/src/lib/widgets.js +215 -57
  203. package/src/lib/widgets.js.map +1 -1
  204. package/src/lib/widgets.mjs +215 -57
  205. package/src/lib/widgets.mjs.map +1 -1
  206. package/src/lib/yes-no.d.mts +9 -0
  207. package/src/lib/yes-no.d.ts +9 -0
  208. package/src/lib/yes-no.js +58 -0
  209. package/src/lib/yes-no.js.map +1 -0
  210. package/src/lib/yes-no.mjs +54 -0
  211. package/src/lib/yes-no.mjs.map +1 -0
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rankingWidget = void 0;
4
+ const kind_parts_1 = require("./kind-parts");
5
+ const shuffle_1 = require("./shuffle");
6
+ /** How far the pointer goes before a press becomes a drag. */
7
+ const SLOP = 4;
8
+ const rankingWidget = ({ form, name, field, node, id, document, labels, locale }) => {
9
+ const words = (0, kind_parts_1.wordsFor)(labels, locale);
10
+ const make = (0, kind_parts_1.maker)(document);
11
+ const options = (0, shuffle_1.shownOptions)(field.type === 'selection' ? field.options : [], form, name, node);
12
+ const list = make('ol', { class: 'fd-rank-list' });
13
+ const voice = (0, kind_parts_1.announcer)(make);
14
+ const most = node.options?.['top'];
15
+ const top = typeof most === 'number' && most >= 1 && most < options.length ? Math.floor(most) : 0;
16
+ const pool = make('div', { class: 'fd-rank-pool' });
17
+ const keepAsShown = make('button', { type: 'button', class: 'fd-button fd-rank-keep' }, words.keepOrder);
18
+ keepAsShown.addEventListener('click', () => form.setValue(name, shown.map((item) => item.option.value)));
19
+ const element = make('div', { id, class: 'fd-ranking', role: 'group' }, ...(top ? [make('div', { class: 'fd-choice-limit' }, (0, kind_parts_1.fillIn)(words.upTo, { n: top })), pool, list] : [list, keepAsShown]), voice.element);
20
+ const items = options.map((option) => {
21
+ const label = option.label;
22
+ const place = make('span', { class: 'fd-rank-place', 'aria-hidden': 'true' });
23
+ const up = make('button', { type: 'button', class: 'fd-rank-move fd-rank-up', 'aria-label': (0, kind_parts_1.fillIn)(words.moveUp, { label }) }, '↑');
24
+ const down = make('button', { type: 'button', class: 'fd-rank-move fd-rank-down', 'aria-label': (0, kind_parts_1.fillIn)(words.moveDown, { label }) }, '↓');
25
+ const grip = make('span', { class: 'fd-rank-grip', 'aria-hidden': 'true' });
26
+ const tools = make('span', { class: 'fd-rank-tools' }, up, down);
27
+ const li = make('li', { class: 'fd-rank-item', 'data-value': String(option.value) }, grip, place, make('span', { class: 'fd-rank-words' }, label), tools);
28
+ const item = { option, element: li, place, up, down };
29
+ if (top) {
30
+ // Picked from the rest to the end of those ranked; its × takes it out again.
31
+ const pick = make('button', { type: 'button', class: 'fd-rank-pick' }, label);
32
+ pick.addEventListener('click', () => !readonly && shown.length < top && keep([...shown, item], item));
33
+ const out = make('button', { type: 'button', class: 'fd-rank-move fd-rank-out', 'aria-label': (0, kind_parts_1.fillIn)(words.remove, { name: label }) }, '×');
34
+ out.addEventListener('click', () => {
35
+ voice.say((0, kind_parts_1.fillIn)(words.removed, { name: label }));
36
+ form.setValue(name, shown.filter((other) => other !== item).map((other) => other.option.value));
37
+ });
38
+ tools.append(out);
39
+ pool.append(pick);
40
+ item.pick = pick;
41
+ }
42
+ up.addEventListener('click', () => move(item, -1, 'up'));
43
+ down.addEventListener('click', () => move(item, 1, 'down'));
44
+ li.addEventListener('pointerdown', (event) => press(item, event));
45
+ return item;
46
+ });
47
+ let readonly = false;
48
+ /** The lines in the order shown now. */
49
+ let shown = [...items];
50
+ /** The button to give the cursor back to once a move has been drawn. */
51
+ let refocus = null;
52
+ function draw(next) {
53
+ shown = next;
54
+ next.forEach((item, i) => {
55
+ if (list.children[i] !== item.element)
56
+ list.insertBefore(item.element, list.children[i] ?? null);
57
+ item.place.textContent = String(i + 1);
58
+ item.up.disabled = i === 0;
59
+ item.down.disabled = i === next.length - 1;
60
+ });
61
+ // Ranking the top few, those not ranked wait among the rest.
62
+ while (list.children.length > next.length)
63
+ list.lastElementChild?.remove();
64
+ }
65
+ /** Keep the order as the answer, and say where the line went. */
66
+ function keep(next, moved) {
67
+ voice.say((0, kind_parts_1.fillIn)(words.movedTo, { label: moved.option.label, n: next.indexOf(moved) + 1, total: next.length }));
68
+ form.setValue(name, next.map((item) => item.option.value));
69
+ }
70
+ function move(item, step, which) {
71
+ const from = shown.indexOf(item);
72
+ const to = from + step;
73
+ if (readonly || to < 0 || to >= shown.length)
74
+ return;
75
+ const next = [...shown];
76
+ next.splice(from, 1);
77
+ next.splice(to, 0, item);
78
+ const holding = item.element.contains(document.activeElement);
79
+ // At an end, the button that moved it is no use: the cursor goes to the other.
80
+ refocus = holding ? { item, which: (which === 'up' && to === 0) || (which === 'down' && to === next.length - 1) ? (which === 'up' ? 'down' : 'up') : which } : null;
81
+ keep(next, item);
82
+ giveBackFocus();
83
+ }
84
+ function giveBackFocus() {
85
+ if (!refocus)
86
+ return;
87
+ const { item, which } = refocus;
88
+ refocus = null;
89
+ item[which].focus();
90
+ }
91
+ list.addEventListener('keydown', (event) => {
92
+ if (readonly || !event.altKey || (event.key !== 'ArrowUp' && event.key !== 'ArrowDown'))
93
+ return;
94
+ const item = items.find((i) => i.element.contains(event.target));
95
+ if (!item)
96
+ return;
97
+ event.preventDefault();
98
+ move(item, event.key === 'ArrowUp' ? -1 : 1, event.key === 'ArrowUp' ? 'up' : 'down');
99
+ });
100
+ // Dragging: the line follows the pointer from place to place; the order is kept when it is let go.
101
+ function press(item, event) {
102
+ if (readonly || event.button !== 0 || event.target.closest('button'))
103
+ return;
104
+ // On a touch screen only the grip drags: anywhere else the page scrolls.
105
+ if (event.pointerType === 'touch' && !event.target.closest('.fd-rank-grip'))
106
+ return;
107
+ const startY = event.clientY;
108
+ const before = [...shown];
109
+ let lifted = false;
110
+ item.element.setPointerCapture?.(event.pointerId);
111
+ const onMove = (e) => {
112
+ if (!lifted && Math.abs(e.clientY - startY) < SLOP)
113
+ return;
114
+ if (!lifted) {
115
+ lifted = true;
116
+ item.element.classList.add('fd-rank-lifted');
117
+ }
118
+ e.preventDefault();
119
+ // Its place: after every other line whose middle the pointer has passed.
120
+ const others = shown.filter((other) => other !== item);
121
+ const at = others.filter((other) => {
122
+ const box = other.element.getBoundingClientRect();
123
+ return box.top + box.height / 2 < e.clientY;
124
+ }).length;
125
+ if (shown.indexOf(item) !== at)
126
+ draw([...others.slice(0, at), item, ...others.slice(at)]);
127
+ };
128
+ const onEnd = () => {
129
+ item.element.removeEventListener('pointermove', onMove);
130
+ item.element.removeEventListener('pointerup', onEnd);
131
+ item.element.removeEventListener('pointercancel', onEnd);
132
+ item.element.classList.remove('fd-rank-lifted');
133
+ if (shown.some((other, i) => other !== before[i]))
134
+ keep(shown, item);
135
+ };
136
+ item.element.addEventListener('pointermove', onMove);
137
+ item.element.addEventListener('pointerup', onEnd);
138
+ item.element.addEventListener('pointercancel', onEnd);
139
+ }
140
+ /** The order a value says: its options first, in its order, then those it leaves out, as they were shown. */
141
+ function orderOf(value) {
142
+ const named = (Array.isArray(value) ? value : []).map((v) => items.find((item) => item.option.value === v)).filter((item) => !!item);
143
+ if (top)
144
+ return named.slice(0, top);
145
+ return Array.isArray(value) ? [...new Set([...named, ...shown])] : shown;
146
+ }
147
+ draw(top ? [] : shown);
148
+ return {
149
+ element,
150
+ focus: () => (items.find((item) => item.pick && !item.pick.hidden && !item.pick.disabled)?.pick ?? (shown[0]?.down.disabled ? shown[0]?.up : shown[0]?.down))?.focus(),
151
+ update(state) {
152
+ readonly = state.readonly;
153
+ element.classList.toggle('fd-ranking-locked', readonly);
154
+ const next = orderOf(state.value);
155
+ if (next.length !== shown.length || next.some((item, i) => item !== shown[i]) || (!top && !list.children.length))
156
+ draw(next);
157
+ for (const item of items) {
158
+ item.up.hidden = item.down.hidden = readonly;
159
+ if (item.pick) {
160
+ item.pick.hidden = shown.includes(item);
161
+ item.pick.disabled = readonly || shown.length >= top;
162
+ item.element.querySelector('.fd-rank-out').hidden = readonly;
163
+ }
164
+ }
165
+ keepAsShown.hidden = readonly || (Array.isArray(state.value) && state.value.length > 0);
166
+ giveBackFocus();
167
+ (0, kind_parts_1.describeState)(element, state);
168
+ },
169
+ };
170
+ };
171
+ exports.rankingWidget = rankingWidget;
172
+ //# sourceMappingURL=ranking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranking.js","sourceRoot":"","sources":["../../../../../libs/widgets/src/lib/ranking.ts"],"names":[],"mappings":";;;AACA,6CAAiF;AACjF,uCAAyC;AA0BzC,8DAA8D;AAC9D,MAAM,IAAI,GAAG,CAAC,CAAC;AAER,MAAM,aAAa,GAAkB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;IACxG,MAAM,KAAK,GAAG,IAAA,qBAAQ,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,IAAA,kBAAK,EAAC,QAAQ,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAa,IAAA,sBAAY,EAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1G,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,IAAA,sBAAS,EAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClG,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,wBAAwB,EAAE,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACzG,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACzG,MAAM,OAAO,GAAG,IAAI,CAClB,KAAK,EACL,EAAE,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,EAC1C,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,IAAA,mBAAM,EAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,EACxH,KAAK,CAAC,OAAO,CACd,CAAC;IAEF,MAAM,KAAK,GAAW,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9E,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,yBAAyB,EAAE,YAAY,EAAE,IAAA,mBAAM,EAAC,KAAK,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QACpI,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,2BAA2B,EAAE,YAAY,EAAE,IAAA,mBAAM,EAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC1I,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5E,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACjE,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1J,MAAM,IAAI,GAAS,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QAC5D,IAAI,GAAG,EAAE,CAAC;YACR,6EAA6E;YAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,KAAK,CAAC,CAAC;YAC9E,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YACtG,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,0BAA0B,EAAE,YAAY,EAAE,IAAA,mBAAM,EAAC,KAAK,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YAC5I,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;gBACjC,KAAK,CAAC,GAAG,CAAC,IAAA,mBAAM,EAAC,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;gBAClD,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAClG,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAClB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;QACD,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5D,EAAE,CAAC,gBAAgB,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,wCAAwC;IACxC,IAAI,KAAK,GAAW,CAAC,GAAG,KAAK,CAAC,CAAC;IAC/B,wEAAwE;IACxE,IAAI,OAAO,GAAgD,IAAI,CAAC;IAEhE,SAAS,IAAI,CAAC,IAAY;QACxB,KAAK,GAAG,IAAI,CAAC;QACb,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO;gBAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;YACjG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,EAAE,CAAC,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QACH,6DAA6D;QAC7D,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC7E,CAAC;IACD,iEAAiE;IACjE,SAAS,IAAI,CAAC,IAAY,EAAE,KAAW;QACrC,KAAK,CAAC,GAAG,CAAC,IAAA,mBAAM,EAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAChH,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,SAAS,IAAI,CAAC,IAAU,EAAE,IAAY,EAAE,KAAoB;QAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;QACvB,IAAI,QAAQ,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,MAAM;YAAE,OAAO;QACrD,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAC9D,+EAA+E;QAC/E,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,KAAK,KAAK,IAAI,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,EAAE,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACpK,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjB,aAAa,EAAE,CAAC;IAClB,CAAC;IACD,SAAS,aAAa;QACpB,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;QAChC,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;QACzC,IAAI,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,CAAC;YAAE,OAAO;QAChG,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAc,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,mGAAmG;IACnG,SAAS,KAAK,CAAC,IAAU,EAAE,KAAmB;QAC5C,IAAI,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAK,KAAK,CAAC,MAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC1F,yEAAyE;QACzE,IAAI,KAAK,CAAC,WAAW,KAAK,OAAO,IAAI,CAAE,KAAK,CAAC,MAAkB,CAAC,OAAO,CAAC,eAAe,CAAC;YAAE,OAAO;QACjG,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC;QAC7B,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;QAC1B,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,CAAC,CAAe,EAAE,EAAE;YACjC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,IAAI;gBAAE,OAAO;YAC3D,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,GAAG,IAAI,CAAC;gBACd,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YAC/C,CAAC;YACD,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,yEAAyE;YACzE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;YACvD,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACjC,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC;gBAClD,OAAO,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;YAC9C,CAAC,CAAC,CAAC,MAAM,CAAC;YACV,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE;gBAAE,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5F,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YACxD,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YACrD,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;YACzD,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;YAChD,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACvE,CAAC,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACrD,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAClD,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC;IAED,6GAA6G;IAC7G,SAAS,OAAO,CAAC,KAAc;QAC7B,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnJ,IAAI,GAAG;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC3E,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO;QACL,OAAO;QACP,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE;QACtK,MAAM,CAAC,KAAK;YACV,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;YAC1B,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAClC,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7H,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;gBAC7C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;oBACxC,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC;oBACpD,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,cAAc,CAAiB,CAAC,MAAM,GAAG,QAAQ,CAAC;gBAChF,CAAC;YACH,CAAC;YACD,WAAW,CAAC,MAAM,GAAG,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACxF,aAAa,EAAE,CAAC;YAChB,IAAA,0BAAa,EAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAChC,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAjKW,QAAA,aAAa,iBAiKxB"}
@@ -0,0 +1,168 @@
1
+ import { announcer, describeState, fillIn, maker, wordsFor } from './kind-parts.mjs';
2
+ import { shownOptions } from './shuffle.mjs';
3
+ /** How far the pointer goes before a press becomes a drag. */
4
+ const SLOP = 4;
5
+ export const rankingWidget = ({ form, name, field, node, id, document, labels, locale }) => {
6
+ const words = wordsFor(labels, locale);
7
+ const make = maker(document);
8
+ const options = shownOptions(field.type === 'selection' ? field.options : [], form, name, node);
9
+ const list = make('ol', { class: 'fd-rank-list' });
10
+ const voice = announcer(make);
11
+ const most = node.options?.['top'];
12
+ const top = typeof most === 'number' && most >= 1 && most < options.length ? Math.floor(most) : 0;
13
+ const pool = make('div', { class: 'fd-rank-pool' });
14
+ const keepAsShown = make('button', { type: 'button', class: 'fd-button fd-rank-keep' }, words.keepOrder);
15
+ keepAsShown.addEventListener('click', () => form.setValue(name, shown.map((item) => item.option.value)));
16
+ const element = make('div', { id, class: 'fd-ranking', role: 'group' }, ...(top ? [make('div', { class: 'fd-choice-limit' }, fillIn(words.upTo, { n: top })), pool, list] : [list, keepAsShown]), voice.element);
17
+ const items = options.map((option) => {
18
+ const label = option.label;
19
+ const place = make('span', { class: 'fd-rank-place', 'aria-hidden': 'true' });
20
+ const up = make('button', { type: 'button', class: 'fd-rank-move fd-rank-up', 'aria-label': fillIn(words.moveUp, { label }) }, '↑');
21
+ const down = make('button', { type: 'button', class: 'fd-rank-move fd-rank-down', 'aria-label': fillIn(words.moveDown, { label }) }, '↓');
22
+ const grip = make('span', { class: 'fd-rank-grip', 'aria-hidden': 'true' });
23
+ const tools = make('span', { class: 'fd-rank-tools' }, up, down);
24
+ const li = make('li', { class: 'fd-rank-item', 'data-value': String(option.value) }, grip, place, make('span', { class: 'fd-rank-words' }, label), tools);
25
+ const item = { option, element: li, place, up, down };
26
+ if (top) {
27
+ // Picked from the rest to the end of those ranked; its × takes it out again.
28
+ const pick = make('button', { type: 'button', class: 'fd-rank-pick' }, label);
29
+ pick.addEventListener('click', () => !readonly && shown.length < top && keep([...shown, item], item));
30
+ const out = make('button', { type: 'button', class: 'fd-rank-move fd-rank-out', 'aria-label': fillIn(words.remove, { name: label }) }, '×');
31
+ out.addEventListener('click', () => {
32
+ voice.say(fillIn(words.removed, { name: label }));
33
+ form.setValue(name, shown.filter((other) => other !== item).map((other) => other.option.value));
34
+ });
35
+ tools.append(out);
36
+ pool.append(pick);
37
+ item.pick = pick;
38
+ }
39
+ up.addEventListener('click', () => move(item, -1, 'up'));
40
+ down.addEventListener('click', () => move(item, 1, 'down'));
41
+ li.addEventListener('pointerdown', (event) => press(item, event));
42
+ return item;
43
+ });
44
+ let readonly = false;
45
+ /** The lines in the order shown now. */
46
+ let shown = [...items];
47
+ /** The button to give the cursor back to once a move has been drawn. */
48
+ let refocus = null;
49
+ function draw(next) {
50
+ shown = next;
51
+ next.forEach((item, i) => {
52
+ if (list.children[i] !== item.element)
53
+ list.insertBefore(item.element, list.children[i] ?? null);
54
+ item.place.textContent = String(i + 1);
55
+ item.up.disabled = i === 0;
56
+ item.down.disabled = i === next.length - 1;
57
+ });
58
+ // Ranking the top few, those not ranked wait among the rest.
59
+ while (list.children.length > next.length)
60
+ list.lastElementChild?.remove();
61
+ }
62
+ /** Keep the order as the answer, and say where the line went. */
63
+ function keep(next, moved) {
64
+ voice.say(fillIn(words.movedTo, { label: moved.option.label, n: next.indexOf(moved) + 1, total: next.length }));
65
+ form.setValue(name, next.map((item) => item.option.value));
66
+ }
67
+ function move(item, step, which) {
68
+ const from = shown.indexOf(item);
69
+ const to = from + step;
70
+ if (readonly || to < 0 || to >= shown.length)
71
+ return;
72
+ const next = [...shown];
73
+ next.splice(from, 1);
74
+ next.splice(to, 0, item);
75
+ const holding = item.element.contains(document.activeElement);
76
+ // At an end, the button that moved it is no use: the cursor goes to the other.
77
+ refocus = holding ? { item, which: (which === 'up' && to === 0) || (which === 'down' && to === next.length - 1) ? (which === 'up' ? 'down' : 'up') : which } : null;
78
+ keep(next, item);
79
+ giveBackFocus();
80
+ }
81
+ function giveBackFocus() {
82
+ if (!refocus)
83
+ return;
84
+ const { item, which } = refocus;
85
+ refocus = null;
86
+ item[which].focus();
87
+ }
88
+ list.addEventListener('keydown', (event) => {
89
+ if (readonly || !event.altKey || (event.key !== 'ArrowUp' && event.key !== 'ArrowDown'))
90
+ return;
91
+ const item = items.find((i) => i.element.contains(event.target));
92
+ if (!item)
93
+ return;
94
+ event.preventDefault();
95
+ move(item, event.key === 'ArrowUp' ? -1 : 1, event.key === 'ArrowUp' ? 'up' : 'down');
96
+ });
97
+ // Dragging: the line follows the pointer from place to place; the order is kept when it is let go.
98
+ function press(item, event) {
99
+ if (readonly || event.button !== 0 || event.target.closest('button'))
100
+ return;
101
+ // On a touch screen only the grip drags: anywhere else the page scrolls.
102
+ if (event.pointerType === 'touch' && !event.target.closest('.fd-rank-grip'))
103
+ return;
104
+ const startY = event.clientY;
105
+ const before = [...shown];
106
+ let lifted = false;
107
+ item.element.setPointerCapture?.(event.pointerId);
108
+ const onMove = (e) => {
109
+ if (!lifted && Math.abs(e.clientY - startY) < SLOP)
110
+ return;
111
+ if (!lifted) {
112
+ lifted = true;
113
+ item.element.classList.add('fd-rank-lifted');
114
+ }
115
+ e.preventDefault();
116
+ // Its place: after every other line whose middle the pointer has passed.
117
+ const others = shown.filter((other) => other !== item);
118
+ const at = others.filter((other) => {
119
+ const box = other.element.getBoundingClientRect();
120
+ return box.top + box.height / 2 < e.clientY;
121
+ }).length;
122
+ if (shown.indexOf(item) !== at)
123
+ draw([...others.slice(0, at), item, ...others.slice(at)]);
124
+ };
125
+ const onEnd = () => {
126
+ item.element.removeEventListener('pointermove', onMove);
127
+ item.element.removeEventListener('pointerup', onEnd);
128
+ item.element.removeEventListener('pointercancel', onEnd);
129
+ item.element.classList.remove('fd-rank-lifted');
130
+ if (shown.some((other, i) => other !== before[i]))
131
+ keep(shown, item);
132
+ };
133
+ item.element.addEventListener('pointermove', onMove);
134
+ item.element.addEventListener('pointerup', onEnd);
135
+ item.element.addEventListener('pointercancel', onEnd);
136
+ }
137
+ /** The order a value says: its options first, in its order, then those it leaves out, as they were shown. */
138
+ function orderOf(value) {
139
+ const named = (Array.isArray(value) ? value : []).map((v) => items.find((item) => item.option.value === v)).filter((item) => !!item);
140
+ if (top)
141
+ return named.slice(0, top);
142
+ return Array.isArray(value) ? [...new Set([...named, ...shown])] : shown;
143
+ }
144
+ draw(top ? [] : shown);
145
+ return {
146
+ element,
147
+ focus: () => (items.find((item) => item.pick && !item.pick.hidden && !item.pick.disabled)?.pick ?? (shown[0]?.down.disabled ? shown[0]?.up : shown[0]?.down))?.focus(),
148
+ update(state) {
149
+ readonly = state.readonly;
150
+ element.classList.toggle('fd-ranking-locked', readonly);
151
+ const next = orderOf(state.value);
152
+ if (next.length !== shown.length || next.some((item, i) => item !== shown[i]) || (!top && !list.children.length))
153
+ draw(next);
154
+ for (const item of items) {
155
+ item.up.hidden = item.down.hidden = readonly;
156
+ if (item.pick) {
157
+ item.pick.hidden = shown.includes(item);
158
+ item.pick.disabled = readonly || shown.length >= top;
159
+ item.element.querySelector('.fd-rank-out').hidden = readonly;
160
+ }
161
+ }
162
+ keepAsShown.hidden = readonly || (Array.isArray(state.value) && state.value.length > 0);
163
+ giveBackFocus();
164
+ describeState(element, state);
165
+ },
166
+ };
167
+ };
168
+ //# sourceMappingURL=ranking.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranking.mjs","sourceRoot":"","sources":["../../../../../libs/widgets/src/lib/ranking.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ export declare const tagsWidget: WidgetFactory;
5
5
  * Free-text tags on a text field, kept as "oak, glass": Enter or a comma adds
6
6
  * what was typed, Backspace in an empty box takes the last one away, and the
7
7
  * node's `options.suggestions` are offered as you type. `options.separator`
8
- * is "," unless set.
8
+ * is "," unless set; with `options.max`, the box goes once there are as many.
9
9
  */
10
10
  export declare const charTagsWidget: WidgetFactory;
11
11
  /** Every record as a checkbox. For short lists: it loads up to 50. */
@@ -5,7 +5,7 @@ export declare const tagsWidget: WidgetFactory;
5
5
  * Free-text tags on a text field, kept as "oak, glass": Enter or a comma adds
6
6
  * what was typed, Backspace in an empty box takes the last one away, and the
7
7
  * node's `options.suggestions` are offered as you type. `options.separator`
8
- * is "," unless set.
8
+ * is "," unless set; with `options.max`, the box goes once there are as many.
9
9
  */
10
10
  export declare const charTagsWidget: WidgetFactory;
11
11
  /** Every record as a checkbox. For short lists: it loads up to 50. */
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.referenceWidget = exports.linkCheckboxesWidget = exports.charTagsWidget = exports.tagsWidget = exports.many2oneWidget = void 0;
4
4
  const labels_1 = require("./labels");
5
+ const kind_parts_1 = require("./kind-parts");
5
6
  /**
6
7
  * Pickers for related records: a search-as-you-type combobox (the ARIA 1.2
7
8
  * combobox pattern), tags for a many2many, and a reference picker. Results
@@ -193,12 +194,13 @@ function combobox(options) {
193
194
  input,
194
195
  setText(text) {
195
196
  shown = text;
196
- if (!editing)
197
+ if (!editing && input.value !== text)
197
198
  input.value = text;
198
199
  },
199
200
  setReadonly(next) {
200
201
  readonly = next;
201
- input.readOnly = next;
202
+ if (input.readOnly !== next)
203
+ input.readOnly = next;
202
204
  if (next)
203
205
  close();
204
206
  },
@@ -270,21 +272,22 @@ const many2oneWidget = ({ form, name, field, node, id, document, labels = labels
270
272
  readonly = state.readonly;
271
273
  box.setText(record?.label ?? '');
272
274
  box.setReadonly(state.readonly);
273
- clear.hidden = !record || state.readonly;
275
+ (0, kind_parts_1.setHidden)(clear, !record || state.readonly);
274
276
  if (open) {
275
- open.hidden = !record;
277
+ (0, kind_parts_1.setHidden)(open, !record);
276
278
  if (record)
277
- open.setAttribute('aria-label', fill(labels.openNamed, { name: record.label }));
279
+ (0, kind_parts_1.setAttr)(open, 'aria-label', fill(labels.openNamed, { name: record.label }));
278
280
  }
279
- box.input.setAttribute('aria-invalid', String(state.invalid));
280
- box.input.setAttribute('aria-required', String(state.required));
281
+ (0, kind_parts_1.setAttr)(box.input, 'aria-invalid', String(state.invalid));
282
+ (0, kind_parts_1.setAttr)(box.input, 'aria-required', String(state.required));
281
283
  if (state.describedBy)
282
- box.input.setAttribute('aria-describedby', state.describedBy);
284
+ (0, kind_parts_1.setAttr)(box.input, 'aria-describedby', state.describedBy);
283
285
  },
284
286
  };
285
287
  };
286
288
  exports.many2oneWidget = many2oneWidget;
287
- const tagsWidget = ({ form, name, node, id, document, labels = labels_1.WIDGET_LABELS.en }) => {
289
+ const tagsWidget = ({ form, name, field, node, id, document, labels = labels_1.WIDGET_LABELS.en, dialogs }) => {
290
+ const relation = field.type === 'many2many' ? field.relation : '';
288
291
  const current = () => form.getState().values[name] ?? [];
289
292
  const element = document.createElement('div');
290
293
  element.className = 'fd-tags';
@@ -295,9 +298,12 @@ const tagsWidget = ({ form, name, node, id, document, labels = labels_1.WIDGET_L
295
298
  document,
296
299
  id,
297
300
  labels,
298
- search: (query) => form.search(name, query),
301
+ // One past what the list shows, besides those chosen, to know whether Search more… has more to find.
302
+ search: (query) => form.search(name, query, SHOWN + 1 + current().length),
303
+ shown: SHOWN,
299
304
  pick: (record) => {
300
- form.setValue(name, [...current(), record]);
305
+ if (!current().some((r) => r.id === record.id))
306
+ form.setValue(name, [...current(), record]);
301
307
  box.input.value = '';
302
308
  },
303
309
  exclude: () => new Set(current().map((record) => record.id)),
@@ -307,7 +313,17 @@ const tagsWidget = ({ form, name, node, id, document, labels = labels_1.WIDGET_L
307
313
  form.setValue(name, records.slice(0, -1));
308
314
  },
309
315
  create: creator(form, name, node),
316
+ // With dialogs: pick from a full list when the short one has no room.
317
+ more: (_typed, overflow) => (dialogs && overflow ? [{ label: labels.searchMore, act: () => dialogs.searchMore({ title: field.label, search: (query, limit) => form.search(name, query, limit) }) }] : []),
310
318
  });
319
+ // A linked record, opened from its tag in a dialog where the app can show it; a new name it is saved with follows here.
320
+ const open = dialogs && dialogs.canOpen(relation)
321
+ ? async (record) => {
322
+ const saved = await dialogs.openRecord(relation, { recordId: record.id, title: record.label });
323
+ if (saved && saved.label !== record.label)
324
+ form.setValue(name, current().map((r) => (r.id === record.id ? saved : r)));
325
+ }
326
+ : undefined;
311
327
  element.append(chips, box.element);
312
328
  let readonly = false;
313
329
  let drawn = '';
@@ -327,21 +343,26 @@ const tagsWidget = ({ form, name, node, id, document, labels = labels_1.WIDGET_L
327
343
  if (key === drawn)
328
344
  return;
329
345
  drawn = key;
330
- drawChips(chips, records, readonly, labels, (record) => form.setValue(name, current().filter((r) => r.id !== record.id)));
346
+ drawChips(chips, records, readonly, labels, (record) => form.setValue(name, current().filter((r) => r.id !== record.id)), open);
331
347
  box.setText('');
332
348
  },
333
349
  };
334
350
  };
335
351
  exports.tagsWidget = tagsWidget;
336
- /** Chips for tags, each with a remove button unless read-only. */
337
- function drawChips(chips, records, readonly, labels, remove) {
352
+ /** Chips for tags, each with a remove button unless read-only; with `open`, each one's words a button that opens it. */
353
+ function drawChips(chips, records, readonly, labels, remove, open) {
338
354
  const doc = chips.ownerDocument;
339
355
  chips.replaceChildren(...records.map((record) => {
340
356
  const chip = doc.createElement('li');
341
357
  chip.className = 'fd-chip';
342
- const text = doc.createElement('span');
358
+ const text = doc.createElement(open ? 'button' : 'span');
343
359
  text.className = 'fd-chip-label';
344
360
  text.textContent = record.label;
361
+ if (open) {
362
+ text.type = 'button';
363
+ text.setAttribute('aria-label', fill(labels.openNamed, { name: record.label }));
364
+ text.addEventListener('click', () => open(record));
365
+ }
345
366
  chip.append(text);
346
367
  if (!readonly) {
347
368
  const button = doc.createElement('button');
@@ -359,7 +380,7 @@ function drawChips(chips, records, readonly, labels, remove) {
359
380
  * Free-text tags on a text field, kept as "oak, glass": Enter or a comma adds
360
381
  * what was typed, Backspace in an empty box takes the last one away, and the
361
382
  * node's `options.suggestions` are offered as you type. `options.separator`
362
- * is "," unless set.
383
+ * is "," unless set; with `options.max`, the box goes once there are as many.
363
384
  */
364
385
  const charTagsWidget = ({ form, name, node, id, document, labels = labels_1.WIDGET_LABELS.en }) => {
365
386
  const options = node.options ?? {};
@@ -371,7 +392,7 @@ const charTagsWidget = ({ form, name, node, id, document, labels = labels_1.WIDG
371
392
  const add = (raw) => {
372
393
  const tag = raw.trim();
373
394
  const tags = current();
374
- if (tag && !tags.some((t) => t.toLowerCase() === tag.toLowerCase()))
395
+ if (tag && !tags.some((t) => t.toLowerCase() === tag.toLowerCase()) && !(tags.length >= options['max']))
375
396
  write([...tags, tag]);
376
397
  };
377
398
  const element = document.createElement('div');
@@ -431,7 +452,7 @@ const charTagsWidget = ({ form, name, node, id, document, labels = labels_1.WIDG
431
452
  update(state) {
432
453
  const tags = split(state.value);
433
454
  box.setReadonly(state.readonly);
434
- box.element.hidden = state.readonly;
455
+ box.element.hidden = state.readonly || tags.length >= options['max'];
435
456
  box.input.setAttribute('aria-invalid', String(state.invalid));
436
457
  if (state.describedBy)
437
458
  box.input.setAttribute('aria-describedby', state.describedBy);
@@ -439,8 +460,12 @@ const charTagsWidget = ({ form, name, node, id, document, labels = labels_1.WIDG
439
460
  if (key === drawn)
440
461
  return;
441
462
  drawn = key;
463
+ const typing = document.activeElement === box.input;
442
464
  drawChips(chips, tags.map((t) => ({ id: t, label: t })), state.readonly, labels, (record) => write(current().filter((t) => t !== record.label)));
443
465
  box.setText('');
466
+ // The box gone at the most, the cursor stays in the keywords: on the last one's ×.
467
+ if (typing && box.element.hidden)
468
+ chips.querySelector('li:last-child button')?.focus();
444
469
  },
445
470
  };
446
471
  };