@expressive/ui 0.0.0-stage → 0.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -2
  3. package/dist/button/base.d.ts +63 -0
  4. package/dist/button/base.js +90 -0
  5. package/dist/button/base.js.map +1 -0
  6. package/dist/button/button.d.ts +56 -0
  7. package/dist/button/button.js +138 -0
  8. package/dist/button/button.js.map +1 -0
  9. package/dist/calendar/base.d.ts +112 -0
  10. package/dist/calendar/base.js +235 -0
  11. package/dist/calendar/base.js.map +1 -0
  12. package/dist/calendar/calendar.d.ts +78 -0
  13. package/dist/calendar/calendar.js +145 -0
  14. package/dist/calendar/calendar.js.map +1 -0
  15. package/dist/calendar/date.js +56 -0
  16. package/dist/calendar/date.js.map +1 -0
  17. package/dist/dialog/base.d.ts +74 -0
  18. package/dist/dialog/base.js +143 -0
  19. package/dist/dialog/base.js.map +1 -0
  20. package/dist/dialog/dialog.d.ts +69 -0
  21. package/dist/dialog/dialog.js +108 -0
  22. package/dist/dialog/dialog.js.map +1 -0
  23. package/dist/dom.d.ts +16 -0
  24. package/dist/dom.js +17 -0
  25. package/dist/dropzone/base.d.ts +77 -0
  26. package/dist/dropzone/base.js +159 -0
  27. package/dist/dropzone/base.js.map +1 -0
  28. package/dist/dropzone/dropzone.d.ts +38 -0
  29. package/dist/dropzone/dropzone.js +92 -0
  30. package/dist/dropzone/dropzone.js.map +1 -0
  31. package/dist/form/base.d.ts +157 -0
  32. package/dist/form/base.js +243 -0
  33. package/dist/form/base.js.map +1 -0
  34. package/dist/form/form.d.ts +123 -0
  35. package/dist/form/form.js +179 -0
  36. package/dist/form/form.js.map +1 -0
  37. package/dist/icons/caret.d.ts +8 -0
  38. package/dist/icons/caret.js +16 -0
  39. package/dist/icons/caret.js.map +1 -0
  40. package/dist/icons/check.d.ts +8 -0
  41. package/dist/icons/check.js +16 -0
  42. package/dist/icons/check.js.map +1 -0
  43. package/dist/icons/cross.d.ts +8 -0
  44. package/dist/icons/cross.js +16 -0
  45. package/dist/icons/cross.js.map +1 -0
  46. package/dist/icons/icon.js +16 -0
  47. package/dist/icons/icon.js.map +1 -0
  48. package/dist/icons/spinner.d.ts +8 -0
  49. package/dist/icons/spinner.js +27 -0
  50. package/dist/icons/spinner.js.map +1 -0
  51. package/dist/icons/upload.d.ts +8 -0
  52. package/dist/icons/upload.js +16 -0
  53. package/dist/icons/upload.js.map +1 -0
  54. package/dist/index.d.ts +11 -0
  55. package/dist/index.js +12 -0
  56. package/dist/layout/base.d.ts +88 -0
  57. package/dist/layout/base.js +158 -0
  58. package/dist/layout/base.js.map +1 -0
  59. package/dist/layout/layout.d.ts +53 -0
  60. package/dist/layout/layout.js +80 -0
  61. package/dist/layout/layout.js.map +1 -0
  62. package/dist/piece.js +13 -0
  63. package/dist/piece.js.map +1 -0
  64. package/dist/popover/base.d.ts +94 -0
  65. package/dist/popover/base.js +176 -0
  66. package/dist/popover/base.js.map +1 -0
  67. package/dist/popover/place.d.ts +12 -0
  68. package/dist/popover/place.js +32 -0
  69. package/dist/popover/place.js.map +1 -0
  70. package/dist/popover/popover.d.ts +52 -0
  71. package/dist/popover/popover.js +104 -0
  72. package/dist/popover/popover.js.map +1 -0
  73. package/dist/select/base.d.ts +196 -0
  74. package/dist/select/base.js +409 -0
  75. package/dist/select/base.js.map +1 -0
  76. package/dist/select/select.d.ts +119 -0
  77. package/dist/select/select.js +219 -0
  78. package/dist/select/select.js.map +1 -0
  79. package/dist/table/base.d.ts +96 -0
  80. package/dist/table/base.js +154 -0
  81. package/dist/table/base.js.map +1 -0
  82. package/dist/table/column.d.ts +53 -0
  83. package/dist/table/column.js +29 -0
  84. package/dist/table/column.js.map +1 -0
  85. package/dist/table/table.d.ts +41 -0
  86. package/dist/table/table.js +101 -0
  87. package/dist/table/table.js.map +1 -0
  88. package/package.json +76 -4
@@ -0,0 +1,219 @@
1
+ import { Select as Select$1 } from "./base.js";
2
+ import { Caret } from "../icons/caret.js";
3
+ import { Cross } from "../icons/cross.js";
4
+ import { Portal, style } from "@expressive/dom";
5
+ import { jsx, jsxs } from "@expressive/dom/jsx-runtime";
6
+
7
+ //#region src/select/select.tsx
8
+ const Root = ({ children }) => {
9
+ const { disabled } = Select$1.get();
10
+ return /* @__PURE__ */ jsx("div", {
11
+ _disabled: disabled,
12
+ children
13
+ });
14
+ };
15
+ style(Root, {
16
+ position: "relative",
17
+ _disabled: {
18
+ opacity: "0.6",
19
+ pointerEvents: "none"
20
+ }
21
+ });
22
+ const Control = ({ children }) => {
23
+ const { focused, controlProps } = Select$1.get();
24
+ return /* @__PURE__ */ jsx("div", {
25
+ ...controlProps,
26
+ _focused: focused,
27
+ children
28
+ });
29
+ };
30
+ style(Control, {
31
+ display: "flex",
32
+ alignItems: "center",
33
+ minHeight: "38px",
34
+ background: "var(--ui-surface, #fff)",
35
+ border: "1px solid var(--ui-line, #ccc)",
36
+ borderRadius: "4px",
37
+ cursor: "default",
38
+ transition: "border-color 100ms, box-shadow 100ms",
39
+ _focused: {
40
+ borderColor: "var(--ui-accent, #2684ff)",
41
+ boxShadow: "0 0 0 1px var(--ui-accent, #2684ff)"
42
+ }
43
+ });
44
+ const Values = ({ children }) => /* @__PURE__ */ jsx("div", { children });
45
+ style(Values, {
46
+ position: "relative",
47
+ flex: "1",
48
+ display: "flex",
49
+ flexWrap: "wrap",
50
+ alignItems: "center",
51
+ gap: "4px",
52
+ minWidth: "0",
53
+ padding: "2px 8px"
54
+ });
55
+ const Chip = ({ option }) => {
56
+ const { removeProps } = Select$1.get();
57
+ return /* @__PURE__ */ jsxs("span", { children: [option.label, /* @__PURE__ */ jsx("button", {
58
+ ...removeProps(option),
59
+ children: /* @__PURE__ */ jsx(Cross, {})
60
+ })] });
61
+ };
62
+ style(Chip, {
63
+ display: "inline-flex",
64
+ alignItems: "center",
65
+ minWidth: "0",
66
+ paddingLeft: "6px",
67
+ borderRadius: "3px",
68
+ background: "var(--ui-chip, #e6e6e6)",
69
+ fontSize: "85%",
70
+ _button: {
71
+ display: "flex",
72
+ marginLeft: "2px",
73
+ padding: "3px",
74
+ border: "0",
75
+ borderRadius: "3px",
76
+ background: "none",
77
+ color: "inherit",
78
+ cursor: "pointer"
79
+ }
80
+ });
81
+ const Value = ({ option }) => /* @__PURE__ */ jsx("span", { children: option.label });
82
+ style(Value, {
83
+ position: "absolute",
84
+ left: "10px",
85
+ right: "8px",
86
+ overflow: "hidden",
87
+ textOverflow: "ellipsis",
88
+ whiteSpace: "nowrap",
89
+ pointerEvents: "none"
90
+ });
91
+ const Input = () => /* @__PURE__ */ jsx("input", { ...Select$1.get().inputProps });
92
+ style(Input, {
93
+ flex: "1",
94
+ width: "0",
95
+ minWidth: "2px",
96
+ margin: "0",
97
+ padding: "4px 0",
98
+ border: "0",
99
+ outline: "0",
100
+ background: "none",
101
+ color: "inherit",
102
+ font: "inherit"
103
+ });
104
+ const indicator = {
105
+ display: "flex",
106
+ alignSelf: "stretch",
107
+ alignItems: "center",
108
+ padding: "0 8px",
109
+ border: "0",
110
+ background: "none",
111
+ color: "var(--ui-muted, #999)",
112
+ cursor: "pointer"
113
+ };
114
+ const Clear = () => /* @__PURE__ */ jsx("button", {
115
+ ...Select$1.get().clearProps,
116
+ children: /* @__PURE__ */ jsx(Cross, {})
117
+ });
118
+ style(Clear, indicator);
119
+ const Toggle = () => {
120
+ const { open, toggleProps } = Select$1.get();
121
+ return /* @__PURE__ */ jsx("button", {
122
+ ...toggleProps,
123
+ children: /* @__PURE__ */ jsx(Caret, { _open: open })
124
+ });
125
+ };
126
+ style(Toggle, indicator, {
127
+ borderLeft: "1px solid var(--ui-line, #ccc)",
128
+ margin: "8px 0",
129
+ _open: { transform: "rotate(180deg)" }
130
+ });
131
+ const Layer = ({ children }) => /* @__PURE__ */ jsx(Portal, {
132
+ into: "body",
133
+ children
134
+ });
135
+ const Menu = ({ children }) => /* @__PURE__ */ jsx("ul", {
136
+ ...Select$1.get().menuProps,
137
+ children
138
+ });
139
+ style(Menu, {
140
+ position: "fixed",
141
+ zIndex: "1000",
142
+ boxSizing: "border-box",
143
+ maxHeight: "300px",
144
+ overflowY: "auto",
145
+ margin: "0",
146
+ padding: "4px 0",
147
+ listStyle: "none",
148
+ background: "var(--ui-surface, #fff)",
149
+ borderRadius: "4px",
150
+ boxShadow: "0 0 0 1px rgba(0, 0, 0, 0.1), 0 4px 11px rgba(0, 0, 0, 0.1)"
151
+ });
152
+ const Option = ({ option, index }) => {
153
+ const { active, selected, props } = Select$1.get().optionProps(option, index);
154
+ return /* @__PURE__ */ jsx("li", {
155
+ ...props,
156
+ _active: active,
157
+ _selected: selected,
158
+ children: option.label
159
+ });
160
+ };
161
+ style(Option, {
162
+ padding: "8px 12px",
163
+ cursor: "default",
164
+ userSelect: "none",
165
+ _active: { background: "var(--ui-highlight, #deebff)" },
166
+ _selected: {
167
+ background: "var(--ui-accent, #2684ff)",
168
+ color: "#fff"
169
+ }
170
+ });
171
+ const Empty = () => /* @__PURE__ */ jsx("li", { children: "No options" });
172
+ style(Empty, {
173
+ padding: "8px 12px",
174
+ color: "var(--ui-muted, #999)",
175
+ textAlign: "center"
176
+ });
177
+ /**
178
+ * Combobox with search, single or multiple selection, keyboard navigation and live announcements.
179
+ *
180
+ * Pieces - `Root`, `Control`, `Values`, `Chip`, `Value`, `Input`, `Clear`, `Toggle`, `Layer`, `Menu`, `Option`,
181
+ * `Empty` - are function components reading `Select.get()`, each styled on its own; pass one as a prop or assign it
182
+ * in a subclass to replace it. Stock pieces are statics. `Layer` portals the menu to the body, so a dialog or a
183
+ * scrolling container does not clip it; the menu sits under the control, flips above when only that fits, and
184
+ * follows scroll and resize.
185
+ *
186
+ * @example
187
+ * <label htmlFor="role">Role</label>
188
+ * <Select id="role" options={roles} value={this.role} onChange={(role) => (this.role = role)} />
189
+ */
190
+ var Select = class extends Select$1 {
191
+ static Root = Root;
192
+ static Control = Control;
193
+ static Values = Values;
194
+ static Chip = Chip;
195
+ static Value = Value;
196
+ static Input = Input;
197
+ static Clear = Clear;
198
+ static Toggle = Toggle;
199
+ static Layer = Layer;
200
+ static Menu = Menu;
201
+ static Option = Option;
202
+ static Empty = Empty;
203
+ Root = Root;
204
+ Control = Control;
205
+ Values = Values;
206
+ Chip = Chip;
207
+ Value = Value;
208
+ Input = Input;
209
+ Clear = Clear;
210
+ Toggle = Toggle;
211
+ Layer = Layer;
212
+ Menu = Menu;
213
+ Option = Option;
214
+ Empty = Empty;
215
+ };
216
+
217
+ //#endregion
218
+ export { Select };
219
+ //# sourceMappingURL=select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.js","names":["Base.Select"],"sources":["../../src/select/select.tsx"],"sourcesContent":["/** @jsxImportSource @expressive/dom */\nimport { Component } from '@expressive/mvc';\nimport { Portal, style } from '@expressive/dom';\n\nimport { Caret, Cross } from '../icons';\nimport * as Base from './base';\n\ndeclare namespace Select {\n type Option<T = unknown> = Base.Select.Option<T>;\n type Value = Base.Select.Value;\n type Key = Base.Select.Key;\n}\n\nconst Root = ({ children }: { children: Component.Node }): Component.Node => {\n const { disabled } = Base.Select.get();\n\n return <div _disabled={disabled}>{children}</div>;\n};\n\nstyle(Root, {\n position: 'relative',\n _disabled: {\n opacity: '0.6',\n pointerEvents: 'none'\n }\n});\n\nconst Control = ({ children }: { children: Component.Node }): Component.Node => {\n const { focused, controlProps } = Base.Select.get();\n\n return <div {...controlProps} _focused={focused}>{children}</div>;\n};\n\nstyle(Control, {\n display: 'flex',\n alignItems: 'center',\n minHeight: '38px',\n background: 'var(--ui-surface, #fff)',\n border: '1px solid var(--ui-line, #ccc)',\n borderRadius: '4px',\n cursor: 'default',\n transition: 'border-color 100ms, box-shadow 100ms',\n _focused: {\n borderColor: 'var(--ui-accent, #2684ff)',\n boxShadow: '0 0 0 1px var(--ui-accent, #2684ff)'\n }\n});\n\nconst Values = ({ children }: { children: Component.Node }): Component.Node => <div>{children}</div>;\n\nstyle(Values, {\n position: 'relative',\n flex: '1',\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: '4px',\n minWidth: '0',\n padding: '2px 8px'\n});\n\nconst Chip = ({ option }: { option: Select.Option }): Component.Node => {\n const { removeProps } = Base.Select.get();\n\n return (\n <span>\n {option.label}\n <button {...removeProps(option)}>\n <Cross />\n </button>\n </span>\n );\n};\n\nstyle(Chip, {\n display: 'inline-flex',\n alignItems: 'center',\n minWidth: '0',\n paddingLeft: '6px',\n borderRadius: '3px',\n background: 'var(--ui-chip, #e6e6e6)',\n fontSize: '85%',\n _button: {\n display: 'flex',\n marginLeft: '2px',\n padding: '3px',\n border: '0',\n borderRadius: '3px',\n background: 'none',\n color: 'inherit',\n cursor: 'pointer'\n }\n});\n\nconst Value = ({ option }: { option: Select.Option }): Component.Node => <span>{option.label}</span>;\n\nstyle(Value, {\n position: 'absolute',\n left: '10px',\n right: '8px',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n pointerEvents: 'none'\n});\n\nconst Input = (): Component.Node => <input {...Base.Select.get().inputProps} />;\n\nstyle(Input, {\n flex: '1',\n width: '0',\n minWidth: '2px',\n margin: '0',\n padding: '4px 0',\n border: '0',\n outline: '0',\n background: 'none',\n color: 'inherit',\n font: 'inherit'\n});\n\nconst indicator = {\n display: 'flex',\n alignSelf: 'stretch',\n alignItems: 'center',\n padding: '0 8px',\n border: '0',\n background: 'none',\n color: 'var(--ui-muted, #999)',\n cursor: 'pointer'\n};\n\nconst Clear = (): Component.Node => (\n <button {...Base.Select.get().clearProps}>\n <Cross />\n </button>\n);\n\nstyle(Clear, indicator);\n\nconst Toggle = (): Component.Node => {\n const { open, toggleProps } = Base.Select.get();\n\n return (\n <button {...toggleProps}>\n <Caret _open={open} />\n </button>\n );\n};\n\nstyle(Toggle, indicator, {\n borderLeft: '1px solid var(--ui-line, #ccc)',\n margin: '8px 0',\n _open: {\n transform: 'rotate(180deg)'\n }\n});\n\nconst Layer = ({ children }: { children: Component.Node }): Component.Node => <Portal into=\"body\">{children}</Portal>;\n\nconst Menu = ({ children }: { children: Component.Node }): Component.Node => (\n <ul {...Base.Select.get().menuProps}>{children}</ul>\n);\n\nstyle(Menu, {\n position: 'fixed',\n zIndex: '1000',\n boxSizing: 'border-box',\n maxHeight: '300px',\n overflowY: 'auto',\n margin: '0',\n padding: '4px 0',\n listStyle: 'none',\n background: 'var(--ui-surface, #fff)',\n borderRadius: '4px',\n boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1), 0 4px 11px rgba(0, 0, 0, 0.1)'\n});\n\nconst Option = ({ option, index }: { option: Select.Option; index: number }): Component.Node => {\n const { active, selected, props } = Base.Select.get().optionProps(option, index);\n\n return (\n <li {...props} _active={active} _selected={selected}>\n {option.label}\n </li>\n );\n};\n\nstyle(Option, {\n padding: '8px 12px',\n cursor: 'default',\n userSelect: 'none',\n _active: {\n background: 'var(--ui-highlight, #deebff)'\n },\n _selected: {\n background: 'var(--ui-accent, #2684ff)',\n color: '#fff'\n }\n});\n\nconst Empty = (): Component.Node => <li>No options</li>;\n\nstyle(Empty, {\n padding: '8px 12px',\n color: 'var(--ui-muted, #999)',\n textAlign: 'center'\n});\n\n/**\n * Combobox with search, single or multiple selection, keyboard navigation and live announcements.\n *\n * Pieces - `Root`, `Control`, `Values`, `Chip`, `Value`, `Input`, `Clear`, `Toggle`, `Layer`, `Menu`, `Option`,\n * `Empty` - are function components reading `Select.get()`, each styled on its own; pass one as a prop or assign it\n * in a subclass to replace it. Stock pieces are statics. `Layer` portals the menu to the body, so a dialog or a\n * scrolling container does not clip it; the menu sits under the control, flips above when only that fits, and\n * follows scroll and resize.\n *\n * @example\n * <label htmlFor=\"role\">Role</label>\n * <Select id=\"role\" options={roles} value={this.role} onChange={(role) => (this.role = role)} />\n */\nclass Select extends Base.Select {\n static Root = Root;\n static Control = Control;\n static Values = Values;\n static Chip = Chip;\n static Value = Value;\n static Input = Input;\n static Clear = Clear;\n static Toggle = Toggle;\n static Layer = Layer;\n static Menu = Menu;\n static Option = Option;\n static Empty = Empty;\n\n Root = Root;\n Control = Control;\n Values = Values;\n Chip = Chip;\n Value = Value;\n Input = Input;\n Clear = Clear;\n Toggle = Toggle;\n Layer = Layer;\n Menu = Menu;\n Option = Option;\n Empty = Empty;\n}\n\nexport { Chip, Clear, Control, Empty, Input, Layer, Menu, Option, Root, Select, Toggle, Value, Values };\n"],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ import { CellSlot, Field, HeadSlot } from "./column.js";
2
+ import { Component, Model } from "@expressive/mvc";
3
+
4
+ //#region src/table/base.d.ts
5
+ declare namespace Table {
6
+ interface RowProps<T = any> {
7
+ data: T;
8
+ index: number;
9
+ children: Component.Node;
10
+ }
11
+ type Press = Pick<MouseEvent, 'target' | 'currentTarget'>;
12
+ type Key = Press & Pick<KeyboardEvent, 'key' | 'preventDefault'>;
13
+ /** A piece: a function component, or a Component class taking the same props. */
14
+ type Slot<P> = ((props: P) => Component.Node) | (new (...args: any[]) => Model & {
15
+ render(props: P): Component.Node;
16
+ });
17
+ type Wrap = Slot<{
18
+ children: Component.Node;
19
+ }>;
20
+ type Line<T = any> = Slot<RowProps<T>>;
21
+ type Fill = Slot<{
22
+ span: number;
23
+ }>;
24
+ }
25
+ /**
26
+ * One row: pressing, selection and its ARIA, read off the enclosing `Table`.
27
+ *
28
+ * `render` is abstract - a skin extends this and renders the row element, spreading `attrs`.
29
+ */
30
+ declare class Row<T = any> extends Component {
31
+ protected table: Table<T>;
32
+ data: T;
33
+ index: number;
34
+ get pressable(): boolean;
35
+ get selected(): boolean;
36
+ /** For the row's element: `aria-current` when selected; with `onPress`, focusable and pressed by click, Enter and Space. */
37
+ get attrs(): {
38
+ 'aria-current': "true" | undefined;
39
+ readonly tabIndex?: undefined;
40
+ readonly onClick?: undefined;
41
+ readonly onKeyDown?: undefined;
42
+ } | {
43
+ readonly tabIndex: 0;
44
+ readonly 'aria-current': "true" | undefined;
45
+ readonly onClick: (event: Table.Press) => void;
46
+ readonly onKeyDown: (event: Table.Key) => void;
47
+ };
48
+ press(): void;
49
+ click(event: Table.Press): void;
50
+ keyDown(event: Table.Key): void;
51
+ /** Whether a press landed on a control inside the row, which keeps the press. Defaults to the DOM's `closest`. */
52
+ protected nested(event: Table.Press): boolean;
53
+ render(_props: {
54
+ children: Component.Node;
55
+ }): Component.Node;
56
+ }
57
+ /**
58
+ * Data table behavior without a look: columns declared as `Column` children, row keys, pressing and selection,
59
+ * assembled from pieces.
60
+ *
61
+ * Every visible piece but `Empty` is a placeholder that throws when rendered - a skin assigns each one it renders. `Row` is
62
+ * a Component class - one per row, so a change re-renders only the rows it touches; a skin extends it and spreads `attrs`.
63
+ * `Head` writes `scope="col"` itself and applies the column's `size`.
64
+ */
65
+ declare class Table<T = any> extends Component {
66
+ data: readonly T[];
67
+ /** Stable identity per row; defaults to the row object itself, else the index. */
68
+ rowKey?: (row: T, index: number) => string | number;
69
+ onPress?: (row: T, index: number) => void;
70
+ /** Row to mark selected, compared by identity. */
71
+ selected?: T;
72
+ /** Shown in place of rows when `data` is empty. */
73
+ empty: Component.Node;
74
+ static Root: Table.Wrap;
75
+ static Header: Table.Wrap;
76
+ static Body: Table.Wrap;
77
+ static Head: HeadSlot;
78
+ static Row: typeof Row<any>;
79
+ static Cell: CellSlot;
80
+ static Empty: Table.Fill;
81
+ Root: Table.Wrap;
82
+ Header: Table.Wrap;
83
+ Body: Table.Wrap;
84
+ Head: HeadSlot<T>;
85
+ Row: Table.Line<T>;
86
+ Cell: CellSlot<T>;
87
+ Empty: Table.Fill;
88
+ /** A cell's content when its column has no `format`. */
89
+ value(row: T, field: Field<T>): Component.Node;
90
+ render(props: {
91
+ children?: Component.Node;
92
+ }): Component.Node;
93
+ }
94
+ //#endregion
95
+ export { Row, Table };
96
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1,154 @@
1
+ import { missing, none } from "../piece.js";
2
+ import { Column } from "./column.js";
3
+ import { Component, get } from "@expressive/mvc";
4
+ import { Fragment, childrenOf, jsx, jsxs, propsOf, typeOf } from "@expressive/mvc/jsx-runtime";
5
+
6
+ //#region src/table/base.tsx
7
+ const CONTROL = "a, button, input, select, textarea, label, summary";
8
+ const IDS = /* @__PURE__ */ new WeakMap();
9
+ let ROWS = 0;
10
+ /**
11
+ * One row: pressing, selection and its ARIA, read off the enclosing `Table`.
12
+ *
13
+ * `render` is abstract - a skin extends this and renders the row element, spreading `attrs`.
14
+ */
15
+ var Row = class extends Component {
16
+ table = get(Table);
17
+ data = void 0;
18
+ index = 0;
19
+ get pressable() {
20
+ return !!this.table.onPress;
21
+ }
22
+ get selected() {
23
+ const { selected } = this.table;
24
+ return selected !== void 0 && this.data === selected;
25
+ }
26
+ /** For the row's element: `aria-current` when selected; with `onPress`, focusable and pressed by click, Enter and Space. */
27
+ get attrs() {
28
+ const { pressable, selected } = this;
29
+ const current = selected ? "true" : void 0;
30
+ if (!pressable) return { "aria-current": current };
31
+ return {
32
+ tabIndex: 0,
33
+ "aria-current": current,
34
+ onClick: this.click,
35
+ onKeyDown: this.keyDown
36
+ };
37
+ }
38
+ press() {
39
+ this.table.onPress(this.data, this.index);
40
+ }
41
+ click(event) {
42
+ if (!this.nested(event)) this.press();
43
+ }
44
+ keyDown(event) {
45
+ if (event.target !== event.currentTarget || event.key != "Enter" && event.key != " ") return;
46
+ event.preventDefault();
47
+ this.press();
48
+ }
49
+ /** Whether a press landed on a control inside the row, which keeps the press. Defaults to the DOM's `closest`. */
50
+ nested(event) {
51
+ const control = event.target.closest(CONTROL);
52
+ return !!control && control !== event.currentTarget;
53
+ }
54
+ render(_props) {
55
+ return missing("Table.Row")();
56
+ }
57
+ };
58
+ /**
59
+ * Data table behavior without a look: columns declared as `Column` children, row keys, pressing and selection,
60
+ * assembled from pieces.
61
+ *
62
+ * Every visible piece but `Empty` is a placeholder that throws when rendered - a skin assigns each one it renders. `Row` is
63
+ * a Component class - one per row, so a change re-renders only the rows it touches; a skin extends it and spreads `attrs`.
64
+ * `Head` writes `scope="col"` itself and applies the column's `size`.
65
+ */
66
+ var Table = class extends Component {
67
+ data = [];
68
+ /** Stable identity per row; defaults to the row object itself, else the index. */
69
+ rowKey = void 0;
70
+ onPress = void 0;
71
+ /** Row to mark selected, compared by identity. */
72
+ selected = void 0;
73
+ /** Shown in place of rows when `data` is empty. */
74
+ empty = "No rows";
75
+ static Root = missing("Table.Root");
76
+ static Header = missing("Table.Header");
77
+ static Body = missing("Table.Body");
78
+ static Head = missing("Table.Head");
79
+ static Row = Row;
80
+ static Cell = missing("Table.Cell");
81
+ static Empty = none;
82
+ Root = kind(this).Root;
83
+ Header = kind(this).Header;
84
+ Body = kind(this).Body;
85
+ Head = kind(this).Head;
86
+ Row = kind(this).Row;
87
+ Cell = kind(this).Cell;
88
+ Empty = kind(this).Empty;
89
+ /** A cell's content when its column has no `format`. */
90
+ value(row, field) {
91
+ return row && typeof row == "object" ? row[field.id] : null;
92
+ }
93
+ render(props) {
94
+ const { data, rowKey, Head, Row, Cell } = this;
95
+ const fields = resolve(props.children);
96
+ return /* @__PURE__ */ jsxs(this.Root, { children: [/* @__PURE__ */ jsx(this.Header, { children: fields.map((field) => {
97
+ return /* @__PURE__ */ jsx(field.Head || Head, {
98
+ field,
99
+ className: field.className,
100
+ children: field.name
101
+ }, field.id || field.index);
102
+ }) }), /* @__PURE__ */ jsxs(this.Body, { children: [data.length == 0 && /* @__PURE__ */ jsx(this.Empty, { span: fields.length }), data.map((row, index) => /* @__PURE__ */ jsx(Row, {
103
+ data: row,
104
+ index,
105
+ children: fields.map((field) => {
106
+ return /* @__PURE__ */ jsx(field.Cell || Cell, {
107
+ field,
108
+ data: row,
109
+ className: field.className,
110
+ children: field.format ? field.format(row, index) : this.value(row, field)
111
+ }, field.id || field.index);
112
+ })
113
+ }, rowKey ? rowKey(row, index) : identity(row, index)))] })] });
114
+ }
115
+ };
116
+ function identity(row, index) {
117
+ if (!row || typeof row != "object") return index;
118
+ let id = IDS.get(row);
119
+ if (id === void 0) IDS.set(row, id = ++ROWS);
120
+ return `#${id}`;
121
+ }
122
+ function kind(table) {
123
+ return table.constructor;
124
+ }
125
+ function resolve(children) {
126
+ const fields = [];
127
+ for (const node of flatten(children)) {
128
+ const type = typeOf(node);
129
+ if (type !== Column && !(typeof type == "function" && type.prototype instanceof Column)) continue;
130
+ const props = propsOf(node);
131
+ const name = props.name ?? "";
132
+ fields.push({
133
+ name,
134
+ id: props.id || (typeof name == "string" ? name.toLowerCase() : ""),
135
+ className: props.className || "",
136
+ index: fields.length,
137
+ Cell: props.Cell,
138
+ Head: props.Head,
139
+ format: props.format,
140
+ size: props.size
141
+ });
142
+ }
143
+ return fields;
144
+ }
145
+ function flatten(children) {
146
+ const out = [];
147
+ for (const node of childrenOf(children)) if (typeOf(node) === Fragment) out.push(...flatten(propsOf(node).children));
148
+ else out.push(node);
149
+ return out;
150
+ }
151
+
152
+ //#endregion
153
+ export { Row, Table };
154
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/table/base.tsx"],"sourcesContent":["import { Component, get, type Model } from '@expressive/mvc';\nimport { Fragment, childrenOf, propsOf, typeOf } from '@expressive/mvc/jsx-runtime';\n\nimport { missing, none } from '../piece';\nimport { Column, type CellSlot, type Field, type HeadSlot } from './column';\n\ndeclare namespace Table {\n interface RowProps<T = any> {\n data: T;\n index: number;\n children: Component.Node;\n }\n\n type Press = Pick<MouseEvent, 'target' | 'currentTarget'>;\n type Key = Press & Pick<KeyboardEvent, 'key' | 'preventDefault'>;\n\n /** A piece: a function component, or a Component class taking the same props. */\n type Slot<P> = ((props: P) => Component.Node) | (new (...args: any[]) => Model & { render(props: P): Component.Node });\n\n type Wrap = Slot<{ children: Component.Node }>;\n type Line<T = any> = Slot<RowProps<T>>;\n type Fill = Slot<{ span: number }>;\n}\n\nconst CONTROL = 'a, button, input, select, textarea, label, summary';\n\nconst IDS = new WeakMap<object, number>();\n\nlet ROWS = 0;\n\n/**\n * One row: pressing, selection and its ARIA, read off the enclosing `Table`.\n *\n * `render` is abstract - a skin extends this and renders the row element, spreading `attrs`.\n */\nclass Row<T = any> extends Component {\n protected table = get(Table) as Table<T>;\n\n data: T = undefined as T;\n index = 0;\n\n get pressable(): boolean {\n return !!this.table.onPress;\n }\n\n get selected(): boolean {\n const { selected } = this.table;\n\n return selected !== undefined && this.data === selected;\n }\n\n /** For the row's element: `aria-current` when selected; with `onPress`, focusable and pressed by click, Enter and Space. */\n get attrs() {\n const { pressable, selected } = this;\n const current = selected ? ('true' as const) : undefined;\n\n if (!pressable) return { 'aria-current': current };\n\n return { tabIndex: 0, 'aria-current': current, onClick: this.click, onKeyDown: this.keyDown } as const;\n }\n\n press() {\n this.table.onPress!(this.data, this.index);\n }\n\n click(event: Table.Press) {\n if (!this.nested(event)) this.press();\n }\n\n keyDown(event: Table.Key) {\n if (event.target !== event.currentTarget || (event.key != 'Enter' && event.key != ' ')) return;\n\n event.preventDefault();\n this.press();\n }\n\n /** Whether a press landed on a control inside the row, which keeps the press. Defaults to the DOM's `closest`. */\n protected nested(event: Table.Press): boolean {\n const control = (event.target as Element).closest(CONTROL);\n\n return !!control && control !== event.currentTarget;\n }\n\n render(_props: { children: Component.Node }): Component.Node {\n return missing('Table.Row')();\n }\n}\n\n\n/**\n * Data table behavior without a look: columns declared as `Column` children, row keys, pressing and selection,\n * assembled from pieces.\n *\n * Every visible piece but `Empty` is a placeholder that throws when rendered - a skin assigns each one it renders. `Row` is\n * a Component class - one per row, so a change re-renders only the rows it touches; a skin extends it and spreads `attrs`.\n * `Head` writes `scope=\"col\"` itself and applies the column's `size`.\n */\nclass Table<T = any> extends Component {\n data: readonly T[] = [];\n\n /** Stable identity per row; defaults to the row object itself, else the index. */\n rowKey?: (row: T, index: number) => string | number = undefined;\n\n onPress?: (row: T, index: number) => void = undefined;\n\n /** Row to mark selected, compared by identity. */\n selected?: T = undefined;\n\n /** Shown in place of rows when `data` is empty. */\n empty: Component.Node = 'No rows';\n\n static Root: Table.Wrap = missing('Table.Root');\n static Header: Table.Wrap = missing('Table.Header');\n static Body: Table.Wrap = missing('Table.Body');\n static Head: HeadSlot = missing('Table.Head');\n static Row: typeof Row<any> = Row;\n static Cell: CellSlot = missing('Table.Cell');\n static Empty: Table.Fill = none;\n\n Root = kind(this).Root;\n Header = kind(this).Header;\n Body = kind(this).Body;\n Head: HeadSlot<T> = kind(this).Head;\n Row: Table.Line<T> = kind(this).Row;\n Cell: CellSlot<T> = kind(this).Cell;\n Empty = kind(this).Empty;\n\n /** A cell's content when its column has no `format`. */\n value(row: T, field: Field<T>): Component.Node {\n return row && typeof row == 'object' ? (row as any)[field.id] : null;\n }\n\n render(props: { children?: Component.Node }): Component.Node {\n const { data, rowKey, Head, Row, Cell } = this;\n const fields = resolve<T>(props.children);\n\n return (\n <this.Root>\n <this.Header>\n {fields.map((field) => {\n const Slot = field.Head || Head;\n\n return (\n <Slot key={field.id || field.index} field={field} className={field.className}>\n {field.name}\n </Slot>\n );\n })}\n </this.Header>\n <this.Body>\n {data.length == 0 && <this.Empty span={fields.length} />}\n {data.map((row, index) => (\n <Row key={rowKey ? rowKey(row, index) : identity(row, index)} data={row} index={index}>\n {fields.map((field) => {\n const Slot = field.Cell || Cell;\n\n return (\n <Slot key={field.id || field.index} field={field} data={row} className={field.className}>\n {field.format ? field.format(row, index) : this.value(row, field)}\n </Slot>\n );\n })}\n </Row>\n ))}\n </this.Body>\n </this.Root>\n );\n }\n}\n\nfunction identity(row: unknown, index: number): string | number {\n if (!row || typeof row != 'object') return index;\n\n let id = IDS.get(row);\n\n if (id === undefined) IDS.set(row, (id = ++ROWS));\n\n return `#${id}`;\n}\n\nfunction kind(table: Table) {\n return table.constructor as typeof Table;\n}\n\nfunction resolve<T>(children: Component.Node): Field<T>[] {\n const fields: Field<T>[] = [];\n\n for (const node of flatten(children)) {\n const type = typeOf(node);\n\n if (type !== Column && !(typeof type == 'function' && type.prototype instanceof Column)) continue;\n\n const props = propsOf(node) as Partial<Field<T>>;\n const name = props.name ?? '';\n\n fields.push({\n name,\n id: props.id || (typeof name == 'string' ? name.toLowerCase() : ''),\n className: props.className || '',\n index: fields.length,\n Cell: props.Cell,\n Head: props.Head,\n format: props.format,\n size: props.size\n });\n }\n\n return fields;\n}\n\nfunction flatten(children: Component.Node): Component.Node[] {\n const out: Component.Node[] = [];\n\n for (const node of childrenOf(children))\n if (typeOf(node) === Fragment) out.push(...flatten((propsOf(node) as any).children));\n else out.push(node);\n\n return out;\n}\n\nexport { Row, Table };\n"],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { Component, Model } from "@expressive/mvc";
2
+
3
+ //#region src/table/column.d.ts
4
+ interface CellProps<T = any> {
5
+ field: Field<T>;
6
+ data: T;
7
+ className?: string;
8
+ children?: Component.Node;
9
+ }
10
+ interface HeadProps<T = any> {
11
+ field: Field<T>;
12
+ className?: string;
13
+ children?: Component.Node;
14
+ }
15
+ type Slot<P> = ((props: P) => Component.Node) | (new (...args: any[]) => Model & {
16
+ render(props: P): Component.Node;
17
+ });
18
+ type CellSlot<T = any> = Slot<CellProps<T>>;
19
+ type HeadSlot<T = any> = Slot<HeadProps<T>>;
20
+ /**
21
+ * Declares a column of the enclosing `Table`. Renders nothing - the table reads its props.
22
+ *
23
+ * Without `format`, a cell shows the row's property named by `id`, which defaults to the lowercased `name`.
24
+ */
25
+ declare class Column<T = any> extends Component {
26
+ /** Header text; `false` for an empty header. */
27
+ name: string | false;
28
+ id: string;
29
+ className: string;
30
+ /** Replaces the table's `Cell` for this column. */
31
+ Cell?: CellSlot<T>;
32
+ /** Replaces the table's `Head` for this column. */
33
+ Head?: HeadSlot<T>;
34
+ /** Per-row content. */
35
+ format?: (row: T, index: number) => Component.Node;
36
+ /** Column width: a number in pixels, or any CSS length. Unset, the table sizes it from content. */
37
+ size?: number | string;
38
+ render(): Component.Node;
39
+ }
40
+ /** A Column element's props, resolved by its `Table`. */
41
+ interface Field<T = any> {
42
+ id: string;
43
+ name: string | false;
44
+ className: string;
45
+ index: number;
46
+ Cell?: CellSlot<T>;
47
+ Head?: HeadSlot<T>;
48
+ format?: (row: T, index: number) => Component.Node;
49
+ size?: number | string;
50
+ }
51
+ //#endregion
52
+ export { type CellProps, type CellSlot, Column, type Field, type HeadProps, type HeadSlot };
53
+ //# sourceMappingURL=column.d.ts.map
@@ -0,0 +1,29 @@
1
+ import { Component } from "@expressive/mvc";
2
+
3
+ //#region src/table/column.ts
4
+ /**
5
+ * Declares a column of the enclosing `Table`. Renders nothing - the table reads its props.
6
+ *
7
+ * Without `format`, a cell shows the row's property named by `id`, which defaults to the lowercased `name`.
8
+ */
9
+ var Column = class extends Component {
10
+ /** Header text; `false` for an empty header. */
11
+ name = "";
12
+ id = "";
13
+ className = "";
14
+ /** Replaces the table's `Cell` for this column. */
15
+ Cell = void 0;
16
+ /** Replaces the table's `Head` for this column. */
17
+ Head = void 0;
18
+ /** Per-row content. */
19
+ format = void 0;
20
+ /** Column width: a number in pixels, or any CSS length. Unset, the table sizes it from content. */
21
+ size = void 0;
22
+ render() {
23
+ return null;
24
+ }
25
+ };
26
+
27
+ //#endregion
28
+ export { Column };
29
+ //# sourceMappingURL=column.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column.js","names":[],"sources":["../../src/table/column.ts"],"sourcesContent":["import { Component, type Model } from '@expressive/mvc';\n\ninterface CellProps<T = any> {\n field: Field<T>;\n data: T;\n className?: string;\n children?: Component.Node;\n}\n\ninterface HeadProps<T = any> {\n field: Field<T>;\n className?: string;\n children?: Component.Node;\n}\n\ntype Slot<P> = ((props: P) => Component.Node) | (new (...args: any[]) => Model & { render(props: P): Component.Node });\n\ntype CellSlot<T = any> = Slot<CellProps<T>>;\ntype HeadSlot<T = any> = Slot<HeadProps<T>>;\n\n/**\n * Declares a column of the enclosing `Table`. Renders nothing - the table reads its props.\n *\n * Without `format`, a cell shows the row's property named by `id`, which defaults to the lowercased `name`.\n */\nclass Column<T = any> extends Component {\n /** Header text; `false` for an empty header. */\n name: string | false = '';\n id = '';\n className = '';\n\n /** Replaces the table's `Cell` for this column. */\n Cell?: CellSlot<T> = undefined;\n\n /** Replaces the table's `Head` for this column. */\n Head?: HeadSlot<T> = undefined;\n\n /** Per-row content. */\n format?: (row: T, index: number) => Component.Node = undefined;\n\n /** Column width: a number in pixels, or any CSS length. Unset, the table sizes it from content. */\n size?: number | string = undefined;\n\n render(): Component.Node {\n return null;\n }\n}\n\n/** A Column element's props, resolved by its `Table`. */\ninterface Field<T = any> {\n id: string;\n name: string | false;\n className: string;\n index: number;\n Cell?: CellSlot<T>;\n Head?: HeadSlot<T>;\n format?: (row: T, index: number) => Component.Node;\n size?: number | string;\n}\n\nexport { Column };\nexport type { CellProps, HeadProps, CellSlot, HeadSlot, Field };\n"],"mappings":";;;;;;;;AAyBA,IAAM,SAAN,cAA8B,UAAU;;CAEtC,OAAuB;CACvB,KAAK;CACL,YAAY;;CAGZ,OAAqB;;CAGrB,OAAqB;;CAGrB,SAAqD;;CAGrD,OAAyB;CAEzB,SAAyB;AACvB,SAAO"}
@@ -0,0 +1,41 @@
1
+ import { CellProps, CellSlot, Column, Field, HeadProps, HeadSlot } from "./column.js";
2
+ import { Row as Row$1, Table as Table$1 } from "./base.js";
3
+ import { Component } from "@expressive/mvc";
4
+
5
+ //#region src/table/table.d.ts
6
+ declare namespace Table {
7
+ type RowProps<T = any> = Table$1.RowProps<T>;
8
+ }
9
+ declare class Row<T = any> extends Row$1<T> {
10
+ render({
11
+ children
12
+ }: {
13
+ children: Component.Node;
14
+ }): Component.Node;
15
+ }
16
+ /**
17
+ * Data table whose columns are declared as `Column` children.
18
+ *
19
+ * Pieces - `Root`, `Header`, `Body`, `Head`, `Row`, `Cell`, `Empty` - are function components reading `Table.get()`,
20
+ * each styled on its own; pass one as a prop or assign it in a subclass to replace it. Stock pieces are statics. A
21
+ * `Column` can also bring its own `Head` or `Cell`. With `onPress`, rows are focusable and respond to click, Enter
22
+ * and Space; `selected` marks one.
23
+ *
24
+ * @example
25
+ * <Table data={people} rowKey={(person) => person.id}>
26
+ * <Column name="Name" />
27
+ * <Column name="Age" format={(person) => `${person.age} yrs`} />
28
+ * </Table>
29
+ */
30
+ declare class Table<T = any> extends Table$1<T> {
31
+ static Root: Table$1.Wrap;
32
+ static Header: Table$1.Wrap;
33
+ static Body: Table$1.Wrap;
34
+ static Head: HeadSlot;
35
+ static Row: typeof Row<any>;
36
+ static Cell: CellSlot;
37
+ static Empty: Table$1.Fill;
38
+ }
39
+ //#endregion
40
+ export { Table };
41
+ //# sourceMappingURL=table.d.ts.map