foldkit-mixins-data-grid 0.2.15 → 0.3.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 (51) hide show
  1. package/dist/fillDrag.d.ts +30 -0
  2. package/dist/fillDrag.d.ts.map +1 -0
  3. package/dist/fillDrag.js +178 -0
  4. package/dist/fillDrag.js.map +1 -0
  5. package/dist/headerDrag.d.ts +34 -0
  6. package/dist/headerDrag.d.ts.map +1 -0
  7. package/dist/headerDrag.js +112 -0
  8. package/dist/headerDrag.js.map +1 -0
  9. package/dist/holdFocus.d.ts +11 -0
  10. package/dist/holdFocus.d.ts.map +1 -0
  11. package/dist/holdFocus.js +31 -0
  12. package/dist/holdFocus.js.map +1 -0
  13. package/dist/index.d.ts +6 -0
  14. package/dist/index.js +6 -0
  15. package/dist/keepFocus.d.ts +9 -0
  16. package/dist/keepFocus.d.ts.map +1 -0
  17. package/dist/keepFocus.js +20 -0
  18. package/dist/keepFocus.js.map +1 -0
  19. package/dist/marks.d.ts +69 -0
  20. package/dist/marks.d.ts.map +1 -0
  21. package/dist/marks.js +90 -0
  22. package/dist/marks.js.map +1 -0
  23. package/dist/moreOnScroll.d.ts +12 -0
  24. package/dist/moreOnScroll.d.ts.map +1 -0
  25. package/dist/moreOnScroll.js +17 -0
  26. package/dist/moreOnScroll.js.map +1 -0
  27. package/dist/nearEnd.d.ts +15 -0
  28. package/dist/nearEnd.d.ts.map +1 -0
  29. package/dist/nearEnd.js +33 -0
  30. package/dist/nearEnd.js.map +1 -0
  31. package/dist/press.d.ts +31 -0
  32. package/dist/press.d.ts.map +1 -0
  33. package/dist/press.js +53 -0
  34. package/dist/press.js.map +1 -0
  35. package/dist/slots.d.ts +85 -0
  36. package/dist/slots.d.ts.map +1 -0
  37. package/dist/slots.js +289 -0
  38. package/dist/slots.js.map +1 -0
  39. package/dist/style.d.ts +555 -0
  40. package/dist/style.d.ts.map +1 -0
  41. package/dist/style.js +224 -0
  42. package/dist/style.js.map +1 -0
  43. package/dist/view.d.ts +140 -0
  44. package/dist/view.d.ts.map +1 -0
  45. package/dist/view.js +861 -0
  46. package/dist/view.js.map +1 -0
  47. package/package.json +12 -12
  48. package/dist/index.d.mts +0 -321
  49. package/dist/index.d.mts.map +0 -1
  50. package/dist/index.mjs +0 -1849
  51. package/dist/index.mjs.map +0 -1
package/dist/style.js ADDED
@@ -0,0 +1,224 @@
1
+ import { GridSlots } from "./slots.js";
2
+ import { Layers, Style } from "foldkit-mixins";
3
+ import { Theme } from "foldkit-mixins/theme";
4
+ // src/style.ts
5
+ /**
6
+ * The grid's default look, for a page that ships `foldkit-mixins/theme`'s
7
+ * tokens and palette. It only paints: the geometry the virtual window
8
+ * depends on is the view's, and the slots refuse a Style that sets it.
9
+ */
10
+ /** The tokens the grid's styles draw with; the marks' too (`marks.ts`). */
11
+ const ref = Theme.ref(Theme.standard());
12
+ const line = `${ref.border.thin} solid ${ref.outline.subtle}`;
13
+ const faint = `${ref.border.thin} solid color-mix(in oklch, ${ref.outline.subtle} 55%, transparent)`;
14
+ const pinnedEdge = [Style.nest("&[data-pinned-edge=\"start\"]", { borderInlineEnd: `${ref.border.thick} solid ${ref.outline.default}` }), Style.nest("&[data-pinned-edge=\"end\"]", { borderInlineStart: `${ref.border.thick} solid ${ref.outline.default}` })];
15
+ const field = Style.compose(Style.self({
16
+ background: ref.surface.base,
17
+ border: "none",
18
+ caretColor: ref.outline.focus,
19
+ color: "inherit",
20
+ font: "inherit",
21
+ outline: `${ref.border.thick} solid ${ref.outline.focus}`,
22
+ outlineOffset: `calc(-1 * ${ref.border.thick})`,
23
+ paddingInline: ref.space.sm
24
+ }), Style.media("(pointer: coarse)", { fontSize: "max(1rem, 1em)" }));
25
+ const refused = Style.nest("&[aria-invalid=\"true\"]", {
26
+ outlineColor: ref.error.default,
27
+ caretColor: ref.error.default
28
+ });
29
+ /** Every piece is in the `components` layer, so an application's own layer wins. */
30
+ const GridStyle = Style.forSlots(GridSlots)({
31
+ root: Style.compose(Style.self({
32
+ background: ref.surface.base,
33
+ color: ref.text.default,
34
+ fontVariantNumeric: "tabular-nums"
35
+ }), Style.pseudo(":focus-visible", { outline: `${ref.border.thick} solid ${ref.outline.focus}` })),
36
+ header: Style.self({
37
+ zIndex: "2",
38
+ background: ref.surface.muted
39
+ }),
40
+ headerCell: Style.compose(Style.self({
41
+ alignItems: "center",
42
+ background: ref.surface.muted,
43
+ borderBlockEnd: line,
44
+ display: "flex",
45
+ fontSize: ref.size.sm,
46
+ fontWeight: ref.weight.semibold,
47
+ paddingInline: ref.space.sm,
48
+ whiteSpace: "nowrap",
49
+ userSelect: "none"
50
+ }), Style.nest("&[data-pinned]", { zIndex: "1" }), ...pinnedEdge, Style.nest("&[aria-readonly=\"true\"]::before", {
51
+ background: ref.text.muted,
52
+ content: "\"\"",
53
+ flex: "none",
54
+ height: "0.75em",
55
+ marginInlineEnd: ref.space["2xs"],
56
+ mask: `${ref.icon.lock} center / contain no-repeat`,
57
+ width: "0.75em"
58
+ }), Style.nest("&[data-dragging]", {
59
+ zIndex: "3",
60
+ background: ref.surface.default,
61
+ opacity: "0.9",
62
+ cursor: "grabbing"
63
+ }), Style.nest("&[data-drop=\"before\"]", { borderInlineStart: `${ref.border.thick} solid ${ref.outline.focus}` }), Style.nest("&[data-drop=\"after\"]", { borderInlineEnd: `${ref.border.thick} solid ${ref.outline.focus}` })),
64
+ cell: Style.compose(Style.self({
65
+ alignItems: "center",
66
+ borderBlockEnd: line,
67
+ borderInlineEnd: faint,
68
+ display: "flex",
69
+ overflow: "hidden",
70
+ paddingInline: ref.space.sm,
71
+ textOverflow: "ellipsis",
72
+ whiteSpace: "nowrap"
73
+ }), Style.nest("&[data-pinned]", {
74
+ background: ref.surface.base,
75
+ zIndex: "1"
76
+ }), ...pinnedEdge, Style.nest("&[data-editable]", { cursor: "text" }), Style.nest("&[aria-readonly=\"true\"]", {
77
+ color: ref.text.muted,
78
+ cursor: "default"
79
+ }), Style.nest("&[data-editing]", {
80
+ boxShadow: ref.shadow.md,
81
+ overflow: "visible",
82
+ paddingInline: "0",
83
+ zIndex: "2"
84
+ }), Style.nest("&[data-focused=\"true\"]", {
85
+ outline: `${ref.border.thick} solid ${ref.outline.focus}`,
86
+ outlineOffset: `calc(-1 * ${ref.border.thick})`
87
+ }), Style.nest("&[data-fill=\"target\"]", {
88
+ outline: `${ref.border.thin} dashed ${ref.outline.focus}`,
89
+ outlineOffset: `calc(-1 * ${ref.border.thin})`
90
+ }), Style.nest("&[data-mark]", { backgroundImage: `radial-gradient(circle at calc(100% - 6px) 6px, ${ref.outline.focus} 3px, transparent 3.5px)` })),
91
+ editor: Style.compose(field, refused),
92
+ choice: Style.compose(field, refused, Style.self({
93
+ display: "flex",
94
+ alignItems: "center",
95
+ cursor: "default"
96
+ })),
97
+ choiceList: Style.compose(Style.self({
98
+ zIndex: "3",
99
+ minWidth: "100%",
100
+ maxHeight: "16rem",
101
+ overflowY: "auto",
102
+ margin: "0",
103
+ padding: ref.space["3xs"],
104
+ listStyle: "none",
105
+ background: ref.surface.base,
106
+ border: `${ref.border.thin} solid ${ref.outline.default}`,
107
+ borderRadius: ref.radius.md,
108
+ boxShadow: ref.shadow.lg
109
+ })),
110
+ choiceOption: Style.compose(Style.self({
111
+ padding: `${ref.space["2xs"]} ${ref.space.sm}`,
112
+ borderRadius: ref.radius.sm,
113
+ cursor: "pointer",
114
+ whiteSpace: "nowrap"
115
+ }), Style.nest("&:hover", { background: ref.surface.subtle }), Style.nest("&[aria-selected=\"true\"]", {
116
+ background: ref.accent.subtle,
117
+ color: ref.accent.ink
118
+ }), Style.media("(pointer: coarse)", {
119
+ minHeight: "44px",
120
+ display: "flex",
121
+ alignItems: "center"
122
+ })),
123
+ editorError: Style.self({
124
+ background: ref.error.default,
125
+ borderRadius: ref.radius.md,
126
+ boxShadow: ref.shadow.lg,
127
+ color: ref.error["on-fill"],
128
+ fontSize: ref.size.xs,
129
+ fontWeight: ref.weight.medium,
130
+ insetInlineStart: "0",
131
+ paddingBlock: ref.space["3xs"],
132
+ paddingInline: ref.space.xs,
133
+ pointerEvents: "none",
134
+ position: "absolute",
135
+ top: `calc(100% + ${ref.space["3xs"]})`,
136
+ whiteSpace: "nowrap",
137
+ zIndex: "5"
138
+ }),
139
+ resizeHandle: Style.compose(Style.self({
140
+ background: `linear-gradient(to right, transparent calc(100% - 1px), color-mix(in oklch, ${ref.outline.subtle} 70%, transparent) calc(100% - 1px))`,
141
+ WebkitTouchCallout: "none"
142
+ }), Style.pseudo(":hover", { background: `linear-gradient(to right, transparent calc(100% - 2px), ${ref.outline.focus} calc(100% - 2px))` }), Style.at("@media (pointer: coarse)", Style.nest("&::before", {
143
+ content: "\"\"",
144
+ position: "absolute",
145
+ insetBlock: "0",
146
+ insetInlineStart: "-12px",
147
+ insetInlineEnd: "-4px"
148
+ }))),
149
+ fillHandle: Style.compose(Style.self({
150
+ width: "7px",
151
+ height: "7px",
152
+ background: ref.outline.focus,
153
+ border: `1px solid ${ref.surface.base}`,
154
+ cursor: "crosshair",
155
+ zIndex: "3",
156
+ touchAction: "none",
157
+ WebkitTouchCallout: "none"
158
+ }), Style.at("@media (pointer: coarse)", Style.nest("&::before", {
159
+ content: "\"\"",
160
+ position: "absolute",
161
+ inset: "-18px"
162
+ }))),
163
+ menuButton: Style.compose(Style.self({
164
+ background: "none",
165
+ border: "none",
166
+ color: ref.text.muted,
167
+ cursor: "pointer",
168
+ marginInlineStart: "auto",
169
+ minBlockSize: "1.5rem",
170
+ minInlineSize: "1.5rem",
171
+ paddingInline: ref.space.xs
172
+ }), Style.nest("&[aria-expanded=\"true\"]", { color: ref.text.default })),
173
+ menu: Style.compose(Style.self({
174
+ background: ref.surface.base,
175
+ border: line,
176
+ borderRadius: ref.radius.md,
177
+ fontWeight: ref.weight.normal,
178
+ minWidth: "10rem",
179
+ paddingBlock: ref.space.xs,
180
+ zIndex: "4"
181
+ }), Style.pseudo(":focus-visible", { outline: `${ref.border.thick} solid ${ref.outline.focus}` })),
182
+ menuItem: Style.compose(Style.self({
183
+ cursor: "pointer",
184
+ paddingBlock: ref.space.xs,
185
+ paddingInline: ref.space.sm
186
+ }), Style.nest("&[data-active=\"true\"]", { background: ref.surface.muted })),
187
+ sort: Style.compose(Style.self({
188
+ alignItems: "center",
189
+ background: "none",
190
+ border: "none",
191
+ color: "inherit",
192
+ cursor: "pointer",
193
+ display: "inline-flex",
194
+ font: "inherit",
195
+ gap: ref.space.xs,
196
+ minBlockSize: "1.5rem",
197
+ minWidth: "0",
198
+ overflow: "hidden",
199
+ padding: "0",
200
+ textOverflow: "ellipsis",
201
+ whiteSpace: "nowrap"
202
+ }), Style.nest("&::after", {
203
+ borderBlockEnd: `1.5px solid currentColor`,
204
+ borderInlineEnd: `1.5px solid currentColor`,
205
+ content: "\"\"",
206
+ flex: "none",
207
+ height: "0.4em",
208
+ opacity: "0",
209
+ transform: "translateY(-0.15em) rotate(45deg)",
210
+ transition: `opacity ${ref.motion.fast} ${ref.motion.ease}, transform calc(${ref.motion.fast} * ${ref.knob.travel}) ${ref.motion.ease}`,
211
+ width: "0.4em"
212
+ }), Style.nest("&:hover::after", { opacity: "0.35" }), Style.nest("&[data-sort=\"desc\"]::after", { opacity: "1" }), Style.nest("&[data-sort=\"asc\"]::after", {
213
+ opacity: "1",
214
+ transform: "translateY(0.1em) rotate(-135deg)"
215
+ })),
216
+ placeholder: Style.self({ background: ref.surface.subtle }),
217
+ status: Style.self({
218
+ color: ref.text.muted,
219
+ padding: ref.space.md
220
+ })
221
+ }, { layer: Layers.standard.layer("components") });
222
+ export { GridStyle, ref };
223
+
224
+ //# sourceMappingURL=style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.js","names":[],"sources":["../src/style.ts"],"sourcesContent":["/**\n * The grid's default look, for a page that ships `foldkit-mixins/theme`'s\n * tokens and palette. It only paints: the geometry the virtual window\n * depends on is the view's, and the slots refuse a Style that sets it.\n */\nimport { Layers, Style } from 'foldkit-mixins'\nimport { Theme } from 'foldkit-mixins/theme'\nimport { GridSlots } from './slots.js'\n\n/** The tokens the grid's styles draw with; the marks' too (`marks.ts`). */\nexport const ref = Theme.ref(Theme.standard())\n\nconst line = `${ref.border.thin} solid ${ref.outline.subtle}`\n// Between columns: barely there, so rows read across and columns still part.\nconst faint = `${ref.border.thin} solid color-mix(in oklch, ${ref.outline.subtle} 55%, transparent)`\n// Where the pinned columns end and the scrolling ones pass under them.\nconst pinnedEdge = [\n Style.nest('&[data-pinned-edge=\"start\"]', {\n borderInlineEnd: `${ref.border.thick} solid ${ref.outline.default}`,\n }),\n Style.nest('&[data-pinned-edge=\"end\"]', {\n borderInlineStart: `${ref.border.thick} solid ${ref.outline.default}`,\n }),\n] as const\n\n// The field an edit is typed in fills its cell, the cell lifted off the grid\n// (below), so an edit does not look like a cell that only has focus.\nconst field = Style.compose(\n Style.self({\n background: ref.surface.base,\n border: 'none',\n caretColor: ref.outline.focus,\n color: 'inherit',\n font: 'inherit',\n outline: `${ref.border.thick} solid ${ref.outline.focus}`,\n outlineOffset: `calc(-1 * ${ref.border.thick})`,\n paddingInline: ref.space.sm,\n }),\n // At least 16px on a touch screen, where iOS zooms into any smaller focused field.\n Style.media('(pointer: coarse)', { fontSize: 'max(1rem, 1em)' }),\n)\n// A draft the column refuses: the field in the error colour.\nconst refused = Style.nest('&[aria-invalid=\"true\"]', {\n outlineColor: ref.error.default,\n caretColor: ref.error.default,\n})\n\n/** Every piece is in the `components` layer, so an application's own layer wins. */\nexport const GridStyle = Style.forSlots(GridSlots)(\n {\n root: Style.compose(\n Style.self({\n background: ref.surface.base,\n color: ref.text.default,\n fontVariantNumeric: 'tabular-nums',\n }),\n Style.pseudo(':focus-visible', { outline: `${ref.border.thick} solid ${ref.outline.focus}` }),\n ),\n // Above the body's cells, pinned ones included, as it sticks to the top.\n header: Style.self({ zIndex: '2', background: ref.surface.muted }),\n headerCell: Style.compose(\n Style.self({\n alignItems: 'center',\n background: ref.surface.muted,\n borderBlockEnd: line,\n display: 'flex',\n fontSize: ref.size.sm,\n fontWeight: ref.weight.semibold,\n paddingInline: ref.space.sm,\n // A label stays on one line, however narrow the column: it is cut, not wrapped.\n whiteSpace: 'nowrap',\n // A drag that began on a header's text would otherwise select it.\n userSelect: 'none',\n }),\n Style.nest('&[data-pinned]', { zIndex: '1' }),\n ...pinnedEdge,\n // A column that does not edit, in a grid where others do: a padlock before its label.\n Style.nest('&[aria-readonly=\"true\"]::before', {\n background: ref.text.muted,\n content: '\"\"',\n flex: 'none',\n height: '0.75em',\n marginInlineEnd: ref.space['2xs'],\n mask: `${ref.icon.lock} center / contain no-repeat`,\n width: '0.75em',\n }),\n Style.nest('&[data-dragging]', {\n zIndex: '3',\n background: ref.surface.default,\n opacity: '0.9',\n cursor: 'grabbing',\n }),\n Style.nest('&[data-drop=\"before\"]', {\n borderInlineStart: `${ref.border.thick} solid ${ref.outline.focus}`,\n }),\n Style.nest('&[data-drop=\"after\"]', {\n borderInlineEnd: `${ref.border.thick} solid ${ref.outline.focus}`,\n }),\n ),\n cell: Style.compose(\n Style.self({\n alignItems: 'center',\n borderBlockEnd: line,\n borderInlineEnd: faint,\n display: 'flex',\n overflow: 'hidden',\n paddingInline: ref.space.sm,\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }),\n // A pinned cell is drawn over the cells scrolling under it, so it needs a ground.\n Style.nest('&[data-pinned]', { background: ref.surface.base, zIndex: '1' }),\n ...pinnedEdge,\n // A text cursor says a double-click edits; the edited cell gives its\n // padding to the field.\n Style.nest('&[data-editable]', { cursor: 'text' }),\n // Its cells, muted, with the ordinary pointer: there is nothing to type into.\n Style.nest('&[aria-readonly=\"true\"]', { color: ref.text.muted, cursor: 'default' }),\n // On the cell, which clips what is in it.\n Style.nest('&[data-editing]', {\n boxShadow: ref.shadow.md,\n // Its error shows below it, past the cell.\n overflow: 'visible',\n paddingInline: '0',\n zIndex: '2',\n }),\n Style.nest('&[data-focused=\"true\"]', {\n outline: `${ref.border.thick} solid ${ref.outline.focus}`,\n outlineOffset: `calc(-1 * ${ref.border.thick})`,\n }),\n // The cells a fill being dragged will write.\n Style.nest('&[data-fill=\"target\"]', {\n outline: `${ref.border.thin} dashed ${ref.outline.focus}`,\n outlineOffset: `calc(-1 * ${ref.border.thin})`,\n }),\n // A marked cell gets a dot in its top end corner. A background image,\n // after the pinned ground in the source, so a pinned cell keeps it, and\n // no geometry; an application styles its own marks by name.\n Style.nest('&[data-mark]', {\n backgroundImage: `radial-gradient(circle at calc(100% - 6px) 6px, ${ref.outline.focus} 3px, transparent 3.5px)`,\n }),\n ),\n editor: Style.compose(field, refused),\n // The combobox reads as the field it replaces: its draft on the line,\n // and room for the list it opens.\n choice: Style.compose(\n field,\n refused,\n Style.self({ display: 'flex', alignItems: 'center', cursor: 'default' }),\n ),\n // Placed by the view (`position` is the Slot's), below the cell or above it.\n choiceList: Style.compose(\n Style.self({\n zIndex: '3',\n minWidth: '100%',\n maxHeight: '16rem',\n overflowY: 'auto',\n margin: '0',\n padding: ref.space['3xs'],\n listStyle: 'none',\n background: ref.surface.base,\n border: `${ref.border.thin} solid ${ref.outline.default}`,\n borderRadius: ref.radius.md,\n boxShadow: ref.shadow.lg,\n }),\n ),\n choiceOption: Style.compose(\n Style.self({\n padding: `${ref.space['2xs']} ${ref.space.sm}`,\n borderRadius: ref.radius.sm,\n cursor: 'pointer',\n whiteSpace: 'nowrap',\n }),\n Style.nest('&:hover', { background: ref.surface.subtle }),\n Style.nest('&[aria-selected=\"true\"]', {\n background: ref.accent.subtle,\n color: ref.accent.ink,\n }),\n // A finger needs a target this tall.\n Style.media('(pointer: coarse)', {\n minHeight: '44px',\n display: 'flex',\n alignItems: 'center',\n }),\n ),\n // Below the field, over the rows beneath: why the column refused the draft.\n editorError: Style.self({\n background: ref.error.default,\n borderRadius: ref.radius.md,\n boxShadow: ref.shadow.lg,\n color: ref.error['on-fill'],\n fontSize: ref.size.xs,\n fontWeight: ref.weight.medium,\n insetInlineStart: '0',\n paddingBlock: ref.space['3xs'],\n paddingInline: ref.space.xs,\n pointerEvents: 'none',\n position: 'absolute',\n top: `calc(100% + ${ref.space['3xs']})`,\n whiteSpace: 'nowrap',\n zIndex: '5',\n }),\n // The edge a column is resized by: the faint line between headers, which\n // darkens and thickens under the pointer, or while dragged.\n resizeHandle: Style.compose(\n Style.self({\n background: `linear-gradient(to right, transparent calc(100% - 1px), color-mix(in oklch, ${ref.outline.subtle} 70%, transparent) calc(100% - 1px))`,\n WebkitTouchCallout: 'none',\n }),\n Style.pseudo(':hover', {\n background: `linear-gradient(to right, transparent calc(100% - 2px), ${ref.outline.focus} calc(100% - 2px))`,\n }),\n // A finger needs more than the 8px a pointer takes: 24px, the line still at its end.\n Style.at(\n '@media (pointer: coarse)',\n Style.nest('&::before', {\n content: '\"\"',\n position: 'absolute',\n insetBlock: '0',\n insetInlineStart: '-12px',\n insetInlineEnd: '-4px',\n }),\n ),\n ),\n fillHandle: Style.compose(\n Style.self({\n width: '7px',\n height: '7px',\n background: ref.outline.focus,\n border: `1px solid ${ref.surface.base}`,\n cursor: 'crosshair',\n zIndex: '3',\n // The drag is the fill's, not a pan of the grid, and a held press no callout of iOS's.\n touchAction: 'none',\n WebkitTouchCallout: 'none',\n }),\n // On a touch screen, a 44px target around the 7px square it draws.\n Style.at(\n '@media (pointer: coarse)',\n Style.nest('&::before', { content: '\"\"', position: 'absolute', inset: '-18px' }),\n ),\n ),\n menuButton: Style.compose(\n Style.self({\n background: 'none',\n border: 'none',\n color: ref.text.muted,\n cursor: 'pointer',\n marginInlineStart: 'auto',\n // A finger's target, however small the glyph.\n minBlockSize: '1.5rem',\n minInlineSize: '1.5rem',\n paddingInline: ref.space.xs,\n }),\n Style.nest('&[aria-expanded=\"true\"]', { color: ref.text.default }),\n ),\n menu: Style.compose(\n Style.self({\n background: ref.surface.base,\n border: line,\n borderRadius: ref.radius.md,\n fontWeight: ref.weight.normal,\n minWidth: '10rem',\n paddingBlock: ref.space.xs,\n zIndex: '4',\n }),\n Style.pseudo(':focus-visible', { outline: `${ref.border.thick} solid ${ref.outline.focus}` }),\n ),\n menuItem: Style.compose(\n Style.self({ cursor: 'pointer', paddingBlock: ref.space.xs, paddingInline: ref.space.sm }),\n Style.nest('&[data-active=\"true\"]', { background: ref.surface.muted }),\n ),\n // The header's label, as text: the direction is drawn after it.\n sort: Style.compose(\n Style.self({\n alignItems: 'center',\n background: 'none',\n border: 'none',\n color: 'inherit',\n cursor: 'pointer',\n display: 'inline-flex',\n font: 'inherit',\n gap: ref.space.xs,\n // A finger's target in height; its width is the label's.\n minBlockSize: '1.5rem',\n minWidth: '0',\n overflow: 'hidden',\n padding: '0',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }),\n // A small chevron, drawn from two borders, after the label. Its place is\n // kept while unsorted, so sorting moves nothing; it shows faintly under\n // the pointer, to say the label sorts.\n Style.nest('&::after', {\n borderBlockEnd: `1.5px solid currentColor`,\n borderInlineEnd: `1.5px solid currentColor`,\n content: '\"\"',\n flex: 'none',\n height: '0.4em',\n opacity: '0',\n transform: 'translateY(-0.15em) rotate(45deg)',\n transition: `opacity ${ref.motion.fast} ${ref.motion.ease}, transform calc(${ref.motion.fast} * ${ref.knob.travel}) ${ref.motion.ease}`,\n width: '0.4em',\n }),\n Style.nest('&:hover::after', { opacity: '0.35' }),\n Style.nest('&[data-sort=\"desc\"]::after', { opacity: '1' }),\n Style.nest('&[data-sort=\"asc\"]::after', {\n opacity: '1',\n transform: 'translateY(0.1em) rotate(-135deg)',\n }),\n ),\n placeholder: Style.self({ background: ref.surface.subtle }),\n status: Style.self({ color: ref.text.muted, padding: ref.space.md }),\n },\n { layer: Layers.standard.layer('components') },\n)\n"],"mappings":"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"}
package/dist/view.d.ts ADDED
@@ -0,0 +1,140 @@
1
+ import { Option } from "effect";
2
+ import { GridSlots } from "./slots.js";
3
+ import { SlotView } from "foldkit-mixins";
4
+ import { CellAddress, ColumnSpec, ColumnState, DataGridOf, Direction, RowModel, RowSelection, RowStatus, Viewport } from "foldkit-data-grid";
5
+ import { Html, HtmlBuilder } from "foldkit/html";
6
+ export interface GridWords {
7
+ /** In place of rows when there are none. Default `No rows.` */
8
+ readonly empty?: string;
9
+ /** While the first rows are awaited. Default `Loading…`. */
10
+ readonly loading?: string;
11
+ /** When the read failed. `{message}` is the failure's. Default `{message}`. */
12
+ readonly failed?: string;
13
+ /** On the button that asks again after a failure. Default `Try again`. */
14
+ readonly retry?: string;
15
+ /** On the button that loads more rows. Default `More`. */
16
+ readonly more?: string;
17
+ /** The name of a column's menu button. `{column}` is its header. Default `{column} menu`. */
18
+ readonly menu?: string;
19
+ /** Menu items. `{column}` in `show` is the hidden column's header. */
20
+ readonly pinStart?: string;
21
+ readonly pinEnd?: string;
22
+ readonly unpin?: string;
23
+ readonly hide?: string;
24
+ readonly show?: string;
25
+ }
26
+ /** How a column is sorted, and the Message that sorts it next: `foldkit-crud`'s `Sort` gives these. */
27
+ export interface ColumnSort<Message> {
28
+ readonly direction?: 'asc' | 'desc' | undefined;
29
+ readonly message: Message;
30
+ }
31
+ /**
32
+ * A state the application gives one cell, such as an edit not yet saved. The
33
+ * grid draws its `name` as `data-mark` on the cell's Slot, for a style, and
34
+ * its `description` as the cell's `aria-description`, for a screen reader,
35
+ * and its `title`, shown on hover.
36
+ */
37
+ export interface CellMark {
38
+ readonly name: string;
39
+ readonly description: string;
40
+ }
41
+ /** What the grid's view reads, and what the application gives it. */
42
+ export interface GridInput<Row, Id extends string, GridMessage, Message> {
43
+ /** The `DataGrid` Model as placed in the parent. */
44
+ readonly state: {
45
+ readonly focus: {
46
+ readonly current: Option.Option<CellAddress<Id>>;
47
+ readonly header: Option.Option<Id>;
48
+ };
49
+ readonly viewport: Viewport;
50
+ readonly columns: ColumnState<Id>;
51
+ readonly selection: {
52
+ readonly rows: RowSelection;
53
+ readonly anchor: Option.Option<string>;
54
+ readonly cells: Option.Option<{
55
+ readonly anchor: CellAddress<Id>;
56
+ readonly focus: CellAddress<Id>;
57
+ }>;
58
+ };
59
+ readonly editing: Option.Option<{
60
+ readonly address: CellAddress<Id>;
61
+ readonly draft: string;
62
+ readonly error: Option.Option<string>;
63
+ }>;
64
+ readonly dragging: Option.Option<{
65
+ readonly column: Id;
66
+ readonly delta: number;
67
+ }>;
68
+ readonly menu: Option.Option<{
69
+ readonly column: Id;
70
+ readonly active: number;
71
+ }>;
72
+ readonly filling: Option.Option<{
73
+ readonly source: {
74
+ readonly anchor: CellAddress<Id>;
75
+ readonly focus: CellAddress<Id>;
76
+ };
77
+ readonly to: CellAddress<Id>;
78
+ }>;
79
+ };
80
+ /** The application's rows, in its order; the view draws them through `state.columns`. */
81
+ readonly rows: RowModel<Row>;
82
+ /** Lifts the grid's own Messages into the parent's: the placement's wrapper. */
83
+ readonly wrap: (message: GridMessage) => Message;
84
+ /** The grid's accessible name. */
85
+ readonly label: string;
86
+ readonly rowHeight: number;
87
+ readonly headerHeight: number;
88
+ readonly overscan?: {
89
+ readonly rows?: number;
90
+ readonly columns?: number;
91
+ };
92
+ readonly direction?: Direction;
93
+ /** Draws one cell; by default the column's value, as text. */
94
+ readonly cell?: (column: Id, row: Row, h: HtmlBuilder<Message>) => Html | string;
95
+ /** A cell's mark, if it has one; asked only for the cells drawn. */
96
+ readonly marks?: (address: CellAddress<Id>) => Option.Option<CellMark>;
97
+ /**
98
+ * How a choice column is edited: a list the grid draws, styled with the
99
+ * page (`list`, the default), or the platform's own `select` (`native`),
100
+ * whose picker suits a touch screen better. Pass `native` from a media
101
+ * fact in the Model, such as a coarse pointer; the view reads no media.
102
+ */
103
+ readonly choiceEditor?: 'list' | 'native';
104
+ readonly words?: GridWords;
105
+ /**
106
+ * Where the rows' source stands (`GridCrud.status` for a Remote page).
107
+ * Default `Ready`. The grid holds no loading state: the source's owner does.
108
+ */
109
+ readonly status?: RowStatus;
110
+ /** Asks again after a failure; given, a failed grid shows a button that sends it. */
111
+ readonly onRetry?: Message;
112
+ /**
113
+ * Loads more rows; given, a grid whose count is not known yet shows a button
114
+ * that sends it. Attach `MoreOnScroll` to send it as the end comes into view.
115
+ */
116
+ readonly onMore?: Message;
117
+ /**
118
+ * A menu button on each header, opening the column's menu: pin it to the
119
+ * start or the end or unpin it, hide it, or show a hidden column. On a
120
+ * focused header Alt+ArrowDown, Shift+F10 or the menu key opens it.
121
+ */
122
+ readonly columnMenu?: boolean;
123
+ /** The columns that sort, each with its direction and its Message. */
124
+ readonly sort?: { readonly [K in Id]?: ColumnSort<Message>; };
125
+ }
126
+ /** Whether the rows' source is reading: the grid says so, and asks for nothing more. */
127
+ export declare const isBusy: (status: RowStatus | undefined) => boolean;
128
+ declare const view: <Message>() => {
129
+ /**
130
+ * The view of one `DataGrid`. It draws the grid's columns' headers and the
131
+ * window of cells `VirtualGrid.window` picks for the placed viewport, and
132
+ * sends the grid's Messages through `wrap`: `Moved` for a key, with the
133
+ * scroll that reveals the cell, `Focused` for the pointer, `Measured` from
134
+ * the scroll container. Attach Style and Behavior to the result.
135
+ */
136
+ define: <Row, Specs extends Record<string, ColumnSpec<Row, unknown>>>(grid: DataGridOf<Row, Specs>) => SlotView.SlotView<typeof GridSlots, GridInput<Row, keyof Specs & string, typeof grid.Message.Type, Message>, Message>;
137
+ };
138
+ export declare const DataGridView: typeof view;
139
+ export {};
140
+ //# sourceMappingURL=view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","names":[],"sources":["../src/view.ts"],"mappings":";;;;;iBAkCiB;;WAEN;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;WACA;WACA;WACA;WACA;;;iBAIM,WAAW;WACjB;WACA,SAAS;;;;;;;;iBASH;WACN;WACA;;;iBAIM,UAAU,KAAK,mBAAmB,aAAa;;WAErD;aACE;eACE,SAAS,OAAO,OAAO,YAAY;eACnC,QAAQ,OAAO,OAAO;;aAExB,UAAU;aACV,SAAS,YAAY;aACrB;eACE,MAAM;eACN,QAAQ,OAAO;eACf,OAAO,OAAO;iBACZ,QAAQ,YAAY;iBACpB,OAAO,YAAY;;;aAGvB,SAAS,OAAO;eACd,SAAS,YAAY;eACrB;eACA,OAAO,OAAO;;aAEhB,UAAU,OAAO;eAAkB,QAAQ;eAAa;;aACxD,MAAM,OAAO;eAAkB,QAAQ;eAAa;;aACpD,SAAS,OAAO;eACd;iBAAmB,QAAQ,YAAY;iBAAc,OAAO,YAAY;;eACxE,IAAI,YAAY;;;;WAIpB,MAAM,SAAS;;WAEf,OAAO,SAAS,gBAAgB;;WAEhC;WACA;WACA;WACA;aAAsB;aAAwB;;WAC9C,YAAY;;WAEZ,QAAQ,QAAQ,IAAI,KAAK,KAAK,GAAG,YAAY,aAAa;;WAE1D,SAAS,SAAS,YAAY,QAAQ,OAAO,OAAO;;;;;;;WAOpD;WACA,QAAQ;;;;;WAKR,SAAS;;WAET,UAAU;;;;;WAKV,SAAS;;;;;;WAMT;;WAEA,mBAAmB,KAAK,MAAM,WAAW;;;qBAMvC,SAAM,QAAY;cA8CzB,OAAQ;;;;;;;;EAQZ,SAAS,KAAK,cAAc,eAAe,WAAW,gBAAc,MAC5D,WAAW,KAAK,WACrB,SAAS,gBACH,WACP,UAAU,WAAW,uBAAuB,KAAK,QAAQ,MAAM,UAC/D;;qBAitCS,qBAAY"}