@0001-labs/design-system-1 0.3.0-alpha.19 → 0.3.0-alpha.21
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/DS1/0-face/app-banner.ts +1 -1
- package/DS1/0-face/bento.ts +84 -0
- package/DS1/0-face/calendar.ts +2 -2
- package/DS1/1-root/bento.css +97 -0
- package/DS1/1-root/card.css +6 -1
- package/DS1/1-root/cjk.css +1 -1
- package/DS1/1-root/controls.css +1 -0
- package/DS1/1-root/fonts.css +1 -1
- package/DS1/1-root/one.css +1 -1
- package/DS1/1-root/one.semantic.css +1 -1
- package/DS1/3-unit/calendar-base.ts +31 -22
- package/DS1/3-unit/ds-bento.ts +67 -0
- package/DS1/3-unit/ds-calendar.ts +477 -22
- package/DS1/3-unit/styles/ds-bento.css +66 -0
- package/DS1/3-unit/styles/ds-calendar.css +119 -1
- package/DS1/index.ts +1 -1
- package/dist/0-face/app-banner.js +1 -1
- package/dist/0-face/bento.d.ts +41 -0
- package/dist/0-face/bento.d.ts.map +1 -0
- package/dist/0-face/bento.js +77 -0
- package/dist/0-face/calendar.js +2 -2
- package/dist/3-unit/calendar-base.d.ts +17 -12
- package/dist/3-unit/calendar-base.d.ts.map +1 -1
- package/dist/3-unit/calendar-base.js +21 -16
- package/dist/3-unit/ds-bento.d.ts +31 -0
- package/dist/3-unit/ds-bento.d.ts.map +1 -0
- package/dist/3-unit/ds-bento.js +47 -0
- package/dist/3-unit/ds-calendar-large.d.ts +3 -4
- package/dist/3-unit/ds-calendar-large.d.ts.map +1 -1
- package/dist/3-unit/ds-calendar.d.ts +139 -12
- package/dist/3-unit/ds-calendar.d.ts.map +1 -1
- package/dist/3-unit/ds-calendar.js +464 -23
- package/dist/design-system-1.bundle.js +1125 -1095
- package/dist/design-system-1.bundle.js.map +1 -1
- package/dist/design-system-1.bundle.min.js +2484 -2457
- package/dist/design-system-1.bundle.min.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/DS1/3-unit/ds-date-picker.ts +0 -540
- package/DS1/3-unit/styles/ds-date-picker.css +0 -124
- package/dist/3-unit/ds-date-picker.d.ts +0 -203
- package/dist/3-unit/ds-date-picker.d.ts.map +0 -1
- package/dist/3-unit/ds-date-picker.js +0 -499
package/DS1/0-face/app-banner.ts
CHANGED
|
@@ -101,7 +101,7 @@ export function ensureSmartAppBanner(options: AppBannerOptions): void {
|
|
|
101
101
|
const meta = document.createElement("meta");
|
|
102
102
|
meta.name = "apple-itunes-app";
|
|
103
103
|
meta.content = [`app-id=${options.appId}`, options.open ? `app-argument=${options.open}` : ""].filter(Boolean).join(", ");
|
|
104
|
-
document.head.
|
|
104
|
+
document.head.appendChild(meta);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/**
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bentos without Lit: places the tiles of a `.ds-bento[data-squares]` (drawn
|
|
3
|
+
* by `1-root/bento.css`) on their squares and lets each surface reach a
|
|
4
|
+
* quarter square towards the tiles beside it, so the tiles stand half a
|
|
5
|
+
* square apart while what they hold stays on the squares. A flow bento needs
|
|
6
|
+
* no script. No framework and no imports.
|
|
7
|
+
*
|
|
8
|
+
* ```html
|
|
9
|
+
* <div class="ds-bento" data-squares style="--ds-bento-columns: 48">
|
|
10
|
+
* <a class="ds-card" href="/archive/" data-place="0 0 15 7">…</a>
|
|
11
|
+
* <a class="ds-card" href="/ezo/" data-place="16 0 16 20">…</a>
|
|
12
|
+
* </div>
|
|
13
|
+
* <script type="module">
|
|
14
|
+
* import { placeBentos } from "/ds1/0-face/bento.js";
|
|
15
|
+
* placeBentos();
|
|
16
|
+
* </script>
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* A tile's `data-place` is its square across, its square down, its width and
|
|
20
|
+
* its height, in whole squares counted from 0. Tiles are placed a square
|
|
21
|
+
* apart; a tile a square away from another, with the two overlapping along
|
|
22
|
+
* that side, reaches towards it.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/** A tile's place in squares: across, down, wide, high. */
|
|
26
|
+
export type BentoPlace = readonly [x: number, y: number, w: number, h: number];
|
|
27
|
+
|
|
28
|
+
/** Which sides of each tile face another tile a square away. */
|
|
29
|
+
export interface BentoReach { start: boolean; top: boolean; end: boolean; bottom: boolean }
|
|
30
|
+
|
|
31
|
+
/** Reads `data-place` ("x y w h"); `undefined` unless it is four whole numbers with a size. */
|
|
32
|
+
export function bentoPlace(value: string | null | undefined): BentoPlace | undefined {
|
|
33
|
+
const parts = (value ?? "").trim().split(/[\s,]+/).map(Number);
|
|
34
|
+
if (parts.length !== 4 || parts.some(part => !Number.isInteger(part) || part < 0)) return undefined;
|
|
35
|
+
const [x, y, w, h] = parts as [number, number, number, number];
|
|
36
|
+
return w > 0 && h > 0 ? [x, y, w, h] : undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const overlaps = (a0: number, a1: number, b0: number, b1: number) => a0 < b1 && b0 < a1;
|
|
40
|
+
|
|
41
|
+
/** For each place, the sides that face another tile across a one-square gap. */
|
|
42
|
+
export function bentoReach(places: readonly BentoPlace[]): BentoReach[] {
|
|
43
|
+
return places.map(([x, y, w, h], index) => {
|
|
44
|
+
const others = places.filter((_, other) => other !== index);
|
|
45
|
+
return {
|
|
46
|
+
start: others.some(([ox, oy, ow, oh]) => ox + ow + 1 === x && overlaps(y, y + h, oy, oy + oh)),
|
|
47
|
+
end: others.some(([ox, oy, , oh]) => x + w + 1 === ox && overlaps(y, y + h, oy, oy + oh)),
|
|
48
|
+
top: others.some(([ox, oy, ow, oh]) => oy + oh + 1 === y && overlaps(x, x + w, ox, ox + ow)),
|
|
49
|
+
bottom: others.some(([ox, oy, ow]) => y + h + 1 === oy && overlaps(x, x + w, ox, ox + ow)),
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Places one squares bento's tiles: their squares and their reach, as custom properties. */
|
|
55
|
+
export function placeBento(bento: HTMLElement): void {
|
|
56
|
+
const tiles = [...bento.children].filter((child): child is HTMLElement => child instanceof HTMLElement && !child.hidden);
|
|
57
|
+
const placed = tiles.map(tile => ({ tile, place: bentoPlace(tile.dataset.place) })).filter((entry): entry is { tile: HTMLElement; place: BentoPlace } => !!entry.place);
|
|
58
|
+
const reach = bentoReach(placed.map(entry => entry.place));
|
|
59
|
+
placed.forEach(({ tile, place: [x, y, w, h] }, index) => {
|
|
60
|
+
const sides = reach[index]!;
|
|
61
|
+
tile.style.setProperty("--ds-bento-x", String(x));
|
|
62
|
+
tile.style.setProperty("--ds-bento-y", String(y));
|
|
63
|
+
tile.style.setProperty("--ds-bento-w", String(w));
|
|
64
|
+
tile.style.setProperty("--ds-bento-h", String(h));
|
|
65
|
+
for (const side of ["start", "top", "end", "bottom"] as const) tile.style.setProperty(`--ds-bento-${side}`, sides[side] ? "1" : "0");
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Places every squares bento on the page (or under `root`), and again when its tiles change. */
|
|
70
|
+
export function placeBentos(root: ParentNode = document): () => void {
|
|
71
|
+
const bentos = [...root.querySelectorAll<HTMLElement>(".ds-bento[data-squares]")];
|
|
72
|
+
const observer = new MutationObserver(records => {
|
|
73
|
+
for (const record of records) {
|
|
74
|
+
const bento = record.target instanceof HTMLElement && record.target.matches(".ds-bento[data-squares]") ? record.target : (record.target as HTMLElement).parentElement;
|
|
75
|
+
if (bento?.matches(".ds-bento[data-squares]")) placeBento(bento);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
for (const bento of bentos) {
|
|
79
|
+
placeBento(bento);
|
|
80
|
+
observer.observe(bento, { childList: true, subtree: false, attributes: true, attributeFilter: ["data-place", "hidden"] });
|
|
81
|
+
for (const tile of bento.children) observer.observe(tile, { attributes: true, attributeFilter: ["data-place", "hidden"] });
|
|
82
|
+
}
|
|
83
|
+
return () => observer.disconnect();
|
|
84
|
+
}
|
package/DS1/0-face/calendar.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// calendar.ts
|
|
2
2
|
// Days as the calendars count them: a day is written `YYYY-MM-DD` and read on
|
|
3
3
|
// its own date in every zone, a month is the whole weeks that hold it, and the
|
|
4
|
-
// week starts where the language starts it. Shared by ds-calendar
|
|
5
|
-
//
|
|
4
|
+
// week starts where the language starts it. Shared by ds-calendar (its
|
|
5
|
+
// picker too) and ds-calendar-large; no Lit, so a page can use it alone.
|
|
6
6
|
|
|
7
7
|
import { currentLanguage } from "./i18n";
|
|
8
8
|
import { dateFormatter, localeTag } from "./format";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
@import "./component-metrics.css";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* A bento, as plain classes on native elements: tiles of different sizes
|
|
5
|
+
* standing half a square (10px) apart, each a card (`.ds-card`, or any box)
|
|
6
|
+
* that holds one thing. The `ds-bento` element draws the same.
|
|
7
|
+
*
|
|
8
|
+
* Flow (the default): columns that share the width (`--ds-bento-columns`,
|
|
9
|
+
* three), a tile one column wide or more (`data-span`, or
|
|
10
|
+
* `--ds-bento-span`) and one row high or more (`data-rows`, or
|
|
11
|
+
* `--ds-bento-rows`); a row is as high as its tallest tile, at least
|
|
12
|
+
* `--ds-bento-row` (ten squares by default). Below thirty squares of width
|
|
13
|
+
* the bento is one column.
|
|
14
|
+
*
|
|
15
|
+
* Squares (`data-squares`): the bento is exactly `--ds-bento-columns` squares wide
|
|
16
|
+
* and every tile is placed on whole squares (`data-place="x y w h"`,
|
|
17
|
+
* counted from 0). Tiles are placed a square apart, and a tile's surface
|
|
18
|
+
* reaches a quarter square towards each tile beside it, so they stand half a
|
|
19
|
+
* square apart while what they hold stays on the squares, and the bento's
|
|
20
|
+
* own edges stay on the page's. `placeBento()` (0-face/bento.ts) reads the
|
|
21
|
+
* places and sets the reach; the element does it itself.
|
|
22
|
+
*
|
|
23
|
+
* data-span="2" a tile two columns wide (to 6)
|
|
24
|
+
* data-rows="2" a tile two rows high (to 6)
|
|
25
|
+
* data-place="0 0 15 7" a tile's square, width and height in squares
|
|
26
|
+
*
|
|
27
|
+
* Tokens: `--ds-bento-gap` (half a square), `--ds-bento-columns`,
|
|
28
|
+
* `--ds-bento-row`, and on a tile `--ds-bento-span`, `--ds-bento-rows`.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
.ds-bento {
|
|
32
|
+
--ds-bento-gap: calc(var(--ds-unit) / 2);
|
|
33
|
+
box-sizing: border-box;
|
|
34
|
+
display: grid;
|
|
35
|
+
grid-template-columns: repeat(var(--ds-bento-columns, 3), minmax(0, 1fr));
|
|
36
|
+
grid-auto-rows: minmax(var(--ds-bento-row, calc(10 * var(--ds-unit))), auto);
|
|
37
|
+
grid-auto-flow: row dense;
|
|
38
|
+
gap: var(--ds-bento-gap);
|
|
39
|
+
margin: 0;
|
|
40
|
+
padding: 0;
|
|
41
|
+
list-style: none;
|
|
42
|
+
}
|
|
43
|
+
.ds-bento[hidden] { display: none; }
|
|
44
|
+
|
|
45
|
+
.ds-bento > * {
|
|
46
|
+
--ds-card-width: auto;
|
|
47
|
+
--ds-card-height: auto;
|
|
48
|
+
box-sizing: border-box;
|
|
49
|
+
min-width: 0;
|
|
50
|
+
min-height: 0;
|
|
51
|
+
grid-column: span var(--ds-bento-span, 1);
|
|
52
|
+
grid-row: span var(--ds-bento-rows, 1);
|
|
53
|
+
}
|
|
54
|
+
.ds-bento > [data-span="2"] { --ds-bento-span: 2; }
|
|
55
|
+
.ds-bento > [data-span="3"] { --ds-bento-span: 3; }
|
|
56
|
+
.ds-bento > [data-span="4"] { --ds-bento-span: 4; }
|
|
57
|
+
.ds-bento > [data-span="5"] { --ds-bento-span: 5; }
|
|
58
|
+
.ds-bento > [data-span="6"] { --ds-bento-span: 6; }
|
|
59
|
+
.ds-bento > [data-rows="2"] { --ds-bento-rows: 2; }
|
|
60
|
+
.ds-bento > [data-rows="3"] { --ds-bento-rows: 3; }
|
|
61
|
+
.ds-bento > [data-rows="4"] { --ds-bento-rows: 4; }
|
|
62
|
+
.ds-bento > [data-rows="5"] { --ds-bento-rows: 5; }
|
|
63
|
+
.ds-bento > [data-rows="6"] { --ds-bento-rows: 6; }
|
|
64
|
+
|
|
65
|
+
@media (max-width: 600px) {
|
|
66
|
+
.ds-bento:not([data-squares]) { grid-template-columns: minmax(0, 1fr); }
|
|
67
|
+
.ds-bento:not([data-squares]) > * { grid-column: auto; }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Squares: every tile on whole squares, a square apart, its surface a quarter square nearer each neighbour. */
|
|
71
|
+
.ds-bento[data-squares] {
|
|
72
|
+
--ds-bento-reach: calc(var(--ds-unit) / 4);
|
|
73
|
+
/* Exactly its squares wide: each column one square. */
|
|
74
|
+
width: calc(var(--ds-bento-columns, 48) * var(--ds-unit));
|
|
75
|
+
max-width: none;
|
|
76
|
+
grid-template-columns: repeat(var(--ds-bento-columns, 48), var(--ds-unit));
|
|
77
|
+
grid-auto-rows: var(--ds-unit);
|
|
78
|
+
grid-auto-flow: row;
|
|
79
|
+
gap: 0;
|
|
80
|
+
}
|
|
81
|
+
.ds-bento[data-squares] > * {
|
|
82
|
+
--ds-bento-inset-top: calc(var(--ds-bento-reach) * var(--ds-bento-top, 0));
|
|
83
|
+
--ds-bento-inset-end: calc(var(--ds-bento-reach) * var(--ds-bento-end, 0));
|
|
84
|
+
--ds-bento-inset-bottom: calc(var(--ds-bento-reach) * var(--ds-bento-bottom, 0));
|
|
85
|
+
--ds-bento-inset-start: calc(var(--ds-bento-reach) * var(--ds-bento-start, 0));
|
|
86
|
+
grid-column: calc(var(--ds-bento-x, 0) + 1) / span var(--ds-bento-w, 4);
|
|
87
|
+
grid-row: calc(var(--ds-bento-y, 0) + 1) / span var(--ds-bento-h, 4);
|
|
88
|
+
margin: calc(-1 * var(--ds-bento-inset-top)) calc(-1 * var(--ds-bento-inset-end)) calc(-1 * var(--ds-bento-inset-bottom)) calc(-1 * var(--ds-bento-inset-start));
|
|
89
|
+
}
|
|
90
|
+
/* A card grows its own padding by the reach (card.css); any other tile is padded here, a square inside. */
|
|
91
|
+
.ds-bento[data-squares] > :not(.ds-card, ds-card) {
|
|
92
|
+
padding:
|
|
93
|
+
calc(var(--ds-unit) + var(--ds-bento-inset-top))
|
|
94
|
+
calc(var(--ds-unit) + var(--ds-bento-inset-end))
|
|
95
|
+
calc(var(--ds-unit) + var(--ds-bento-inset-bottom))
|
|
96
|
+
calc(var(--ds-unit) + var(--ds-bento-inset-start));
|
|
97
|
+
}
|
package/DS1/1-root/card.css
CHANGED
|
@@ -45,7 +45,12 @@
|
|
|
45
45
|
height: var(--ds-card-height, auto);
|
|
46
46
|
min-width: 0;
|
|
47
47
|
margin: 0;
|
|
48
|
-
|
|
48
|
+
/* In a squares bento the surface reaches a quarter square towards its neighbours (`--ds-bento-inset-*`, 0 elsewhere), and the padding grows by as much so what it holds stays on the squares. */
|
|
49
|
+
padding:
|
|
50
|
+
calc(var(--ds-card-padding) + var(--ds-bento-inset-top, 0px))
|
|
51
|
+
calc(var(--ds-card-padding) + var(--ds-bento-inset-end, 0px))
|
|
52
|
+
var(--ds-bento-inset-bottom, 0px)
|
|
53
|
+
calc(var(--ds-card-padding) + var(--ds-bento-inset-start, 0px));
|
|
49
54
|
overflow: hidden;
|
|
50
55
|
border-radius: var(--ds-radius-card);
|
|
51
56
|
background: var(--ds-card-fill);
|
package/DS1/1-root/cjk.css
CHANGED
package/DS1/1-root/controls.css
CHANGED
package/DS1/1-root/fonts.css
CHANGED
package/DS1/1-root/one.css
CHANGED
|
@@ -37,9 +37,10 @@ export interface CalendarEventDetail {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Detail of `change`: the value a person chose and the one before it.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* Detail of `change`: the value a person chose and the one before it. The
|
|
41
|
+
* first day pressed is `value` alone, with `end` empty while the end is still
|
|
42
|
+
* to come; the second ends it, and `value` is `start/end` (one day when the
|
|
43
|
+
* same day is pressed twice).
|
|
43
44
|
*/
|
|
44
45
|
export interface CalendarChangeDetail {
|
|
45
46
|
value: string;
|
|
@@ -77,15 +78,15 @@ export abstract class CalendarBase extends LitElement {
|
|
|
77
78
|
today: { type: String },
|
|
78
79
|
weekStart: { type: String, attribute: "week-start" },
|
|
79
80
|
selectable: { type: Boolean, reflect: true },
|
|
80
|
-
range: { type: Boolean, reflect: true },
|
|
81
81
|
label: { type: String },
|
|
82
82
|
literal: { type: Boolean, reflect: true },
|
|
83
83
|
events: { attribute: false },
|
|
84
84
|
focusDay: { state: true },
|
|
85
85
|
hoverDay: { state: true },
|
|
86
|
+
endPending: { state: true },
|
|
86
87
|
};
|
|
87
88
|
|
|
88
|
-
/** The selected day, `YYYY-MM-DD`, or
|
|
89
|
+
/** The selected day, `YYYY-MM-DD`, or a range of days, `YYYY-MM-DD/YYYY-MM-DD`; empty for none. */
|
|
89
90
|
declare value: string;
|
|
90
91
|
/** The first day a person may choose. */
|
|
91
92
|
declare min: string | undefined;
|
|
@@ -95,10 +96,8 @@ export abstract class CalendarBase extends LitElement {
|
|
|
95
96
|
declare today: string | undefined;
|
|
96
97
|
/** The first day of the week: `0`–`6` from Sunday, or a day's English name; the language's own when left out. */
|
|
97
98
|
declare weekStart: string | undefined;
|
|
98
|
-
/** Pressing a day selects it and fires `change
|
|
99
|
+
/** Pressing a day selects it and fires `change`: one day, or a first and a last. */
|
|
99
100
|
declare selectable: boolean;
|
|
100
|
-
/** A selectable calendar chooses a first and a last day. */
|
|
101
|
-
declare range: boolean;
|
|
102
101
|
/** The grid's name: a translation key, or literal words. The month's name when left out. */
|
|
103
102
|
declare label: string | undefined;
|
|
104
103
|
/** Show `label` as written, never looked up. */
|
|
@@ -109,6 +108,11 @@ export abstract class CalendarBase extends LitElement {
|
|
|
109
108
|
declare focusDay: Day | undefined;
|
|
110
109
|
/** The day under the pointer, which previews a range's end. */
|
|
111
110
|
declare hoverDay: Day | undefined;
|
|
111
|
+
/** A first day has been pressed and the next press ends the range. */
|
|
112
|
+
protected declare endPending: boolean;
|
|
113
|
+
|
|
114
|
+
/** The value the last press wrote, so a value set from outside settles the range. */
|
|
115
|
+
private pressedValue: string | undefined;
|
|
112
116
|
|
|
113
117
|
/** Weeks run along rows (a month) or along columns (the large calendar). */
|
|
114
118
|
protected abstract readonly weeksRun: "rows" | "columns";
|
|
@@ -119,7 +123,7 @@ export abstract class CalendarBase extends LitElement {
|
|
|
119
123
|
super();
|
|
120
124
|
this.value = "";
|
|
121
125
|
this.selectable = false;
|
|
122
|
-
this.
|
|
126
|
+
this.endPending = false;
|
|
123
127
|
this.literal = false;
|
|
124
128
|
this.events = [];
|
|
125
129
|
}
|
|
@@ -139,6 +143,8 @@ export abstract class CalendarBase extends LitElement {
|
|
|
139
143
|
protected willUpdate(changed: PropertyValues<this>) {
|
|
140
144
|
super.willUpdate(changed);
|
|
141
145
|
if (changed.has("value") && this.value && !readRange(this.value).start) this.value = "";
|
|
146
|
+
// A value given from outside is whole: the next press starts again.
|
|
147
|
+
if (changed.has("value") && this.value !== this.pressedValue) this.endPending = false;
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
/** Shared words, filled in: `words("Week {week}", { week: 42 })`. */
|
|
@@ -177,16 +183,16 @@ export abstract class CalendarBase extends LitElement {
|
|
|
177
183
|
/** The chosen days: the first and the last of a range, or the one day twice. */
|
|
178
184
|
protected get chosen(): { start: Day; end: Day } {
|
|
179
185
|
const { start, end } = readRange(this.value);
|
|
180
|
-
return
|
|
186
|
+
return { start, end: end || start };
|
|
181
187
|
}
|
|
182
188
|
|
|
183
189
|
/** How a day stands to the selection: an end of it, inside it, or neither; with the end still to come, the pointer previews it. */
|
|
184
190
|
protected selection(day: Day): { selected: boolean; inside: boolean; first: boolean; last: boolean } {
|
|
185
191
|
let { start, end } = this.chosen;
|
|
186
|
-
if (this.
|
|
192
|
+
if (this.endPending && start && this.hoverDay) end = this.hoverDay;
|
|
187
193
|
if (end && end < start) [start, end] = [end, start];
|
|
188
194
|
const selected = day === start || day === end;
|
|
189
|
-
const spans = Boolean(
|
|
195
|
+
const spans = Boolean(start && end && start !== end);
|
|
190
196
|
return { selected, inside: spans && day > start && day < end, first: spans && day === start, last: spans && day === end };
|
|
191
197
|
}
|
|
192
198
|
|
|
@@ -219,7 +225,10 @@ export abstract class CalendarBase extends LitElement {
|
|
|
219
225
|
|
|
220
226
|
/**
|
|
221
227
|
* A person pressed a day: `day-press` fires, and unless it is cancelled a
|
|
222
|
-
* selectable calendar takes the day and fires `change`.
|
|
228
|
+
* selectable calendar takes the day and fires `change`. There is one way to
|
|
229
|
+
* pick: the first press chooses a day, which is the value; the next ends a
|
|
230
|
+
* range from it, before or after (the same day again keeps the one day);
|
|
231
|
+
* the press after that starts again.
|
|
223
232
|
*/
|
|
224
233
|
protected press(day: Day) {
|
|
225
234
|
const pressed = new CustomEvent<CalendarDayDetail>("day-press", {
|
|
@@ -230,18 +239,18 @@ export abstract class CalendarBase extends LitElement {
|
|
|
230
239
|
});
|
|
231
240
|
if (!this.dispatchEvent(pressed) || !this.selectable || !this.allowed(day)) return;
|
|
232
241
|
const previous = this.value || "";
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const { start, end } = readRange(previous);
|
|
237
|
-
if (start && !end) value = day < start ? `${day}/${start}` : `${start}/${day}`;
|
|
238
|
-
}
|
|
242
|
+
const { start: first } = readRange(previous);
|
|
243
|
+
const ending = this.endPending && Boolean(first);
|
|
244
|
+
const value: string = !ending || day === first ? day : day < first ? `${day}/${first}` : `${first}/${day}`;
|
|
239
245
|
this.focusDay = day;
|
|
240
|
-
|
|
241
|
-
this.value = value;
|
|
246
|
+
this.endPending = !ending;
|
|
242
247
|
this.hoverDay = undefined;
|
|
248
|
+
this.pressedValue = value;
|
|
249
|
+
// An end on the first day keeps the value but still says the range is whole.
|
|
250
|
+
if (value === previous && !ending) return;
|
|
251
|
+
this.value = value;
|
|
243
252
|
const { start, end } = readRange(value);
|
|
244
|
-
this.dispatchEvent(new CustomEvent<CalendarChangeDetail>("change", { bubbles: true, composed: true, detail: { value, previous, start, end:
|
|
253
|
+
this.dispatchEvent(new CustomEvent<CalendarChangeDetail>("change", { bubbles: true, composed: true, detail: { value, previous, start, end: ending ? end || start : "" } }));
|
|
245
254
|
}
|
|
246
255
|
|
|
247
256
|
protected pressEvent(event: CalendarEvent, day: Day) {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// ds-bento.ts
|
|
2
|
+
// Tiles of different sizes, half a square apart: in columns that share the
|
|
3
|
+
// width (a tile `data-span` columns wide, `data-rows` rows high), or with
|
|
4
|
+
// `squares`, each placed on whole squares by its `data-place`, its surface
|
|
5
|
+
// reaching towards the tiles beside it. The tiles are cards (`ds-card`) or
|
|
6
|
+
// any box. Drawn as 1-root/bento.css draws `.ds-bento`, and placed by the
|
|
7
|
+
// helpers it shares with 0-face/bento.ts.
|
|
8
|
+
|
|
9
|
+
import { LitElement, html, unsafeCSS } from "lit";
|
|
10
|
+
import { define } from "../0-face/define";
|
|
11
|
+
import { placeBento } from "../0-face/bento";
|
|
12
|
+
import metrics from "../1-root/component-metrics.css?inline";
|
|
13
|
+
import styles from "./styles/ds-bento.css?inline";
|
|
14
|
+
|
|
15
|
+
export class Bento extends LitElement {
|
|
16
|
+
static properties = {
|
|
17
|
+
columns: { type: Number, reflect: true },
|
|
18
|
+
squares: { type: Boolean, reflect: true },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** The number of columns (flow, three by default), or the squares across (`squares`, 48 by default). */
|
|
22
|
+
declare columns: number | undefined;
|
|
23
|
+
/** Places every tile on whole squares by its `data-place`. */
|
|
24
|
+
declare squares: boolean;
|
|
25
|
+
|
|
26
|
+
static styles = [unsafeCSS(metrics), unsafeCSS(styles)];
|
|
27
|
+
|
|
28
|
+
private observer?: MutationObserver;
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
super();
|
|
32
|
+
this.squares = false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
connectedCallback() {
|
|
36
|
+
super.connectedCallback();
|
|
37
|
+
this.observer = new MutationObserver(() => this.place());
|
|
38
|
+
this.observer.observe(this, { childList: true, subtree: true, attributes: true, attributeFilter: ["data-place", "hidden"] });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
disconnectedCallback() {
|
|
42
|
+
this.observer?.disconnect();
|
|
43
|
+
super.disconnectedCallback();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
protected updated() {
|
|
47
|
+
if (this.columns) this.style.setProperty("--ds-bento-columns", String(this.columns));
|
|
48
|
+
else this.style.removeProperty("--ds-bento-columns");
|
|
49
|
+
this.place();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private place() {
|
|
53
|
+
if (this.squares) placeBento(this);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
render() {
|
|
57
|
+
return html`<slot @slotchange=${() => this.place()}></slot>`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
define("ds-bento", Bento);
|
|
62
|
+
|
|
63
|
+
declare global {
|
|
64
|
+
interface HTMLElementTagNameMap {
|
|
65
|
+
"ds-bento": Bento;
|
|
66
|
+
}
|
|
67
|
+
}
|