@fieldia/widgets 0.9.2 → 0.11.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 (218) hide show
  1. package/README.md +2 -1
  2. package/package.json +2 -2
  3. package/src/index.d.mts +2 -0
  4. package/src/index.d.ts +2 -0
  5. package/src/index.js +4 -0
  6. package/src/index.js.map +1 -1
  7. package/src/index.mjs +2 -0
  8. package/src/index.mjs.map +1 -1
  9. package/src/lib/address.d.mts +4 -0
  10. package/src/lib/address.d.ts +4 -0
  11. package/src/lib/address.js +105 -0
  12. package/src/lib/address.js.map +1 -0
  13. package/src/lib/address.mjs +100 -0
  14. package/src/lib/address.mjs.map +1 -0
  15. package/src/lib/cards.d.mts +2 -0
  16. package/src/lib/cards.d.ts +2 -0
  17. package/src/lib/cards.js +152 -0
  18. package/src/lib/cards.js.map +1 -0
  19. package/src/lib/cards.mjs +148 -0
  20. package/src/lib/cards.mjs.map +1 -0
  21. package/src/lib/choice-images.d.mts +2 -0
  22. package/src/lib/choice-images.d.ts +2 -0
  23. package/src/lib/choice-images.js +99 -0
  24. package/src/lib/choice-images.js.map +1 -0
  25. package/src/lib/choice-images.mjs +95 -0
  26. package/src/lib/choice-images.mjs.map +1 -0
  27. package/src/lib/choice-rules.d.mts +22 -0
  28. package/src/lib/choice-rules.d.ts +22 -0
  29. package/src/lib/choice-rules.js +46 -0
  30. package/src/lib/choice-rules.js.map +1 -0
  31. package/src/lib/choice-rules.mjs +41 -0
  32. package/src/lib/choice-rules.mjs.map +1 -0
  33. package/src/lib/choice-tags.d.mts +17 -0
  34. package/src/lib/choice-tags.d.ts +17 -0
  35. package/src/lib/choice-tags.js +187 -0
  36. package/src/lib/choice-tags.js.map +1 -0
  37. package/src/lib/choice-tags.mjs +182 -0
  38. package/src/lib/choice-tags.mjs.map +1 -0
  39. package/src/lib/choices-from.d.mts +8 -0
  40. package/src/lib/choices-from.d.ts +8 -0
  41. package/src/lib/choices-from.js +63 -0
  42. package/src/lib/choices-from.js.map +1 -0
  43. package/src/lib/choices-from.mjs +60 -0
  44. package/src/lib/choices-from.mjs.map +1 -0
  45. package/src/lib/display.js +4 -3
  46. package/src/lib/display.js.map +1 -1
  47. package/src/lib/display.mjs +5 -4
  48. package/src/lib/display.mjs.map +1 -1
  49. package/src/lib/extras.js +8 -4
  50. package/src/lib/extras.js.map +1 -1
  51. package/src/lib/extras.mjs +8 -4
  52. package/src/lib/extras.mjs.map +1 -1
  53. package/src/lib/files.d.mts +2 -0
  54. package/src/lib/files.d.ts +2 -0
  55. package/src/lib/files.js +236 -78
  56. package/src/lib/files.js.map +1 -1
  57. package/src/lib/files.mjs +235 -78
  58. package/src/lib/files.mjs.map +1 -1
  59. package/src/lib/focus-trap.d.mts +7 -0
  60. package/src/lib/focus-trap.d.ts +7 -0
  61. package/src/lib/focus-trap.js +26 -0
  62. package/src/lib/focus-trap.js.map +1 -0
  63. package/src/lib/focus-trap.mjs +23 -0
  64. package/src/lib/focus-trap.mjs.map +1 -0
  65. package/src/lib/icons.js +1 -0
  66. package/src/lib/icons.js.map +1 -1
  67. package/src/lib/icons.mjs +1 -0
  68. package/src/lib/icons.mjs.map +1 -1
  69. package/src/lib/kind-parts.d.mts +56 -0
  70. package/src/lib/kind-parts.d.ts +56 -0
  71. package/src/lib/kind-parts.js +121 -0
  72. package/src/lib/kind-parts.js.map +1 -0
  73. package/src/lib/kind-parts.mjs +107 -0
  74. package/src/lib/kind-parts.mjs.map +1 -0
  75. package/src/lib/labels.d.mts +85 -0
  76. package/src/lib/labels.d.ts +85 -0
  77. package/src/lib/labels.js +111 -189
  78. package/src/lib/labels.js.map +1 -1
  79. package/src/lib/labels.mjs +111 -189
  80. package/src/lib/labels.mjs.map +1 -1
  81. package/src/lib/layout-styles.d.mts +11 -0
  82. package/src/lib/layout-styles.d.ts +11 -0
  83. package/src/lib/layout-styles.js +178 -0
  84. package/src/lib/layout-styles.js.map +1 -0
  85. package/src/lib/layout-styles.mjs +175 -0
  86. package/src/lib/layout-styles.mjs.map +1 -0
  87. package/src/lib/limits.d.mts +20 -0
  88. package/src/lib/limits.d.ts +20 -0
  89. package/src/lib/limits.js +71 -0
  90. package/src/lib/limits.js.map +1 -0
  91. package/src/lib/limits.mjs +66 -0
  92. package/src/lib/limits.mjs.map +1 -0
  93. package/src/lib/line-moves.d.mts +8 -0
  94. package/src/lib/line-moves.d.ts +8 -0
  95. package/src/lib/line-moves.js +20 -0
  96. package/src/lib/line-moves.js.map +1 -0
  97. package/src/lib/line-moves.mjs +17 -0
  98. package/src/lib/line-moves.mjs.map +1 -0
  99. package/src/lib/lines.js +85 -7
  100. package/src/lib/lines.js.map +1 -1
  101. package/src/lib/lines.mjs +86 -8
  102. package/src/lib/lines.mjs.map +1 -1
  103. package/src/lib/locales/all.d.mts +8 -0
  104. package/src/lib/locales/all.d.ts +8 -0
  105. package/src/lib/locales/all.js +13 -0
  106. package/src/lib/locales/all.js.map +1 -0
  107. package/src/lib/locales/all.mjs +10 -0
  108. package/src/lib/locales/all.mjs.map +1 -0
  109. package/src/lib/locales/ar.d.mts +3 -0
  110. package/src/lib/locales/ar.d.ts +3 -0
  111. package/src/lib/locales/ar.js +108 -0
  112. package/src/lib/locales/ar.js.map +1 -0
  113. package/src/lib/locales/ar.mjs +105 -0
  114. package/src/lib/locales/ar.mjs.map +1 -0
  115. package/src/lib/locales/de.d.mts +3 -0
  116. package/src/lib/locales/de.d.ts +3 -0
  117. package/src/lib/locales/de.js +108 -0
  118. package/src/lib/locales/de.js.map +1 -0
  119. package/src/lib/locales/de.mjs +105 -0
  120. package/src/lib/locales/de.mjs.map +1 -0
  121. package/src/lib/locales/fr.d.mts +3 -0
  122. package/src/lib/locales/fr.d.ts +3 -0
  123. package/src/lib/locales/fr.js +108 -0
  124. package/src/lib/locales/fr.js.map +1 -0
  125. package/src/lib/locales/fr.mjs +105 -0
  126. package/src/lib/locales/fr.mjs.map +1 -0
  127. package/src/lib/matrix.d.mts +10 -0
  128. package/src/lib/matrix.d.ts +10 -0
  129. package/src/lib/matrix.js +86 -0
  130. package/src/lib/matrix.js.map +1 -0
  131. package/src/lib/matrix.mjs +82 -0
  132. package/src/lib/matrix.mjs.map +1 -0
  133. package/src/lib/numbers.d.mts +7 -0
  134. package/src/lib/numbers.d.ts +7 -0
  135. package/src/lib/numbers.js +15 -0
  136. package/src/lib/numbers.js.map +1 -1
  137. package/src/lib/numbers.mjs +14 -0
  138. package/src/lib/numbers.mjs.map +1 -1
  139. package/src/lib/progress.js +8 -4
  140. package/src/lib/progress.js.map +1 -1
  141. package/src/lib/progress.mjs +8 -4
  142. package/src/lib/progress.mjs.map +1 -1
  143. package/src/lib/ranking.d.mts +2 -0
  144. package/src/lib/ranking.d.ts +2 -0
  145. package/src/lib/ranking.js +172 -0
  146. package/src/lib/ranking.js.map +1 -0
  147. package/src/lib/ranking.mjs +168 -0
  148. package/src/lib/ranking.mjs.map +1 -0
  149. package/src/lib/relations.d.mts +1 -1
  150. package/src/lib/relations.d.ts +1 -1
  151. package/src/lib/relations.js +43 -18
  152. package/src/lib/relations.js.map +1 -1
  153. package/src/lib/relations.mjs +43 -18
  154. package/src/lib/relations.mjs.map +1 -1
  155. package/src/lib/shuffle.d.mts +7 -0
  156. package/src/lib/shuffle.d.ts +7 -0
  157. package/src/lib/shuffle.js +60 -0
  158. package/src/lib/shuffle.js.map +1 -0
  159. package/src/lib/shuffle.mjs +57 -0
  160. package/src/lib/shuffle.mjs.map +1 -0
  161. package/src/lib/signature.d.mts +2 -0
  162. package/src/lib/signature.d.ts +2 -0
  163. package/src/lib/signature.js +223 -0
  164. package/src/lib/signature.js.map +1 -0
  165. package/src/lib/signature.mjs +219 -0
  166. package/src/lib/signature.mjs.map +1 -0
  167. package/src/lib/slider.d.mts +10 -0
  168. package/src/lib/slider.d.ts +10 -0
  169. package/src/lib/slider.js +57 -0
  170. package/src/lib/slider.js.map +1 -0
  171. package/src/lib/slider.mjs +53 -0
  172. package/src/lib/slider.mjs.map +1 -0
  173. package/src/lib/styles-choices.d.mts +7 -0
  174. package/src/lib/styles-choices.d.ts +7 -0
  175. package/src/lib/styles-choices.js +47 -0
  176. package/src/lib/styles-choices.js.map +1 -0
  177. package/src/lib/styles-choices.mjs +44 -0
  178. package/src/lib/styles-choices.mjs.map +1 -0
  179. package/src/lib/styles-inputs.d.mts +9 -0
  180. package/src/lib/styles-inputs.d.ts +9 -0
  181. package/src/lib/styles-inputs.js +41 -0
  182. package/src/lib/styles-inputs.js.map +1 -0
  183. package/src/lib/styles-inputs.mjs +38 -0
  184. package/src/lib/styles-inputs.mjs.map +1 -0
  185. package/src/lib/styles-kinds.d.mts +7 -0
  186. package/src/lib/styles-kinds.d.ts +7 -0
  187. package/src/lib/styles-kinds.js +119 -0
  188. package/src/lib/styles-kinds.js.map +1 -0
  189. package/src/lib/styles-kinds.mjs +116 -0
  190. package/src/lib/styles-kinds.mjs.map +1 -0
  191. package/src/lib/styles-parts.d.mts +16 -0
  192. package/src/lib/styles-parts.d.ts +16 -0
  193. package/src/lib/styles-parts.js +69 -0
  194. package/src/lib/styles-parts.js.map +1 -0
  195. package/src/lib/styles-parts.mjs +66 -0
  196. package/src/lib/styles-parts.mjs.map +1 -0
  197. package/src/lib/styles.d.mts +10 -12
  198. package/src/lib/styles.d.ts +10 -12
  199. package/src/lib/styles.js +259 -64
  200. package/src/lib/styles.js.map +1 -1
  201. package/src/lib/styles.mjs +258 -63
  202. package/src/lib/styles.mjs.map +1 -1
  203. package/src/lib/units.d.mts +10 -0
  204. package/src/lib/units.d.ts +10 -0
  205. package/src/lib/units.js +19 -0
  206. package/src/lib/units.js.map +1 -0
  207. package/src/lib/units.mjs +16 -0
  208. package/src/lib/units.mjs.map +1 -0
  209. package/src/lib/widgets.js +215 -57
  210. package/src/lib/widgets.js.map +1 -1
  211. package/src/lib/widgets.mjs +215 -57
  212. package/src/lib/widgets.mjs.map +1 -1
  213. package/src/lib/yes-no.d.mts +9 -0
  214. package/src/lib/yes-no.d.ts +9 -0
  215. package/src/lib/yes-no.js +58 -0
  216. package/src/lib/yes-no.js.map +1 -0
  217. package/src/lib/yes-no.mjs +54 -0
  218. package/src/lib/yes-no.mjs.map +1 -0
@@ -1,3 +1,7 @@
1
+ import { KINDS_CSS } from './styles-kinds.mjs';
2
+ import { CHOICES_CSS } from './styles-choices.mjs';
3
+ import { INPUTS_CSS } from './styles-inputs.mjs';
4
+ import { PARTS_CSS } from './styles-parts.mjs';
1
5
  /**
2
6
  * Fieldia's stylesheet: two skins and the layout chrome, all scoped to the
3
7
  * form's own root (`.fd-form[data-fd-skin=…]`), so two forms on one page can
@@ -11,12 +15,22 @@
11
15
  * Written with logical properties (inline/block, start/end), so a right-to-left
12
16
  * form mirrors without a second stylesheet.
13
17
  */
14
- export const FIELDIA_CSS = /* css */ `
15
- /* .fd-theme carries the same tokens for things outside a form, such as a dialog over the page. */
16
- .fd-form, .fd-theme {
18
+ import { LAYOUT_CSS } from './layout-styles.mjs';
19
+ /**
20
+ * The widths of a form at which its groups take their medium and their narrow
21
+ * columns: up to 760px and up to 520px of the form's own width, as the
22
+ * stylesheet's @container rules say (a spec holds the two together). What
23
+ * shows a form at a width — the designer's canvas — asks these.
24
+ */
25
+ export const FORM_WIDTHS = { medium: 760, narrow: 520 };
26
+ /** The skins and the parts' chrome. One literal, so the script bundle can minify it as CSS. */
27
+ const SKINS_CSS = /* css */ `
28
+ /* .fd-theme carries the same tokens for things outside a form, such as a dialog over the page. One inside a form
29
+ with no skin of its own (the conversation beside a record) wears the form's skin and scheme instead. */
30
+ .fd-form, .fd-theme:is([data-fd-skin], :not(.fd-form *)) {
17
31
  --fd-font: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "Noto Sans Arabic", sans-serif;
18
32
  --fd-text: #212529;
19
- --fd-muted: #6b7280;
33
+ --fd-muted: #636976;
20
34
  --fd-page: #f2f3f5;
21
35
  --fd-surface: #ffffff;
22
36
  --fd-border: #cfd4da;
@@ -49,17 +63,18 @@ export const FIELDIA_CSS = /* css */ `
49
63
  color: var(--fd-text);
50
64
  -webkit-text-size-adjust: 100%;
51
65
  }
66
+ /* Ant Design's blue and red, a shade darker: words in them read at 4.5:1 (WCAG AA) on white, the page and their soft shades. */
52
67
  .fd-form[data-fd-skin="outlined"], .fd-theme[data-fd-skin="outlined"] {
53
68
  --fd-text: rgba(0, 0, 0, 0.88);
54
69
  --fd-muted: rgba(0, 0, 0, 0.55);
55
70
  --fd-page: #f5f5f5;
56
71
  --fd-border: #d9d9d9;
57
72
  --fd-border-strong: #bfbfbf;
58
- --fd-accent: #1677ff;
73
+ --fd-accent: #1365d9;
59
74
  --fd-accent-soft: #e6f4ff;
60
- --fd-focus: #1677ff;
75
+ --fd-focus: #1365d9;
61
76
  --fd-focus-ring: 0 0 0 2px rgba(5, 145, 255, 0.12);
62
- --fd-error: #ff4d4f;
77
+ --fd-error: #c63c3d;
63
78
  --fd-error-soft: #fff2f0;
64
79
  --fd-radius: 8px;
65
80
  --fd-control-radius: 6px;
@@ -92,13 +107,19 @@ export const FIELDIA_CSS = /* css */ `
92
107
  .fd-section-title .fd-icon { color: var(--fd-muted); }
93
108
 
94
109
  /* ---- fields ---------------------------------------------------------------- */
110
+ /* A grid of parts. --fd-cols is how many columns it has at the width it has now: the
111
+ rules for narrower widths change only that, and each part spans its --fd-span of them, never more. */
95
112
  .fd-grid {
113
+ --fd-cols: var(--fd-columns, 1);
114
+ /* A group that spans columns does not hand its width down to the parts inside it. */
115
+ --fd-span: 1;
96
116
  display: grid;
97
- grid-template-columns: repeat(var(--fd-columns, 1), minmax(0, 1fr));
117
+ grid-template-columns: repeat(var(--fd-cols), minmax(0, 1fr));
98
118
  gap: var(--fd-gap-y) var(--fd-gap-x);
99
119
  align-items: start;
100
120
  }
101
- .fd-field { display: grid; gap: 4px; min-width: 0; grid-column: span min(var(--fd-span, 1), var(--fd-columns, 1)); }
121
+ .fd-grid > * { grid-column: span min(var(--fd-span, 1), var(--fd-cols)); }
122
+ .fd-field { display: grid; gap: 4px; min-width: 0; }
102
123
  .fd-label { font-weight: var(--fd-label-weight); color: var(--fd-text); }
103
124
  /* The ✓ of a field filled in right, by its label. */
104
125
  .fd-valid-mark { color: var(--fd-success); width: 1em; height: 1em; margin-inline-start: 6px; vertical-align: -0.15em; stroke-width: 2.4; }
@@ -106,43 +127,51 @@ export const FIELDIA_CSS = /* css */ `
106
127
  .fd-form[data-fd-skin="outlined"] .fd-field.fd-required > .fd-label::after { content: ""; }
107
128
  .fd-form[data-fd-skin="outlined"] .fd-field.fd-required > .fd-label::before { content: "* "; color: var(--fd-error); }
108
129
  .fd-help { color: var(--fd-muted); font-size: 12.5px; }
130
+ /*
131
+ * A page's words run the way they are written — a sentence left in English on
132
+ * an Arabic page keeps its full stop at its end — and line up with the form.
133
+ * Titles with an icon keep their words apart instead, in a <bdi>.
134
+ */
135
+ .fd-page-title, .fd-page-description, .fd-section-description, .fd-label, .fd-help, .fd-text-heading, .fd-text-paragraph, .fd-text-note, .fd-choice > span {
136
+ unicode-bidi: plaintext; text-align: match-parent; text-align: -webkit-match-parent;
137
+ }
109
138
  .fd-error { color: var(--fd-error); font-size: 12.5px; }
110
139
  .fd-warning {
111
140
  color: var(--fd-warning); background: var(--fd-warning-soft); font-size: 12.5px;
112
141
  padding: 3px 8px; border-radius: var(--fd-control-radius); justify-self: start;
113
142
  }
114
143
 
115
- /* underline: label beside the value, the way a Flectra sheet reads */
116
- .fd-form[data-fd-skin="underline"] .fd-field {
144
+ /* underline: label beside the value, the way a Flectra sheet reads. A field whose page or group
145
+ says where its label goes (data-labels) is laid out by those rules instead, in either skin. */
146
+ .fd-form[data-fd-skin="underline"] .fd-field:where(:not([data-labels])) {
117
147
  /* One label width for every field, so a field spanning two columns lines up with its neighbours. */
118
148
  grid-template-columns: var(--fd-label-width, 11em) minmax(0, 1fr);
119
149
  column-gap: 12px;
120
150
  align-items: baseline;
121
151
  }
122
- .fd-form[data-fd-skin="underline"] .fd-field > .fd-label { grid-column: 1; }
152
+ .fd-form[data-fd-skin="underline"] .fd-field:where(:not([data-labels])) > .fd-label { grid-column: 1; }
123
153
  /* A table of lines needs the full width: its label sits above it. */
124
154
  .fd-form[data-fd-skin="underline"] .fd-field[data-type="one2many"] { grid-template-columns: minmax(0, 1fr); }
125
155
  .fd-form[data-fd-skin="underline"] .fd-field[data-type="one2many"] > * { grid-column: 1 !important; }
126
- .fd-form[data-fd-skin="underline"] .fd-field > :not(.fd-label) { grid-column: 2; }
156
+ .fd-form[data-fd-skin="underline"] .fd-field:where(:not([data-labels])) > :not(.fd-label) { grid-column: 2; }
127
157
  /* A label beside every value needs room twice over: the underline skin stacks its columns sooner. */
128
158
  @container (max-width: 760px) {
129
- .fd-form[data-fd-skin="underline"] .fd-grid { grid-template-columns: minmax(0, 1fr); }
130
- .fd-form[data-fd-skin="underline"] .fd-field { grid-column: auto; }
159
+ .fd-form[data-fd-skin="underline"] .fd-grid { --fd-cols: 1; }
131
160
  /* A section that says how many columns it keeps here keeps them, in either skin. */
132
- .fd-form .fd-grid[data-columns-medium] { grid-template-columns: repeat(var(--fd-columns-medium), minmax(0, 1fr)); }
133
- .fd-form .fd-grid[data-columns-medium] > .fd-field { grid-column: span min(var(--fd-span, 1), var(--fd-columns-medium)); }
161
+ .fd-form .fd-grid[data-columns-medium] { --fd-cols: var(--fd-columns-medium); }
134
162
  /* Kept side by side here, the underline skin's fields have no room for a label beside: it goes above. */
135
- .fd-form[data-fd-skin="underline"] .fd-grid[data-columns-medium]:not([data-columns-medium="1"]) .fd-field { grid-template-columns: minmax(0, 1fr); }
136
- .fd-form[data-fd-skin="underline"] .fd-grid[data-columns-medium]:not([data-columns-medium="1"]) .fd-field > * { grid-column: 1 !important; }
163
+ .fd-form[data-fd-skin="underline"] .fd-grid[data-columns-medium]:not([data-columns-medium="1"]) .fd-field:where(:not([data-labels])) { grid-template-columns: minmax(0, 1fr); }
164
+ .fd-form[data-fd-skin="underline"] .fd-grid[data-columns-medium]:not([data-columns-medium="1"]) .fd-field:where(:not([data-labels])) > * { grid-column: 1 !important; }
137
165
  }
138
166
  @container (max-width: 520px) {
139
- .fd-grid { grid-template-columns: minmax(0, 1fr); }
140
- .fd-field { grid-column: auto; }
141
- .fd-form[data-fd-skin="underline"] .fd-field { grid-template-columns: minmax(0, 1fr); }
142
- .fd-form[data-fd-skin="underline"] .fd-field > * { grid-column: 1 !important; }
167
+ .fd-grid { --fd-cols: 1; }
168
+ .fd-form[data-fd-skin="underline"] .fd-field:where(:not([data-labels])) { grid-template-columns: minmax(0, 1fr); }
169
+ .fd-form[data-fd-skin="underline"] .fd-field:where(:not([data-labels])) > * { grid-column: 1 !important; }
143
170
  /* The narrow count, or one column when only the medium one was given. */
144
- .fd-form .fd-grid[data-columns-medium], .fd-form .fd-grid[data-columns-narrow] { grid-template-columns: repeat(var(--fd-columns-narrow, 1), minmax(0, 1fr)); }
145
- .fd-form .fd-grid[data-columns-medium] > .fd-field, .fd-form .fd-grid[data-columns-narrow] > .fd-field { grid-column: span min(var(--fd-span, 1), var(--fd-columns-narrow, 1)); }
171
+ .fd-form .fd-grid[data-columns-medium], .fd-form .fd-grid[data-columns-narrow] { --fd-cols: var(--fd-columns-narrow, 1); }
172
+ /* A file open on a phone: its name and Close on a row, the tools on the next. */
173
+ .fd-form .fd-file-viewer > :first-child { padding-inline-end: 16px; }
174
+ .fd-form .fd-file-viewer h2 { flex-basis: 100%; margin-inline-end: 36px; }
146
175
  }
147
176
 
148
177
  /* ---- inputs ---------------------------------------------------------------- */
@@ -156,7 +185,7 @@ export const FIELDIA_CSS = /* css */ `
156
185
  border-width: var(--fd-input-border);
157
186
  border-radius: var(--fd-control-radius);
158
187
  padding: var(--fd-pad-y) var(--fd-pad-x);
159
- min-height: 30px;
188
+ min-height: var(--fd-control-height, 30px);
160
189
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
161
190
  }
162
191
  .fd-input::placeholder { color: var(--fd-muted); opacity: 0.8; }
@@ -201,6 +230,21 @@ export const FIELDIA_CSS = /* css */ `
201
230
  [dir="rtl"] .fd-switch:checked::after { transform: translateX(-14px); }
202
231
  .fd-choices { display: flex; flex-wrap: wrap; gap: 6px 18px; }
203
232
  .fd-choice { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; }
233
+ /* "Other:", with a box for an answer of one's own, a choice like the others. */
234
+ .fd-choice-other { cursor: default; flex: 1 1 260px; max-width: 420px; min-width: 0; }
235
+ .fd-choice-other-pick { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; flex: none; }
236
+ .fd-choice-other .fd-other-input { flex: 1; min-width: 6em; width: auto; min-height: 30px; padding-block: 2px; }
237
+ /* A scale's ends in words, under its first and last points. */
238
+ .fd-scale-box { display: inline-grid; gap: 4px; max-width: 100%; }
239
+ .fd-scale-ends { display: flex; justify-content: space-between; gap: 16px; font-size: 12.5px; color: var(--fd-muted); }
240
+ /* "Clear selection", at the question's end, once a single choice that need not be answered has one; never in a table's cell. */
241
+ .fd-choices-box { display: grid; gap: 6px; min-width: 0; }
242
+ .fd-choice-clear {
243
+ justify-self: end; font: inherit; font-size: 13px; color: var(--fd-muted); background: none; border: 0;
244
+ padding: 2px 4px; border-radius: 4px; cursor: pointer;
245
+ }
246
+ .fd-choice-clear:hover { color: var(--fd-text); text-decoration: underline; text-underline-offset: 3px; }
247
+ .fd-lines-table .fd-choice-clear, .fd-grid-editor .fd-choice-clear { display: none; }
204
248
  .fd-points { display: flex; flex-wrap: wrap; gap: 6px; }
205
249
  .fd-points button {
206
250
  font: inherit; cursor: pointer; border: 1px solid var(--fd-border); background: var(--fd-surface);
@@ -215,17 +259,18 @@ export const FIELDIA_CSS = /* css */ `
215
259
 
216
260
  /* ---- pickers: many2one, many2many, reference ------------------------------ */
217
261
  .fd-combo { position: relative; display: flex; align-items: center; min-width: 0; }
218
- .fd-combo-input { padding-inline-end: 28px; }
262
+ .fd-combo-input { padding-inline-end: 30px; }
263
+ /* Its buttons are 24px each way at least: a target a finger or a shaking hand can hit (WCAG 2.5.8). */
219
264
  .fd-combo-clear {
220
- position: absolute; inset-inline-end: 4px; border: none; background: none; cursor: pointer; color: var(--fd-muted);
221
- font-size: 16px; line-height: 1; padding: 2px 6px; border-radius: 4px;
265
+ position: absolute; inset-inline-end: 3px; border: none; background: none; cursor: pointer; color: var(--fd-muted);
266
+ font-size: 16px; line-height: 1; padding: 0 4px; border-radius: 4px; min-width: 24px; min-height: 24px; display: inline-grid; place-items: center;
222
267
  }
223
268
  .fd-combo-clear:hover { color: var(--fd-text); background: var(--fd-page); }
224
269
  /* A link that can be opened has its open button beside the clear button. */
225
- .fd-combo:has(> .fd-combo-open:not([hidden])) .fd-combo-input { padding-inline-end: 52px; }
270
+ .fd-combo:has(> .fd-combo-open:not([hidden])) .fd-combo-input { padding-inline-end: 56px; }
226
271
  .fd-combo-open {
227
- position: absolute; inset-inline-end: 28px; border: none; background: none; cursor: pointer; color: var(--fd-accent);
228
- font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 4px;
272
+ position: absolute; inset-inline-end: 29px; border: none; background: none; cursor: pointer; color: var(--fd-accent);
273
+ font-size: 14px; line-height: 1; padding: 0 4px; border-radius: 4px; min-width: 24px; min-height: 24px; display: inline-grid; place-items: center;
229
274
  }
230
275
  .fd-combo-open:hover { background: var(--fd-page); }
231
276
  .fd-listbox {
@@ -243,6 +288,8 @@ export const FIELDIA_CSS = /* css */ `
243
288
  display: inline-flex; align-items: center; gap: 4px; padding: 1px 4px 1px 10px; border-radius: 999px;
244
289
  background: var(--fd-accent-soft); color: var(--fd-text); font-size: 13px; line-height: 22px;
245
290
  }
291
+ button.fd-chip-label { border: none; padding: 0; background: none; font: inherit; color: inherit; cursor: pointer; }
292
+ button.fd-chip-label:hover { text-decoration: underline; }
246
293
  .fd-chip-remove { border: none; background: none; cursor: pointer; color: var(--fd-muted); font-size: 15px; line-height: 1; padding: 0 4px; border-radius: 999px; }
247
294
  .fd-chip-remove:hover { color: var(--fd-error); }
248
295
  .fd-tags .fd-combo { flex: 1 1 140px; }
@@ -260,6 +307,8 @@ export const FIELDIA_CSS = /* css */ `
260
307
  .fd-lines-table .fd-input { min-height: 28px; }
261
308
  /* A yes/no cell sits level with the inputs beside it. */
262
309
  .fd-lines-table td > .fd-checkbox, .fd-lines-table td > .fd-switch { margin-block-start: 6px; }
310
+ .fd-lines-table .fd-lines-grip { width: 1px; min-width: 0; padding-inline: 6px 2px; }
311
+ .fd-line-grip { display: block; margin-block-start: 7px; cursor: grab; }
263
312
  .fd-line-delete { border: none; background: none; cursor: pointer; color: var(--fd-muted); font-size: 16px; line-height: 1; padding: 4px 6px; border-radius: 4px; }
264
313
  .fd-line-delete:hover { color: var(--fd-error); background: var(--fd-error-soft); }
265
314
  .fd-lines-totals td { padding: 8px; font-weight: 600; border-block-start: 1px solid var(--fd-border); font-variant-numeric: tabular-nums; }
@@ -272,19 +321,95 @@ export const FIELDIA_CSS = /* css */ `
272
321
  .fd-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
273
322
 
274
323
  /* ---- files, images, rich text, json ------------------------------------ */
275
- .fd-file { display: grid; gap: 8px; justify-items: start; padding: 6px 0; border-radius: var(--fd-control-radius); }
324
+ .fd-file { display: grid; gap: 8px; justify-items: start; padding: 6px 0; border-radius: var(--fd-control-radius); min-width: 0; }
276
325
  .fd-file.fd-dragging { outline: 2px dashed var(--fd-accent); outline-offset: 4px; }
277
- .fd-file-pick { display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; cursor: pointer; }
278
- .fd-file-chosen { display: inline-flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; }
279
- .fd-file-name { font-variant-numeric: tabular-nums; }
326
+ .fd-file-pick { display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: center; cursor: pointer; }
327
+ .fd-file input:focus-visible + .fd-file-pick { outline: 2px solid var(--fd-focus); outline-offset: 2px; }
328
+ .fd-files-list .fd-file-pick { justify-self: stretch; padding: 10px 14px; border: 1px dashed var(--fd-border-strong); border-radius: var(--fd-control-radius); background: var(--fd-page); }
329
+ .fd-file-pick:hover, .fd-dragging .fd-file-pick { border-color: var(--fd-accent); }
330
+ .fd-files { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; justify-self: stretch; min-width: 0; }
331
+ .fd-files:empty { display: none; }
332
+ .fd-file-item { position: relative; display: flex; align-items: center; gap: 2px; min-width: 0; }
333
+ .fd-file-open {
334
+ flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; padding: 5px 8px; font: inherit; color: inherit; text-align: start; cursor: pointer;
335
+ background: var(--fd-surface); border: 1px solid var(--fd-border); border-radius: var(--fd-control-radius);
336
+ }
337
+ .fd-file-open:hover { border-color: var(--fd-accent); }
338
+ .fd-file-thumb, .fd-file-icon { flex: none; width: 36px; height: 36px; border-radius: 3px; object-fit: cover; }
339
+ /* A page with its corner folded, its colour by kind, its extension on it. */
340
+ .fd-file-icon {
341
+ display: grid; place-items: end center; padding-block-end: 4px; font-size: 9px; font-weight: 700; color: #fff;
342
+ background: var(--fd-kind, #5b6573); clip-path: polygon(0 0, 68% 0, 100% 28%, 100% 100%, 0 100%);
343
+ }
344
+ .fd-file-icon[data-kind="pdf"] { --fd-kind: #c62828; }
345
+ .fd-file-icon[data-kind="doc"] { --fd-kind: #1f5fbf; }
346
+ .fd-file-icon[data-kind="sheet"] { --fd-kind: #1d7a3e; }
347
+ .fd-file-icon[data-kind="zip"] { --fd-kind: #8a5300; }
348
+ .fd-file-name { flex: 1; display: flex; min-width: 0; white-space: pre; }
349
+ .fd-file-name > span { overflow: hidden; text-overflow: ellipsis; }
350
+ /* A size reads in its own direction, right to left too. */
351
+ .fd-file-size { color: var(--fd-muted); font-size: 12.5px; font-variant-numeric: tabular-nums; unicode-bidi: plaintext; }
352
+ .fd-file-remove { flex: none; width: 32px; height: 32px; border: none; border-radius: 999px; background: none; color: var(--fd-muted); font-size: 20px; line-height: 1; cursor: pointer; }
353
+ .fd-file-remove:hover { color: var(--fd-error); background: var(--fd-error-soft); }
354
+ .fd-file-confirm:not([hidden]) { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px; }
355
+ .fd-file-note:empty { display: none; }
356
+ .fd-file-note { color: var(--fd-warning); }
357
+ /* Over the files: how many, and the switch between a list and pictures, at the end. */
358
+ .fd-file-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; justify-self: stretch; }
359
+ .fd-file-views { display: flex; gap: 2px; margin-inline-start: auto; padding: 2px; border: 1px solid var(--fd-border); border-radius: var(--fd-control-radius); background: var(--fd-page); }
360
+ .fd-file-views button {
361
+ display: flex; align-items: center; gap: 6px; min-height: 28px; padding: 2px 10px; font: inherit; font-size: 13px; color: var(--fd-muted); cursor: pointer;
362
+ border: none; border-radius: calc(var(--fd-control-radius) - 2px); background: none;
363
+ }
364
+ .fd-file-views [aria-pressed="true"] { color: var(--fd-text); background: var(--fd-surface); box-shadow: 0 0 0 1px var(--fd-border); }
365
+ /* Thumbnails: tiles in a row that wraps, the picker the last of them. */
366
+ .fd-files-thumbs { display: flex; flex-wrap: wrap; align-items: flex-start; }
367
+ .fd-files-thumbs > * { flex-basis: 100%; }
368
+ :is(.fd-files-thumbs, .fd-files-cards) > .fd-files { display: contents; }
369
+ .fd-files-thumbs .fd-file-item, .fd-image-pick { flex: none; width: 96px; height: 96px; }
370
+ .fd-files-thumbs .fd-file-open { height: 100%; padding: 6px; flex-direction: column; justify-content: center; gap: 4px; overflow: hidden; font-size: 12px; }
371
+ :is(.fd-files-thumbs, .fd-files-cards) .fd-file-thumb { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: inherit; }
372
+ .fd-files-thumbs .fd-file-name { flex: none; max-width: 100%; }
373
+ .fd-files-thumbs .fd-file-size, .fd-files-thumbs .fd-file-thumb ~ * { display: none; }
374
+ :is(.fd-files-thumbs, .fd-files-cards) .fd-file-remove {
375
+ position: absolute; inset-block-start: 4px; inset-inline-end: 4px; width: 26px; height: 26px; font-size: 17px;
376
+ background: rgba(15, 20, 25, 0.62); color: #fff; opacity: 0;
377
+ }
378
+ .fd-file-item:is(:hover, :focus-within) .fd-file-remove { opacity: 1; }
379
+ /* A screen with no pointer to hover with shows each tile's remove. */
380
+ @media (hover: none) { .fd-file-item .fd-file-remove { opacity: 1; } }
280
381
  .fd-image-pick {
281
- width: 120px; height: 120px; border: 1px dashed var(--fd-border-strong); border-radius: var(--fd-control-radius);
282
- display: grid; place-content: center; justify-items: center; text-align: center; padding: 8px; background: var(--fd-page);
283
- }
284
- .fd-image-pick .fd-button { border: none; background: none; color: var(--fd-accent); padding: 0; min-height: 0; }
285
- .fd-image-pick:hover { border-color: var(--fd-accent); }
286
- .fd-avatar .fd-image-pick { width: 88px; height: 88px; }
287
- .fd-image-preview { max-width: 160px; max-height: 160px; border-radius: var(--fd-control-radius); border: 1px solid var(--fd-border); object-fit: cover; background: var(--fd-page); }
382
+ display: grid; place-content: center; justify-items: center; gap: 2px; padding: 6px; text-align: center; font-size: 12px;
383
+ border: 1px dashed var(--fd-border-strong); border-radius: var(--fd-control-radius); background: var(--fd-page);
384
+ }
385
+ /* Cards: a picture over each file's name, in two lines at most, and its size; as many to a row as fit. */
386
+ .fd-files-cards { grid-template-columns: repeat(auto-fill, minmax(min(100%, 130px), 1fr)); }
387
+ .fd-files-cards > * { grid-column: 1 / -1; }
388
+ .fd-files-cards > .fd-image-pick { grid-column: auto; justify-self: stretch; width: auto; height: auto; min-height: 96px; }
389
+ .fd-files-cards .fd-file-item { justify-self: stretch; align-items: stretch; }
390
+ .fd-files-cards .fd-file-open { flex-direction: column; align-items: stretch; gap: 2px; padding: 0 0 8px; overflow: hidden; }
391
+ /* The picture fills its box; with none, the kind's page, large, on the box's ground. */
392
+ .fd-file-picture { position: relative; display: grid; place-items: center; aspect-ratio: 4 / 3; margin-block-end: 6px; background: var(--fd-page); border-block-end: 1px solid var(--fd-border); }
393
+ .fd-file-picture .fd-file-icon { width: 44px; height: 56px; padding-block-end: 8px; font-size: 12px; }
394
+ .fd-files-cards :is(.fd-file-name, .fd-file-size) { padding-inline: 8px; }
395
+ .fd-files-cards .fd-file-name { flex: none; flex-wrap: wrap; font-size: 13px; line-height: 1.35; }
396
+ .fd-files-cards .fd-file-name > span { max-width: 100%; }
397
+ .fd-image-pick .fd-button { border: none; background: none; color: var(--fd-accent); padding: 0; min-height: 0; font-size: 13px; }
398
+ /* A file open to look at: its name and tools over it, the image whole, a PDF or text filling the box. */
399
+ .fd-file-viewer { max-width: 1000px; height: min(88vh, 100%); background: var(--fd-surface); }
400
+ /* Close in the corner, beside the name however the tools wrap. */
401
+ .fd-file-viewer > :first-child { position: relative; flex-wrap: wrap; justify-content: start; gap: 6px 10px; padding-block: 8px; padding-inline-end: 52px; }
402
+ .fd-file-viewer .fd-dialog-close { position: absolute; inset-block-start: 10px; inset-inline-end: 10px; }
403
+ .fd-file-viewer h2 { flex: 1 1 10em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
404
+ .fd-file-step { font-size: 18px; line-height: 1; min-width: 34px; }
405
+ .fd-file-viewer a { text-decoration: none; }
406
+ .fd-file-viewer-body { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: auto; background: var(--fd-page); }
407
+ .fd-file-viewer-body img { max-width: 100%; max-height: 100%; object-fit: contain; }
408
+ .fd-file-viewer-body :is(iframe, pre) { flex: 1; align-self: stretch; margin: 0; border: 0; background: var(--fd-surface); }
409
+ .fd-file-viewer-body pre { padding: 14px 16px; overflow: auto; font: 13px/1.5 monospace; white-space: pre-wrap; overflow-wrap: anywhere; }
410
+ .fd-file-none { display: grid; justify-items: center; gap: 4px; padding: 24px; text-align: center; color: var(--fd-muted); }
411
+ .fd-file-none strong { color: var(--fd-text); overflow-wrap: anywhere; }
412
+ .fd-file-none .fd-file-icon { width: 64px; height: 64px; font-size: 14px; padding-block-end: 8px; }
288
413
  .fd-richtext { min-height: 96px; line-height: 1.5; overflow-wrap: anywhere; }
289
414
  .fd-richtext-box { display: grid; gap: 0; min-width: 0; }
290
415
  .fd-richtext-box > .fd-richtext { border-start-start-radius: 0; border-start-end-radius: 0; }
@@ -309,7 +434,7 @@ export const FIELDIA_CSS = /* css */ `
309
434
  .fd-code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 12.5px; min-height: 96px; }
310
435
 
311
436
  /* ---- sections, tabs ---------------------------------------------------- */
312
- .fd-sections { display: grid; gap: 24px; }
437
+ .fd-sections { display: grid; gap: var(--fd-gap-block, 24px); }
313
438
  .fd-section { border: 0; margin: 0; padding: 0; min-width: 0; display: grid; gap: 14px; }
314
439
  .fd-section-title { font-size: 15px; font-weight: 650; padding: 0; margin: 0; float: inline-start; width: 100%; }
315
440
  .fd-section-title + * { clear: both; }
@@ -329,9 +454,13 @@ export const FIELDIA_CSS = /* css */ `
329
454
  }
330
455
  .fd-section-folded .fd-section-chevron { transform: rotate(-45deg); margin-block-start: 0; }
331
456
  [dir="rtl"] .fd-section-folded .fd-section-chevron { transform: rotate(135deg); }
332
- .fd-form[data-fd-skin="outlined"] .fd-sections > .fd-section {
333
- background: var(--fd-surface); border: 1px solid var(--fd-border); border-radius: var(--fd-radius); padding: 20px 24px;
457
+ /* A card on the page's own ground is a box of its own: on the page, or in an arrangement, a line or tabs there (data-on-page). */
458
+ .fd-form[data-fd-skin="outlined"] :is(.fd-sections > .fd-section:not([data-style]), .fd-section[data-style="card"][data-on-page]) {
459
+ background: var(--fd-surface); border: 1px solid var(--fd-border); border-radius: var(--fd-radius); padding: var(--fd-group-pad, 20px 24px);
334
460
  }
461
+ /* A saved form placed in another: a quiet line while its page comes, and words in a dashed box when it cannot be shown. */
462
+ .fd-form-part-note { margin: 0; color: var(--fd-muted); font-size: 13px; }
463
+ .fd-form-part-problem { padding: 10px 12px; border: 1px dashed var(--fd-border); border-radius: var(--fd-radius); }
335
464
  .fd-tablist { display: flex; gap: 2px; border-block-end: 1px solid var(--fd-border); overflow-x: auto; }
336
465
  .fd-tab {
337
466
  font: inherit; background: none; border: none; cursor: pointer; padding: 8px 14px; color: var(--fd-muted);
@@ -343,7 +472,7 @@ export const FIELDIA_CSS = /* css */ `
343
472
  /* ---- buttons ---------------------------------------------------------- */
344
473
  .fd-button {
345
474
  font: inherit; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; justify-content: center;
346
- min-height: 32px; padding: 4px 14px; border-radius: var(--fd-control-radius);
475
+ min-height: var(--fd-control-height, 32px); padding: 4px 14px; border-radius: var(--fd-control-radius);
347
476
  border: 1px solid var(--fd-border); background: var(--fd-surface); color: var(--fd-text);
348
477
  }
349
478
  .fd-button:hover { border-color: var(--fd-accent); color: var(--fd-accent); }
@@ -431,18 +560,10 @@ export const FIELDIA_CSS = /* css */ `
431
560
  .fd-avatar > .fd-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
432
561
  .fd-form[data-fd-skin="underline"] .fd-avatar { grid-template-columns: minmax(0, 1fr); }
433
562
  .fd-form[data-fd-skin="underline"] .fd-avatar > * { grid-column: 1 !important; }
434
- .fd-avatar .fd-image-pick {
435
- width: 120px; height: 120px; border: 1px dashed var(--fd-border-strong); border-radius: var(--fd-control-radius);
436
- display: grid; place-content: center; justify-items: center; text-align: center; padding: 8px; background: var(--fd-page);
437
- }
438
- .fd-image-pick .fd-button { border: none; background: none; color: var(--fd-accent); padding: 0; min-height: 0; }
439
- .fd-image-pick:hover { border-color: var(--fd-accent); }
440
- .fd-avatar .fd-image-pick { width: 88px; height: 88px; }
441
- .fd-image-preview { width: 88px; height: 88px; }
442
- .fd-avatar .fd-file-pick .fd-help { display: none; }
443
- .fd-avatar .fd-file-name { display: none; }
444
- .fd-avatar .fd-file { justify-items: center; gap: 2px; padding: 0; }
445
- .fd-avatar .fd-file-chosen { gap: 2px 8px; justify-content: center; font-size: 12.5px; }
563
+ .fd-avatar .fd-file { justify-items: center; gap: 4px 8px; padding: 0; justify-content: center; }
564
+ .fd-avatar :is(.fd-file-item, .fd-image-pick) { width: 88px; height: 88px; }
565
+ .fd-avatar :is(.fd-image-pick .fd-help, .fd-file-limits) { display: none; }
566
+ .fd-avatar .fd-button-link { flex-basis: auto; font-size: 12.5px; }
446
567
  /* The title and subtitle themselves: big, their labels only for screen readers. */
447
568
  .fd-title > .fd-field .fd-input { font-size: 24px; font-weight: 600; min-height: 40px; }
448
569
  .fd-form[data-fd-skin="underline"] .fd-title > .fd-field { grid-template-columns: minmax(0, 1fr); }
@@ -518,7 +639,9 @@ export const FIELDIA_CSS = /* css */ `
518
639
  .fd-progressbar[data-tone="warning"] .fd-progressbar-fill { background: #d97706; }
519
640
  .fd-progressbar[data-tone="danger"] .fd-progressbar-fill { background: var(--fd-error); }
520
641
  .fd-progressbar[data-tone="info"] .fd-progressbar-fill { background: var(--fd-info); }
521
- .fd-progressbar-text { position: absolute; inset: 0; display: grid; place-items: center; font-size: 12px; font-weight: 600; color: var(--fd-text); }
642
+ /* The share in words, on a chip of the surface: it reads the same over the fill and the track, in either scheme. Centred by its left edge, so it is centred right to left too. */
643
+ .fd-progressbar-text { position: absolute; inset-block: 2px; left: 50%; translate: -50% 0; display: grid; place-items: center; padding-inline: 7px; border-radius: 999px; background: var(--fd-surface); font-size: 12px; line-height: 1; font-weight: 600; color: var(--fd-text); }
644
+ .fd-progressbar-text:empty { display: none; }
522
645
  .fd-progressbar-edit { display: flex; align-items: center; gap: 12px; min-width: 0; }
523
646
  .fd-progressbar-edit > .fd-progressbar { flex: 1 1 auto; }
524
647
  .fd-progressbar-edit > .fd-input { flex: 0 0 96px; }
@@ -551,6 +674,25 @@ export const FIELDIA_CSS = /* css */ `
551
674
 
552
675
  /* ---- text, status, dialog ------------------------------------------------- */
553
676
  .fd-text-heading { font-size: 16px; font-weight: 650; margin: 0; }
677
+ /* Blocks between fields: a line across the row; empty room or a picture that spans like a field. */
678
+ /* A matrix: rows against columns; it scrolls sideways in its own box on a narrow screen. */
679
+ .fd-matrix { overflow-x: auto; max-width: 100%; }
680
+ .fd-matrix-table { border-collapse: collapse; min-width: 100%; }
681
+ .fd-matrix-table th, .fd-matrix-table td { padding: 6px 10px; text-align: center; border-bottom: 1px solid var(--fd-border); }
682
+ .fd-matrix-table thead th { font-weight: 500; font-size: 13px; color: var(--fd-muted); }
683
+ .fd-matrix-table tbody th { text-align: start; font-weight: 500; }
684
+ .fd-matrix-table input { accent-color: var(--fd-accent); width: 16px; height: 16px; margin: 0; }
685
+ .fd-divider { grid-column: 1 / -1; width: 100%; border: 0; border-top: 1px solid var(--fd-border); margin: 4px 0; }
686
+ .fd-block { min-width: 0; }
687
+ .fd-spacer { min-height: 24px; }
688
+ .fd-image { display: block; max-width: 100%; height: auto; border-radius: var(--fd-radius); }
689
+ /* A picture's width, by name or in pixels, its place in its row, its link and its caption. */
690
+ .fd-figure { display: grid; justify-items: start; gap: 6px; margin: 0; }
691
+ .fd-figure[data-align="center"] { justify-items: center; }
692
+ .fd-figure[data-align="end"] { justify-items: end; }
693
+ .fd-figure > a, .fd-figure .fd-image { width: var(--fd-image-width, auto); max-width: 100%; }
694
+ .fd-figure > a { display: block; border-radius: var(--fd-radius); }
695
+ .fd-caption { font-size: 13px; color: var(--fd-muted); }
554
696
  .fd-text-paragraph { margin: 0; }
555
697
  .fd-text-note { margin: 0; color: var(--fd-muted); font-size: 13px; }
556
698
  .fd-status { min-height: 1.4em; color: var(--fd-muted); font-size: 13px; }
@@ -586,8 +728,34 @@ export const FIELDIA_CSS = /* css */ `
586
728
  .fd-dialog {
587
729
  background: var(--fd-surface); color: var(--fd-text); border-radius: max(var(--fd-radius), 6px); max-width: 420px; width: 100%;
588
730
  padding: 20px 22px; display: grid; gap: 16px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); font-family: var(--fd-font);
731
+ /* An edge of its own: in the dark scheme a shadow is lost on the dimmed page, so the box would barely stand out. */
732
+ border: 1px solid var(--fd-edge, transparent);
589
733
  }
590
734
  .fd-dialog p { margin: 0; }
735
+ /* Words a step says: toasts at the foot of the screen, one over another, each in its tone; over the page, under a dialog. */
736
+ .fd-says {
737
+ position: fixed; inset-inline: 16px; inset-block-end: max(20px, env(safe-area-inset-bottom, 0px)); z-index: 990;
738
+ display: grid; justify-items: center; gap: 8px; pointer-events: none;
739
+ }
740
+ .fd-say {
741
+ pointer-events: auto; display: flex; align-items: center; gap: 8px; max-width: 420px;
742
+ padding-block: 8px; padding-inline: 14px 6px; border: 1px solid var(--fd-border); border-inline-start: 4px solid var(--fd-tone);
743
+ border-radius: max(var(--fd-control-radius), 6px); background: var(--fd-surface); color: var(--fd-text);
744
+ box-shadow: 0 8px 24px rgba(15, 20, 25, 0.25); font-size: 13.5px;
745
+ }
746
+ .fd-say > span { flex: 1 1 auto; min-width: 0; }
747
+ /* A button whose steps are running: busy, a turning ring beside its words, not pressed again. */
748
+ .fd-button[aria-busy="true"], .fd-stat[aria-busy="true"] { cursor: progress; }
749
+ .fd-button[aria-busy="true"]::after {
750
+ content: ""; width: 0.85em; height: 0.85em; border: 2px solid currentColor; border-inline-end-color: transparent; border-radius: 50%;
751
+ animation: fd-spin 0.8s linear infinite;
752
+ }
753
+ @keyframes fd-spin { to { rotate: 1turn; } }
754
+ /* A page opened in a form's place: Back over it, the way the page reads. */
755
+ .fd-back { margin: 8px 12px; }
756
+ .fd-back::before { content: "←"; }
757
+ .fd-back:dir(rtl)::before { content: "→"; }
758
+ .fd-form[data-scheme] > .fd-back { margin: 12px 20px 0; }
591
759
  /* A page in a dialog: a head with its title and ×, a body that scrolls, a foot with Discard and Save & Close. */
592
760
  .fd-form-dialog {
593
761
  display: flex; flex-direction: column; width: 100%; max-height: min(90vh, 100%); min-height: 0;
@@ -598,8 +766,10 @@ export const FIELDIA_CSS = /* css */ `
598
766
  .fd-form-dialog.fd-size-small { max-width: 440px; }
599
767
  .fd-form-dialog.fd-size-medium { max-width: 760px; }
600
768
  .fd-form-dialog.fd-size-large { max-width: 1080px; }
601
- .fd-form-dialog-backdrop:has(> .fd-size-full) { padding: 0; }
602
- .fd-form-dialog.fd-size-full { max-width: none; max-height: none; height: 100%; border-radius: 0; }
769
+ /* A dialog of the full size, and a panel (below): the whole height, square, nothing round it. */
770
+ .fd-form-dialog-backdrop:has(> .fd-size-full), .fd-form-panel-backdrop { padding: 0; }
771
+ .fd-form-dialog:is(.fd-size-full, .fd-form-panel) { max-height: none; height: 100%; border-radius: 0; }
772
+ .fd-size-full { max-width: none; }
603
773
  .fd-form-dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 16px; border-block-end: 1px solid var(--fd-border); background: var(--fd-surface); }
604
774
  .fd-form-dialog-title { margin: 0; font-size: 16px; font-weight: 600; }
605
775
  .fd-dialog-close { border: none; background: none; cursor: pointer; font-size: 22px; line-height: 1; padding: 2px 8px; border-radius: 4px; color: var(--fd-muted); }
@@ -620,8 +790,33 @@ export const FIELDIA_CSS = /* css */ `
620
790
  /* A page with no sheet of its own sits on the dialog's surface, clear of its edges. */
621
791
  .fd-form-dialog-body:not(:has(.fd-sheet-layout)) { background: var(--fd-surface); padding: 16px 20px 20px; }
622
792
  .fd-form-dialog-foot { padding: 12px 16px; border-block-start: 1px solid var(--fd-border); background: var(--fd-surface); margin: 0; }
623
- @media (prefers-reduced-motion: reduce) { .fd-form *, .fd-form *::before, .fd-form *::after { transition: none !important; } }
793
+ /* A page in a side panel: at the inline-end edge unless it names another, the page behind dimmed, sliding in from its edge; on a phone, the whole screen. */
794
+ .fd-form-panel-backdrop { justify-items: end; }
795
+ .fd-form-panel { max-width: 560px; position: relative; }
796
+ /* Its question before changes are dropped sits over the panel, not over the page. */
797
+ .fd-form-panel > .fd-dialog-backdrop { position: absolute; }
798
+ .fd-width-narrow { max-width: 420px; }
799
+ .fd-width-wide { max-width: 720px; }
800
+ /* The other edges: the start of the line as the page reads; the left, right, top or bottom whatever it reads, the top and bottom the whole width.
801
+ Each says where its slide starts (--fd-from) and which edge it steps back from (--fd-back): the right unless told. */
802
+ .fd-form-panel[data-side="start"] { justify-self: start; }
803
+ .fd-form-panel[data-side="left"] { justify-self: left; }
804
+ .fd-form-panel[data-side="right"] { justify-self: right; }
805
+ .fd-form-panel[data-side="top"] { align-self: start; --fd-from: 0 -100%; --fd-back: 48px 0 0; }
806
+ .fd-form-panel[data-side="bottom"] { align-self: end; --fd-from: 0 100%; --fd-back: 0 0 48px; }
807
+ .fd-form-panel[data-side="end"]:dir(rtl), .fd-form-panel[data-side="start"]:dir(ltr), .fd-form-panel[data-side="left"] { --fd-from: -100% 0; --fd-back: 0 0 0 48px; }
808
+ .fd-form-panel:is([data-side="top"], [data-side="bottom"]) { max-width: none; height: 60%; }
809
+ .fd-form-panel.fd-height-short { height: 40%; }
810
+ .fd-form-panel.fd-height-tall { height: 85%; }
811
+ /* A panel opened from another: the older one steps back from its own edge, still in sight. */
812
+ .fd-form-panel[data-behind] { margin: var(--fd-back, 0 48px 0 0); }
813
+ @media (max-width: 600px) { .fd-form-dialog.fd-form-panel[data-side] { max-width: none; height: 100%; margin: 0; --fd-from: 0 100%; } .fd-form-dialog.fd-form-panel[data-side="top"] { --fd-from: 0 -100%; } }
814
+ @media (prefers-reduced-motion: no-preference) { .fd-form-panel { animation: fd-slide 0.25s ease-out; transition: margin 0.2s; } }
815
+ @keyframes fd-slide { from { translate: var(--fd-from, 100% 0); } }
816
+ @media (prefers-reduced-motion: reduce) { .fd-form *, .fd-form *::before, .fd-form *::after { transition: none !important; } .fd-button[aria-busy="true"]::after { animation: none; } }
624
817
  `;
818
+ /** Fieldia's whole stylesheet: the skins, then the layout over them, the inputs' details, the question kinds and the choices' details. */
819
+ export const FIELDIA_CSS = SKINS_CSS + LAYOUT_CSS + INPUTS_CSS + KINDS_CSS + CHOICES_CSS + PARTS_CSS;
625
820
  const STYLE_ID = 'fieldia-styles';
626
821
  /** Add Fieldia's stylesheet to a document, once. */
627
822
  export function installStyles(document) {
@@ -1 +1 @@
1
- {"version":3,"file":"styles.mjs","sourceRoot":"","sources":["../../../../../libs/widgets/src/lib/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkmBpC,CAAC;AAEF,MAAM,QAAQ,GAAG,gBAAgB,CAAC;AAElC,oDAAoD;AACpD,MAAM,UAAU,aAAa,CAAC,QAAkB;IAC9C,IAAI,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC;QAAE,OAAO;IAC9C,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,GAAG,QAAQ,CAAC;IACpB,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;IAChC,CAAC,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC"}
1
+ {"version":3,"file":"styles.mjs","sourceRoot":"","sources":["../../../../../libs/widgets/src/lib/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAW,CAAC;AAEjE,+FAA+F;AAC/F,MAAM,SAAS,GAAG,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsxB3B,CAAC;AAEF,0IAA0I;AAC1I,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAErG,MAAM,QAAQ,GAAG,gBAAgB,CAAC;AAElC,oDAAoD;AACpD,MAAM,UAAU,aAAa,CAAC,QAAkB;IAC9C,IAAI,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC;QAAE,OAAO;IAC9C,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,GAAG,QAAQ,CAAC;IACpB,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;IAChC,CAAC,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Locale } from '@fieldia/core';
2
+ /**
3
+ * A currency as the page's language writes it beside an amount: its symbol —
4
+ * "$", "€", "E£" — and whether it comes after the number, as in "12,50 €".
5
+ * A name that is no currency code stays as it is, before the number.
6
+ */
7
+ export declare function currencySymbol(code: string, locale: Locale): {
8
+ text: string;
9
+ after: boolean;
10
+ };
@@ -0,0 +1,10 @@
1
+ import type { Locale } from '@fieldia/core';
2
+ /**
3
+ * A currency as the page's language writes it beside an amount: its symbol —
4
+ * "$", "€", "E£" — and whether it comes after the number, as in "12,50 €".
5
+ * A name that is no currency code stays as it is, before the number.
6
+ */
7
+ export declare function currencySymbol(code: string, locale: Locale): {
8
+ text: string;
9
+ after: boolean;
10
+ };
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.currencySymbol = currencySymbol;
4
+ /**
5
+ * A currency as the page's language writes it beside an amount: its symbol —
6
+ * "$", "€", "E£" — and whether it comes after the number, as in "12,50 €".
7
+ * A name that is no currency code stays as it is, before the number.
8
+ */
9
+ function currencySymbol(code, locale) {
10
+ try {
11
+ const parts = new Intl.NumberFormat(locale, { style: 'currency', currency: code, currencyDisplay: 'narrowSymbol' }).formatToParts(1);
12
+ const at = parts.findIndex((part) => part.type === 'currency');
13
+ return { text: parts[at].value, after: at > parts.findIndex((part) => part.type === 'integer') };
14
+ }
15
+ catch {
16
+ return { text: code, after: false };
17
+ }
18
+ }
19
+ //# sourceMappingURL=units.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"units.js","sourceRoot":"","sources":["../../../../../libs/widgets/src/lib/units.ts"],"names":[],"mappings":";;AAOA,wCAQC;AAbD;;;;GAIG;AACH,SAAgB,cAAc,CAAC,IAAY,EAAE,MAAc;IACzD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QACrI,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;QAC/D,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;IACnG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACtC,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * A currency as the page's language writes it beside an amount: its symbol —
3
+ * "$", "€", "E£" — and whether it comes after the number, as in "12,50 €".
4
+ * A name that is no currency code stays as it is, before the number.
5
+ */
6
+ export function currencySymbol(code, locale) {
7
+ try {
8
+ const parts = new Intl.NumberFormat(locale, { style: 'currency', currency: code, currencyDisplay: 'narrowSymbol' }).formatToParts(1);
9
+ const at = parts.findIndex((part) => part.type === 'currency');
10
+ return { text: parts[at].value, after: at > parts.findIndex((part) => part.type === 'integer') };
11
+ }
12
+ catch {
13
+ return { text: code, after: false };
14
+ }
15
+ }
16
+ //# sourceMappingURL=units.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"units.mjs","sourceRoot":"","sources":["../../../../../libs/widgets/src/lib/units.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAAc;IACzD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QACrI,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;QAC/D,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;IACnG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACtC,CAAC;AACH,CAAC"}