@coffer-org/plugin-transit 7.0.1 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bus_route/index.js +3 -3
- package/dist/schema.js +299 -26
- package/package.json +4 -4
package/dist/bus_route/index.js
CHANGED
|
@@ -15,9 +15,9 @@ export default defineShelf({
|
|
|
15
15
|
from: field.string({ label: 'transit.bus_route.fields.from', rules: { max: 100 }, ui: { span: 3 } }),
|
|
16
16
|
to: field.string({ label: 'transit.bus_route.fields.to', rules: { max: 100 }, ui: { span: 3 } }),
|
|
17
17
|
stop: field.string({ label: 'transit.bus_route.fields.stop', rules: { max: 200 }, ui: { span: 3 } }),
|
|
18
|
-
weekday_times: field.
|
|
19
|
-
saturday_times: field.
|
|
20
|
-
sunday_times: field.
|
|
18
|
+
weekday_times: field.timetable({ label: 'transit.bus_route.fields.weekday_times', ui: { span: 12 } }),
|
|
19
|
+
saturday_times: field.timetable({ label: 'transit.bus_route.fields.saturday_times', ui: { span: 6 } }),
|
|
20
|
+
sunday_times: field.timetable({ label: 'transit.bus_route.fields.sunday_times', ui: { span: 6 } }),
|
|
21
21
|
tags: field.tags({ label: 'transit.bus_route.fields.tags' }),
|
|
22
22
|
notes: field.text({ label: 'transit.bus_route.fields.notes', rules: { max: 500 } }),
|
|
23
23
|
},
|
package/dist/schema.js
CHANGED
|
@@ -4701,6 +4701,13 @@ function wrapKey(key, opts, meta) {
|
|
|
4701
4701
|
span: opts.span
|
|
4702
4702
|
}
|
|
4703
4703
|
};
|
|
4704
|
+
if (opts.faces !== void 0) m = {
|
|
4705
|
+
...m,
|
|
4706
|
+
hints: {
|
|
4707
|
+
...m.hints,
|
|
4708
|
+
faces: opts.faces
|
|
4709
|
+
}
|
|
4710
|
+
};
|
|
4704
4711
|
if (opts.default !== void 0) m = {
|
|
4705
4712
|
...m,
|
|
4706
4713
|
default: opts.default
|
|
@@ -4800,6 +4807,7 @@ function normalizeOpts(rawIn) {
|
|
|
4800
4807
|
...v.valueLabel !== void 0 ? { valueLabel: v.valueLabel } : {},
|
|
4801
4808
|
compareWith: v.compareWith,
|
|
4802
4809
|
span: v.span,
|
|
4810
|
+
faces: v.faces,
|
|
4803
4811
|
emphasis: v.emphasis,
|
|
4804
4812
|
noLabel: v.noLabel,
|
|
4805
4813
|
role: v.role,
|
|
@@ -5708,6 +5716,63 @@ registerPreset("slug", "string", {}, {
|
|
|
5708
5716
|
};
|
|
5709
5717
|
}
|
|
5710
5718
|
});
|
|
5719
|
+
/**
|
|
5720
|
+
* Identifier — a code printed for a machine and read back by one: a serial number, an order
|
|
5721
|
+
* number, a policy number, an IMEI. What a person actually DOES with one is copy it, which is
|
|
5722
|
+
* why this is a type of its own and not `f.string({ ui: { voice: 'data' } })`: the machine face
|
|
5723
|
+
* is one word on any string now, but the click that copies belongs to the kind.
|
|
5724
|
+
*
|
|
5725
|
+
* Deliberately unvalidated beyond a length: an identifier's format belongs to whoever issued
|
|
5726
|
+
* it, and a pattern here would reject the next manufacturer's.
|
|
5727
|
+
*
|
|
5728
|
+
* @layer preset
|
|
5729
|
+
* @base string
|
|
5730
|
+
* @prim text
|
|
5731
|
+
* @widget identifier
|
|
5732
|
+
* @example f.identifier({ label: 'mod.fields.serialNumber' })
|
|
5733
|
+
*/
|
|
5734
|
+
function identifier(o) {
|
|
5735
|
+
return declare("identifier", o);
|
|
5736
|
+
}
|
|
5737
|
+
registerPreset("identifier", "string", {}, {
|
|
5738
|
+
kind: "identifier",
|
|
5739
|
+
widget: "identifier",
|
|
5740
|
+
build() {
|
|
5741
|
+
return {
|
|
5742
|
+
column: "text",
|
|
5743
|
+
zod: string$1(),
|
|
5744
|
+
hints: {}
|
|
5745
|
+
};
|
|
5746
|
+
}
|
|
5747
|
+
});
|
|
5748
|
+
/**
|
|
5749
|
+
* The machine-readable zone of a travel document — the identifier taken to its limit: printed
|
|
5750
|
+
* for a scanner, not for a person. Fixed pitch, chevrons kept as the filler they are, and the
|
|
5751
|
+
* line breaks preserved, because an MRZ's line structure is part of what it encodes.
|
|
5752
|
+
*
|
|
5753
|
+
* Unvalidated on purpose, like `identifier`: the ICAO line formats differ by document type, and
|
|
5754
|
+
* a strip transcribed from a real document is worth storing even when it does not check out.
|
|
5755
|
+
*
|
|
5756
|
+
* @layer preset
|
|
5757
|
+
* @base string
|
|
5758
|
+
* @prim text
|
|
5759
|
+
* @widget mrz
|
|
5760
|
+
* @example f.mrz({ label: 'documents.personal_document.fields.mrz' })
|
|
5761
|
+
*/
|
|
5762
|
+
function mrz(o) {
|
|
5763
|
+
return declare("mrz", o);
|
|
5764
|
+
}
|
|
5765
|
+
registerPreset("mrz", "string", {}, {
|
|
5766
|
+
kind: "mrz",
|
|
5767
|
+
widget: "mrz",
|
|
5768
|
+
build() {
|
|
5769
|
+
return {
|
|
5770
|
+
column: "text",
|
|
5771
|
+
zod: string$1(),
|
|
5772
|
+
hints: {}
|
|
5773
|
+
};
|
|
5774
|
+
}
|
|
5775
|
+
});
|
|
5711
5776
|
var COLOR_RE = /^#[0-9a-fA-F]{6}$/;
|
|
5712
5777
|
/**
|
|
5713
5778
|
* Hex color — kind 'color', `#rrggbb` + swatch widget.
|
|
@@ -5992,6 +6057,38 @@ registerPreset("tag", "string", {}, {
|
|
|
5992
6057
|
}
|
|
5993
6058
|
});
|
|
5994
6059
|
/**
|
|
6060
|
+
* A location written the way it is said aloud: workshop › shelf 2 › box. A `string` fixed to
|
|
6061
|
+
* `multiple`, exactly as `f.tags` is, because a place inside a place inside a place IS a
|
|
6062
|
+
* sequence — the plurality is the type, not a modifier someone remembered to add.
|
|
6063
|
+
*
|
|
6064
|
+
* Distinct from `f.tags`, which stores the same shape: tags are an unordered SET, and a path is
|
|
6065
|
+
* an ordered CHAIN where each step is inside the one before it. Drawn as chips, that
|
|
6066
|
+
* containment — the only thing the value actually carries — is lost.
|
|
6067
|
+
*
|
|
6068
|
+
* @layer preset
|
|
6069
|
+
* @base string
|
|
6070
|
+
* @prim text
|
|
6071
|
+
* @widget path
|
|
6072
|
+
* @example f.path({ label: 'things.storage_location.fields.path' })
|
|
6073
|
+
*/
|
|
6074
|
+
function path(o) {
|
|
6075
|
+
return declare("path", {
|
|
6076
|
+
...o,
|
|
6077
|
+
multiple: true
|
|
6078
|
+
});
|
|
6079
|
+
}
|
|
6080
|
+
registerPreset("path", "string", {}, {
|
|
6081
|
+
kind: "path",
|
|
6082
|
+
widget: "path",
|
|
6083
|
+
build() {
|
|
6084
|
+
return {
|
|
6085
|
+
column: "text",
|
|
6086
|
+
zod: string$1(),
|
|
6087
|
+
hints: {}
|
|
6088
|
+
};
|
|
6089
|
+
}
|
|
6090
|
+
});
|
|
6091
|
+
/**
|
|
5995
6092
|
* Tags — `tag({ multiple: true })`.
|
|
5996
6093
|
*
|
|
5997
6094
|
* @layer preset
|
|
@@ -6184,6 +6281,34 @@ registerPreset("reminder", "date", { lead: 30 }, {
|
|
|
6184
6281
|
};
|
|
6185
6282
|
}
|
|
6186
6283
|
});
|
|
6284
|
+
/** Timetable — a set of times of day, read as a schedule rather than as a bag of values.
|
|
6285
|
+
* kind 'timetable', prim 'time', always `multiple`.
|
|
6286
|
+
*
|
|
6287
|
+
* Same shape as `f.reminder`/`f.age` over `date`: a semantic type whose renderer knows what
|
|
6288
|
+
* the values MEAN. Everything it shows beyond the times themselves — when the service starts
|
|
6289
|
+
* and ends, how many runs there are, which one is next — is derived from the values at render
|
|
6290
|
+
* time, never stored: a "next departure" is wrong the moment it is written down, exactly the
|
|
6291
|
+
* argument `f.age` already makes for an age.
|
|
6292
|
+
*
|
|
6293
|
+
* Storage is a plain multiple `time`, so a field can be switched to this from
|
|
6294
|
+
* `f.time({ multiple: true })` and back with no migration.
|
|
6295
|
+
*
|
|
6296
|
+
* @layer preset
|
|
6297
|
+
* @base time
|
|
6298
|
+
* @prim time
|
|
6299
|
+
* @widget timetable
|
|
6300
|
+
* @example f.timetable({ label: 'mod.fields.weekdays' })
|
|
6301
|
+
*/
|
|
6302
|
+
function timetable(o) {
|
|
6303
|
+
return declare("timetable", {
|
|
6304
|
+
...o,
|
|
6305
|
+
multiple: true
|
|
6306
|
+
});
|
|
6307
|
+
}
|
|
6308
|
+
registerPreset("timetable", "time", {}, {
|
|
6309
|
+
kind: "timetable",
|
|
6310
|
+
widget: "timetable"
|
|
6311
|
+
});
|
|
6187
6312
|
/** Age — date whose whole-year age (as of today) renders alongside it, e.g. a birth date.
|
|
6188
6313
|
* kind 'age', prim 'date'. The age itself is computed at RENDER time, never stored: unlike a
|
|
6189
6314
|
* `mutate`-driven computed field, it must be right on every day that passes, not only the day
|
|
@@ -6398,6 +6523,9 @@ var presets = {
|
|
|
6398
6523
|
email,
|
|
6399
6524
|
tel,
|
|
6400
6525
|
slug,
|
|
6526
|
+
path,
|
|
6527
|
+
identifier,
|
|
6528
|
+
mrz,
|
|
6401
6529
|
color,
|
|
6402
6530
|
colorname,
|
|
6403
6531
|
title,
|
|
@@ -6412,6 +6540,7 @@ var presets = {
|
|
|
6412
6540
|
duration,
|
|
6413
6541
|
reminder,
|
|
6414
6542
|
age,
|
|
6543
|
+
timetable,
|
|
6415
6544
|
percent,
|
|
6416
6545
|
year,
|
|
6417
6546
|
weight,
|
|
@@ -7069,26 +7198,38 @@ function identity(opts) {
|
|
|
7069
7198
|
}
|
|
7070
7199
|
};
|
|
7071
7200
|
}
|
|
7072
|
-
/**
|
|
7201
|
+
/** One measure out of an optional max, from ONE OR MORE named sources, with an optional verdict.
|
|
7202
|
+
*
|
|
7203
|
+
* `source` takes several entries for the same reason `f.identity`'s `channels` does — it is a
|
|
7204
|
+
* role that holds a LIST, so `view.source` is an ordered list of names rather than one name.
|
|
7205
|
+
* Two ratings of the same film out of ten are one measure read twice, and drawing them apart is
|
|
7206
|
+
* what makes them incomparable: the eye has to carry the scale between two figures instead of
|
|
7207
|
+
* reading them against a shared one. `media/title` had exactly that, two `f.score` blocks of
|
|
7208
|
+
* `max: 10` held apart inside an `f.compare`, until this took the restriction off.
|
|
7209
|
+
*
|
|
7210
|
+
* NOT `multiple`. A multiple field is an anonymous array; these are NAMED sources, and the name
|
|
7211
|
+
* is what says which reading came from where. The two are different shapes and the block wants
|
|
7212
|
+
* this one.
|
|
7073
7213
|
*
|
|
7074
7214
|
* @layer block
|
|
7075
7215
|
* @base group
|
|
7076
7216
|
* @prim —
|
|
7077
7217
|
* @widget score
|
|
7078
|
-
* @example f.score({ source: {
|
|
7218
|
+
* @example f.score({ source: { imdb: f.real({ label: '…' }), tmdb: f.real({ label: '…' }) }, max: 10 })
|
|
7079
7219
|
*/
|
|
7080
7220
|
function score(opts) {
|
|
7081
|
-
const
|
|
7221
|
+
const names = Object.keys(opts.source ?? {});
|
|
7222
|
+
if (names.length === 0) throw new Error(`[field.score] slot 'source' expects at least one entry, got 0`);
|
|
7082
7223
|
const verdict = opts.verdict !== void 0 ? slot("score", "verdict", opts.verdict) : void 0;
|
|
7083
7224
|
return {
|
|
7084
7225
|
...group({
|
|
7085
7226
|
label: opts.label,
|
|
7086
|
-
fields: merge("score", source, verdict),
|
|
7227
|
+
fields: merge("score", opts.source, verdict),
|
|
7087
7228
|
ui: { kind: "score" }
|
|
7088
7229
|
}),
|
|
7089
7230
|
view: {
|
|
7090
7231
|
kind: "score",
|
|
7091
|
-
source:
|
|
7232
|
+
source: names,
|
|
7092
7233
|
max: opts.max,
|
|
7093
7234
|
verdict: verdict && Object.keys(verdict)[0]
|
|
7094
7235
|
}
|
|
@@ -7210,6 +7351,11 @@ function balance(opts) {
|
|
|
7210
7351
|
* @base group
|
|
7211
7352
|
* @prim —
|
|
7212
7353
|
* @widget route
|
|
7354
|
+
* A `stub` is the part of the ticket that is TORN OFF and kept — a seat, a gate, a booking
|
|
7355
|
+
* reference. Declaring one makes the block a ticket rather than a line: the two halves are
|
|
7356
|
+
* separated by a perforation, and the fields in the stub sit below it. Without one the block
|
|
7357
|
+
* is exactly what it was, a route from here to there, so no existing call changes.
|
|
7358
|
+
*
|
|
7213
7359
|
* @example f.route({ from: { from: f.string({ label: '…' }) }, to: { to: f.string({ label: '…' }) } })
|
|
7214
7360
|
*/
|
|
7215
7361
|
function route(opts) {
|
|
@@ -7218,9 +7364,10 @@ function route(opts) {
|
|
|
7218
7364
|
const depart = opts.depart !== void 0 ? slot("route", "depart", opts.depart) : void 0;
|
|
7219
7365
|
const arrive = opts.arrive !== void 0 ? slot("route", "arrive", opts.arrive) : void 0;
|
|
7220
7366
|
const duration = opts.duration !== void 0 ? slot("route", "duration", opts.duration) : void 0;
|
|
7367
|
+
const stub = opts.stub ?? {};
|
|
7221
7368
|
return {
|
|
7222
7369
|
...group({
|
|
7223
|
-
fields: merge("route", from, to, depart, arrive, duration),
|
|
7370
|
+
fields: merge("route", from, to, depart, arrive, duration, stub),
|
|
7224
7371
|
ui: { kind: "route" }
|
|
7225
7372
|
}),
|
|
7226
7373
|
view: {
|
|
@@ -7229,7 +7376,8 @@ function route(opts) {
|
|
|
7229
7376
|
to: Object.keys(to)[0],
|
|
7230
7377
|
depart: depart && Object.keys(depart)[0],
|
|
7231
7378
|
arrive: arrive && Object.keys(arrive)[0],
|
|
7232
|
-
duration: duration && Object.keys(duration)[0]
|
|
7379
|
+
duration: duration && Object.keys(duration)[0],
|
|
7380
|
+
stub: Object.keys(stub)
|
|
7233
7381
|
}
|
|
7234
7382
|
};
|
|
7235
7383
|
}
|
|
@@ -7407,6 +7555,81 @@ function specimen(opts) {
|
|
|
7407
7555
|
};
|
|
7408
7556
|
}
|
|
7409
7557
|
/**
|
|
7558
|
+
* Measurements against the range they were supposed to fall in, rendered from a single
|
|
7559
|
+
* collection source — see `stampCollection`. `analyte`, `value`, `unit`, `low` and `high` are
|
|
7560
|
+
* part KEYS inside each collection row, NOT `LayoutEl` positions — the same reasoning as
|
|
7561
|
+
* `manifest`'s `quantity`/`item`.
|
|
7562
|
+
*
|
|
7563
|
+
* The point is the COMPARISON. A `f.table` over the same rows prints the bounds as two more
|
|
7564
|
+
* columns and leaves the reader to do it; here each value sits on its own band with the
|
|
7565
|
+
* reference span marked on it, so "outside the range" is seen rather than worked out. That is
|
|
7566
|
+
* also the only thing on the row worth a colour — it is what the reader has to act on.
|
|
7567
|
+
*
|
|
7568
|
+
* `unit`, `low` and `high` are optional: a measurement with no published range (a culture, a
|
|
7569
|
+
* description) still belongs in the same list and simply gets no band.
|
|
7570
|
+
*
|
|
7571
|
+
* @layer block
|
|
7572
|
+
* @base group
|
|
7573
|
+
* @prim —
|
|
7574
|
+
* @widget assay
|
|
7575
|
+
* @example f.assay({ source: { results: f.group({ scope: 'nest', multiple: true, fields: { analyte: f.string({ label: '…' }), value: f.real({ label: '…' }) } }) }, analyte: 'analyte', value: 'value' })
|
|
7576
|
+
*/
|
|
7577
|
+
function assay(opts) {
|
|
7578
|
+
return stampCollection("assay", opts.source, opts.label, {
|
|
7579
|
+
kind: "assay",
|
|
7580
|
+
analyte: opts.analyte,
|
|
7581
|
+
value: opts.value,
|
|
7582
|
+
...opts.unit ? { unit: opts.unit } : {},
|
|
7583
|
+
...opts.low ? { low: opts.low } : {},
|
|
7584
|
+
...opts.high ? { high: opts.high } : {}
|
|
7585
|
+
});
|
|
7586
|
+
}
|
|
7587
|
+
/**
|
|
7588
|
+
* Value moving from one place to another, where the MOVEMENT is the subject — not one more
|
|
7589
|
+
* labelled row among the record's fields. The sum is set large in the machine voice, and the two
|
|
7590
|
+
* ends read as a path beneath it.
|
|
7591
|
+
*
|
|
7592
|
+
* amount — what moved. The one required role, and the reason the block exists
|
|
7593
|
+
* from — where it left. Absent on money that only arrived
|
|
7594
|
+
* to — where it arrived. Absent on money that only left
|
|
7595
|
+
* meta — the record's own remaining fields, under a rule: date, category, reference
|
|
7596
|
+
*
|
|
7597
|
+
* An absent end is not drawn, and that is the whole reading: money that left an account and
|
|
7598
|
+
* arrived nowhere IS an expense. It is read off which ends the record actually has, never
|
|
7599
|
+
* guessed from the shape of a value. What the movement MEANS beyond that — whether this
|
|
7600
|
+
* particular kind of transfer is good news — is carried by the classifier's own option `tone`,
|
|
7601
|
+
* the same declaration every other coloured value in the product uses.
|
|
7602
|
+
*
|
|
7603
|
+
* Distinct from `f.route`, which also has two ends: there the journey is the subject and the
|
|
7604
|
+
* ends are places, so it carries times and a duration; here the ends are accounts and the
|
|
7605
|
+
* subject is the quantity.
|
|
7606
|
+
*
|
|
7607
|
+
* @layer block
|
|
7608
|
+
* @base group
|
|
7609
|
+
* @prim —
|
|
7610
|
+
* @widget flow
|
|
7611
|
+
* @example f.flow({ amount: { amount: f.money({ label: '…' }) }, from: { source: f.relation({ label: '…' }) } })
|
|
7612
|
+
*/
|
|
7613
|
+
function flow(opts) {
|
|
7614
|
+
const amount = slot("flow", "amount", opts.amount);
|
|
7615
|
+
const from = opts.from !== void 0 ? slot("flow", "from", opts.from) : void 0;
|
|
7616
|
+
const to = opts.to !== void 0 ? slot("flow", "to", opts.to) : void 0;
|
|
7617
|
+
return {
|
|
7618
|
+
...group({
|
|
7619
|
+
label: opts.label,
|
|
7620
|
+
fields: merge("flow", amount, from, to, opts.meta),
|
|
7621
|
+
ui: { kind: "flow" }
|
|
7622
|
+
}),
|
|
7623
|
+
view: {
|
|
7624
|
+
kind: "flow",
|
|
7625
|
+
amount: Object.keys(amount)[0],
|
|
7626
|
+
from: from && Object.keys(from)[0],
|
|
7627
|
+
to: to && Object.keys(to)[0],
|
|
7628
|
+
meta: Object.keys(opts.meta ?? {})
|
|
7629
|
+
}
|
|
7630
|
+
};
|
|
7631
|
+
}
|
|
7632
|
+
/**
|
|
7410
7633
|
* A packing/cargo manifest rendered from a single collection source — see `stampCollection`.
|
|
7411
7634
|
* `quantity` and `item` are part KEYS inside each collection row, NOT `LayoutEl` positions —
|
|
7412
7635
|
* the same reasoning as `journal`'s `date`/`text`.
|
|
@@ -7453,13 +7676,25 @@ function table(opts) {
|
|
|
7453
7676
|
} : {},
|
|
7454
7677
|
...opts.groupBy ? { groupBy: opts.groupBy } : {},
|
|
7455
7678
|
...opts.totals ? { totals: opts.totals } : {},
|
|
7679
|
+
...opts.summary ? { summary: opts.summary } : {},
|
|
7456
7680
|
...opts.numbered ? { numbered: true } : {}
|
|
7457
7681
|
});
|
|
7458
7682
|
}
|
|
7459
7683
|
/**
|
|
7460
|
-
* An
|
|
7461
|
-
*
|
|
7462
|
-
*
|
|
7684
|
+
* An identity document, drawn as the card it is: a caption and its number across the top, a
|
|
7685
|
+
* portrait beside the holder's own fields, the issuing details under a rule, and the
|
|
7686
|
+
* machine-readable strip at the foot. `view` names each role (Task 5) — see `masthead`'s own
|
|
7687
|
+
* doc comment for what an ordered name list means.
|
|
7688
|
+
*
|
|
7689
|
+
* overline — the caption at the top left ("PASSPORT", "DRIVING LICENCE")
|
|
7690
|
+
* number — the document's number, set apart at the top right
|
|
7691
|
+
* photo — the portrait. One field, rendered in a portrait frame beside the body
|
|
7692
|
+
* meta — the card's OWN fields, labelled, at each field's declared span
|
|
7693
|
+
* footer — the fields below the rule: issued, authority, record number
|
|
7694
|
+
* mrz — the machine-readable strip, set in monospace at the foot
|
|
7695
|
+
*
|
|
7696
|
+
* Every role is optional but `number`: a bank card has no `mrz`, a library card no `photo`,
|
|
7697
|
+
* and the card simply omits the part it was given nothing for.
|
|
7463
7698
|
*
|
|
7464
7699
|
* @layer block
|
|
7465
7700
|
* @base group
|
|
@@ -7470,16 +7705,21 @@ function table(opts) {
|
|
|
7470
7705
|
function idcard(opts) {
|
|
7471
7706
|
const overline = opts.overline !== void 0 ? slot("idcard", "overline", opts.overline) : void 0;
|
|
7472
7707
|
const number = slot("idcard", "number", opts.number);
|
|
7708
|
+
const photo = opts.photo !== void 0 ? slot("idcard", "photo", opts.photo) : void 0;
|
|
7709
|
+
const mrz = opts.mrz !== void 0 ? slot("idcard", "mrz", opts.mrz) : void 0;
|
|
7473
7710
|
return {
|
|
7474
7711
|
...group({
|
|
7475
|
-
fields: merge("idcard", overline, number, opts.meta),
|
|
7712
|
+
fields: merge("idcard", overline, number, photo, opts.meta, opts.footer, mrz),
|
|
7476
7713
|
ui: { kind: "idcard" }
|
|
7477
7714
|
}),
|
|
7478
7715
|
view: {
|
|
7479
7716
|
kind: "idcard",
|
|
7480
7717
|
overline: overline && Object.keys(overline)[0],
|
|
7481
7718
|
number: Object.keys(number)[0],
|
|
7482
|
-
|
|
7719
|
+
photo: photo && Object.keys(photo)[0],
|
|
7720
|
+
meta: Object.keys(opts.meta ?? {}),
|
|
7721
|
+
footer: Object.keys(opts.footer ?? {}),
|
|
7722
|
+
mrz: mrz && Object.keys(mrz)[0]
|
|
7483
7723
|
}
|
|
7484
7724
|
};
|
|
7485
7725
|
}
|
|
@@ -7564,6 +7804,8 @@ var blocks = {
|
|
|
7564
7804
|
nutrition,
|
|
7565
7805
|
specimen,
|
|
7566
7806
|
manifest,
|
|
7807
|
+
assay,
|
|
7808
|
+
flow,
|
|
7567
7809
|
table,
|
|
7568
7810
|
idcard,
|
|
7569
7811
|
properties,
|
|
@@ -8426,6 +8668,11 @@ function group(o) {
|
|
|
8426
8668
|
for (const f of fields) if (!("key" in f && f.key !== void 0) && !hasChildren(f)) throw new Error(`[field.group] a 'nest' group's children must be fields or groups, not layout elements`);
|
|
8427
8669
|
for (const k of r.unique ?? []) if (!fields.some((f) => "key" in f && f.key === k)) throw new Error(`[field.group] unique key '${k}' is not a subfield`);
|
|
8428
8670
|
} else if (o.value !== void 0) throw new Error(`[field.group] value requires scope 'nest' — a hoist group owns no children to write`);
|
|
8671
|
+
const title = v.title ?? [];
|
|
8672
|
+
if (title.length > 0) {
|
|
8673
|
+
if (!o.multiple) throw new Error(`[field.group] ui.title heads a collection's ROWS — it needs multiple: true`);
|
|
8674
|
+
for (const name of title) if (!fields.some((f) => "key" in f && f.key === name)) throw new Error(`[field.group] ui.title '${name}' is not one of its fields`);
|
|
8675
|
+
}
|
|
8429
8676
|
return {
|
|
8430
8677
|
el: "group",
|
|
8431
8678
|
scope,
|
|
@@ -8438,6 +8685,7 @@ function group(o) {
|
|
|
8438
8685
|
display: v.display ?? "wrap",
|
|
8439
8686
|
kind: v.kind,
|
|
8440
8687
|
fixed: r.fixed,
|
|
8688
|
+
view: title.length > 0 ? { title } : void 0,
|
|
8441
8689
|
fields
|
|
8442
8690
|
};
|
|
8443
8691
|
}
|
|
@@ -8607,6 +8855,31 @@ function info(textKey) {
|
|
|
8607
8855
|
};
|
|
8608
8856
|
}
|
|
8609
8857
|
/**
|
|
8858
|
+
* What else points AT this record — the inverse of a relation, which is often the more useful
|
|
8859
|
+
* direction on a record page: a box is more usefully "what is in it" than "what it is in".
|
|
8860
|
+
*
|
|
8861
|
+
* Stores NOTHING and has no column: it declares where to look, and the server answers by asking
|
|
8862
|
+
* the pointing shelf. That is why it is a pseudo-element beside `divider` and `info` rather than
|
|
8863
|
+
* a field — there is no value here to validate or save.
|
|
8864
|
+
*
|
|
8865
|
+
* `from` names the pointing side explicitly (which shelf, and WHICH of its fields), never
|
|
8866
|
+
* "everything that happens to point here": a shelf may point at the same target through two
|
|
8867
|
+
* fields — a transaction has a source account and a destination account — and a panel that
|
|
8868
|
+
* merged them would answer a question nobody asked.
|
|
8869
|
+
*
|
|
8870
|
+
* @layer primitive
|
|
8871
|
+
* @prim —
|
|
8872
|
+
* @widget backrefs
|
|
8873
|
+
* @example f.backrefs({ label: 'mod.fields.storedHere', from: { library: 'things', shelf: 'item', field: 'location' } })
|
|
8874
|
+
*/
|
|
8875
|
+
function backrefs(o) {
|
|
8876
|
+
return {
|
|
8877
|
+
el: "backrefs",
|
|
8878
|
+
label: o.label,
|
|
8879
|
+
from: o.from
|
|
8880
|
+
};
|
|
8881
|
+
}
|
|
8882
|
+
/**
|
|
8610
8883
|
* Action button: invokes the handler registered in actionRegistry under the key `value`.
|
|
8611
8884
|
*
|
|
8612
8885
|
* @layer primitive
|
|
@@ -8931,20 +9204,22 @@ registerType("time", {
|
|
|
8931
9204
|
prim: "time",
|
|
8932
9205
|
widget: "time",
|
|
8933
9206
|
build(o) {
|
|
8934
|
-
const granularity = o.config?.granularity ?? "
|
|
9207
|
+
const granularity = o.config?.granularity ?? "minute";
|
|
9208
|
+
const s = string$1(reqErr()).regex({
|
|
9209
|
+
hour: /^([01]\d|2[0-3])$/,
|
|
9210
|
+
minute: /^([01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/,
|
|
9211
|
+
second: /^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$/
|
|
9212
|
+
}[granularity], { message: vmsg("time_format") });
|
|
8935
9213
|
return {
|
|
8936
9214
|
column: "time",
|
|
8937
|
-
zod:
|
|
8938
|
-
hour: /^([01]\d|2[0-3])$/,
|
|
8939
|
-
minute: /^([01]\d|2[0-3]):[0-5]\d$/,
|
|
8940
|
-
second: /^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$/
|
|
8941
|
-
}[granularity], { message: vmsg("time_format") }),
|
|
9215
|
+
zod: granularity === "minute" ? s.transform((v) => v.slice(0, 5)) : s,
|
|
8942
9216
|
hints: { granularity }
|
|
8943
9217
|
};
|
|
8944
9218
|
}
|
|
8945
9219
|
});
|
|
8946
9220
|
/**
|
|
8947
|
-
* Time-of-day value with configurable granularity ('hour' | 'minute' | 'second', default
|
|
9221
|
+
* Time-of-day value with configurable granularity ('hour' | 'minute' | 'second', default
|
|
9222
|
+
* 'minute' — the same default `f.datetime` has always had).
|
|
8948
9223
|
*
|
|
8949
9224
|
* @layer primitive
|
|
8950
9225
|
* @prim time
|
|
@@ -10189,7 +10464,8 @@ var PRIMITIVES = {
|
|
|
10189
10464
|
url,
|
|
10190
10465
|
divider,
|
|
10191
10466
|
info,
|
|
10192
|
-
button
|
|
10467
|
+
button,
|
|
10468
|
+
backrefs
|
|
10193
10469
|
};
|
|
10194
10470
|
/** Assembles `f`, guaranteeing no preset/block shadows a primitive. */
|
|
10195
10471
|
function composeF(presets, blocks) {
|
|
@@ -11091,19 +11367,16 @@ var bus_route_default = defineShelf({
|
|
|
11091
11367
|
rules: { max: 200 },
|
|
11092
11368
|
ui: { span: 3 }
|
|
11093
11369
|
}),
|
|
11094
|
-
weekday_times: field.
|
|
11370
|
+
weekday_times: field.timetable({
|
|
11095
11371
|
label: "transit.bus_route.fields.weekday_times",
|
|
11096
|
-
multiple: true,
|
|
11097
11372
|
ui: { span: 12 }
|
|
11098
11373
|
}),
|
|
11099
|
-
saturday_times: field.
|
|
11374
|
+
saturday_times: field.timetable({
|
|
11100
11375
|
label: "transit.bus_route.fields.saturday_times",
|
|
11101
|
-
multiple: true,
|
|
11102
11376
|
ui: { span: 6 }
|
|
11103
11377
|
}),
|
|
11104
|
-
sunday_times: field.
|
|
11378
|
+
sunday_times: field.timetable({
|
|
11105
11379
|
label: "transit.bus_route.fields.sunday_times",
|
|
11106
|
-
multiple: true,
|
|
11107
11380
|
ui: { span: 6 }
|
|
11108
11381
|
}),
|
|
11109
11382
|
tags: field.tags({ label: "transit.bus_route.fields.tags" }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffer-org/plugin-transit",
|
|
3
|
-
"version": "7.0
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24"
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"test": "node --import tsx/esm --test 'src/runtime/*.test.ts'"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@coffer-org/sdk": "^7.
|
|
30
|
-
"@coffer-org/server": "^7.
|
|
31
|
-
"@coffer-org/helper-dav": "^7.
|
|
29
|
+
"@coffer-org/sdk": "^7.3.0",
|
|
30
|
+
"@coffer-org/server": "^7.3.0",
|
|
31
|
+
"@coffer-org/helper-dav": "^7.1.0"
|
|
32
32
|
},
|
|
33
33
|
"coffer": {
|
|
34
34
|
"runtime": "node",
|