@sylwellsoftware/fray 0.2.0 → 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 (46) hide show
  1. package/README.md +79 -11
  2. package/dist/Components/Placeholder.d.ts +1 -1
  3. package/dist/Components/Placeholder.d.ts.map +1 -1
  4. package/dist/Components/controlUtils.d.ts.map +1 -1
  5. package/dist/Components/data/filterState.d.ts +38 -0
  6. package/dist/Components/data/filterState.d.ts.map +1 -0
  7. package/dist/Components/data/listview/listview.d.ts +16 -5
  8. package/dist/Components/data/listview/listview.d.ts.map +1 -1
  9. package/dist/Components/data/selectionhandler.d.ts +24 -5
  10. package/dist/Components/data/selectionhandler.d.ts.map +1 -1
  11. package/dist/Components/data/table/DataTable.d.ts +36 -30
  12. package/dist/Components/data/table/DataTable.d.ts.map +1 -1
  13. package/dist/Components/data/table/FilterPanel.d.ts +8 -1
  14. package/dist/Components/data/table/FilterPanel.d.ts.map +1 -1
  15. package/dist/Components/data/table/TableHeaderCell.d.ts.map +1 -1
  16. package/dist/Components/data/table/tableDataSource.d.ts +49 -0
  17. package/dist/Components/data/table/tableDataSource.d.ts.map +1 -0
  18. package/dist/Components/data/table/tableQuery.d.ts +6 -2
  19. package/dist/Components/data/table/tableQuery.d.ts.map +1 -1
  20. package/dist/Components/data/treeview/treeModel.d.ts +23 -0
  21. package/dist/Components/data/treeview/treeModel.d.ts.map +1 -0
  22. package/dist/Components/data/treeview/treeview.d.ts +1 -1
  23. package/dist/Components/data/treeview/treeview.d.ts.map +1 -1
  24. package/dist/Components/dialog/dialog.d.ts +1 -1
  25. package/dist/Components/dialog/dialog.d.ts.map +1 -1
  26. package/dist/Components/lineinputs/checkbox/Checkbox.d.ts +1 -1
  27. package/dist/Components/lineinputs/checkbox/Checkbox.d.ts.map +1 -1
  28. package/dist/Components/lineinputs/checkbox/QuadCheckbox.d.ts +2 -2
  29. package/dist/Components/lineinputs/checkbox/QuadCheckbox.d.ts.map +1 -1
  30. package/dist/Components/lineinputs/checkbox/TriCheckbox.d.ts +2 -2
  31. package/dist/Components/lineinputs/checkbox/TriCheckbox.d.ts.map +1 -1
  32. package/dist/index.d.ts +14 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +2676 -726
  35. package/dist/index.js.map +1 -1
  36. package/dist/util/filterMode.d.ts +6 -4
  37. package/dist/util/filterMode.d.ts.map +1 -1
  38. package/package.json +4 -9
  39. package/styles/structural.css +9 -3
  40. package/EXPERIMENTAL.md +0 -75
  41. package/dist/button-CqDGmkBt.js +0 -212
  42. package/dist/button-CqDGmkBt.js.map +0 -1
  43. package/dist/experimental.d.ts +0 -16
  44. package/dist/experimental.d.ts.map +0 -1
  45. package/dist/experimental.js +0 -1399
  46. package/dist/experimental.js.map +0 -1
@@ -1,13 +1,15 @@
1
1
  /** Represents the filter mode for a query. */
2
2
  export declare const FilterMode: {
3
3
  /** Deny mode: Excludes items that match the filter. */
4
- readonly Deny: "!";
4
+ readonly Deny: "deny";
5
5
  /** Require mode: Includes only items that match the filter. */
6
- readonly Require: "_";
6
+ readonly Require: "require";
7
7
  /** Prefer mode: If there are any filter options that are set to Prefer, at least one of the preferred filter options must match. Otherwise, it is treated as Neutral. */
8
- readonly Prefer: "";
8
+ readonly Prefer: "prefer";
9
9
  /** Neutral mode: Does not affect the inclusion or exclusion of items. */
10
- readonly Neutral: "";
10
+ readonly Neutral: "neutral";
11
11
  };
12
12
  export type FilterModeValue = typeof FilterMode[keyof typeof FilterMode];
13
+ /** Return whether a value is one of Fray's semantic filter modes. */
14
+ export declare function isFilterMode(value: unknown): value is FilterModeValue;
13
15
  //# sourceMappingURL=filterMode.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"filterMode.d.ts","sourceRoot":"","sources":["../../src/util/filterMode.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,eAAO,MAAM,UAAU;IACnB,uDAAuD;;IAEvD,+DAA+D;;IAE/D,yKAAyK;;IAEzK,yEAAyE;;CAEnE,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG,OAAO,UAAU,CAAC,MAAM,OAAO,UAAU,CAAC,CAAA"}
1
+ {"version":3,"file":"filterMode.d.ts","sourceRoot":"","sources":["../../src/util/filterMode.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,eAAO,MAAM,UAAU;IACnB,uDAAuD;;IAEvD,+DAA+D;;IAE/D,yKAAyK;;IAEzK,yEAAyE;;CAEnE,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG,OAAO,UAAU,CAAC,MAAM,OAAO,UAAU,CAAC,CAAA;AAExE,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CAErE"}
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "type": "module",
3
3
  "name": "@sylwellsoftware/fray",
4
4
  "private": false,
5
- "version": "0.2.0",
6
- "description": "Experimental browser-only TypeScript component runtime, JSX controls, and semantic themes.",
5
+ "version": "0.3.0",
6
+ "description": "Browser-only TypeScript component runtime, JSX controls, and semantic themes.",
7
7
  "license": "Apache-2.0",
8
8
  "author": {
9
9
  "name": "Sylwell Software",
@@ -36,10 +36,6 @@
36
36
  "types": "./dist/index.d.ts",
37
37
  "import": "./dist/index.js"
38
38
  },
39
- "./experimental": {
40
- "types": "./dist/experimental.d.ts",
41
- "import": "./dist/experimental.js"
42
- },
43
39
  "./jsx-runtime": {
44
40
  "types": "./dist/jsx-runtime.d.ts",
45
41
  "import": "./dist/jsx-runtime.js"
@@ -59,7 +55,6 @@
59
55
  "styles",
60
56
  "themes",
61
57
  "colors",
62
- "EXPERIMENTAL.md",
63
58
  "LICENSE",
64
59
  "NOTICE"
65
60
  ],
@@ -69,11 +64,11 @@
69
64
  "./themes/**/*.css"
70
65
  ],
71
66
  "peerDependencies": {
72
- "@sylwellsoftware/glue": "^0.2.0"
67
+ "@sylwellsoftware/glue": "^0.3.0"
73
68
  },
74
69
  "devDependencies": {
75
70
  "vite": "^6.3.5",
76
- "@sylwellsoftware/glue": "^0.2.0"
71
+ "@sylwellsoftware/glue": "^0.3.0"
77
72
  },
78
73
  "engines": {
79
74
  "node": ">=22",
@@ -323,6 +323,11 @@ fray-data-table {
323
323
  border-collapse: collapse;
324
324
  }
325
325
 
326
+ fray-data-table thead:has([data-fray-component="filter-panel"]) {
327
+ position: relative;
328
+ z-index: 1100;
329
+ }
330
+
326
331
  fray-data-table th,
327
332
  fray-data-table td {
328
333
  padding: var(--ui-padding-v) var(--ui-padding-h);
@@ -408,9 +413,9 @@ th[data-fray-component="table-header-cell"] {
408
413
  }
409
414
 
410
415
  fray-filter-panel {
411
- position: absolute;
412
- z-index: 1000;
413
- inset-block-start: 100%;
416
+ position: fixed;
417
+ z-index: 1100;
418
+ inset-block-start: 0;
414
419
  inset-inline-end: 0;
415
420
  display: flex;
416
421
  min-width: 12rem;
@@ -422,6 +427,7 @@ fray-filter-panel {
422
427
  border: var(--panel-border);
423
428
  border-radius: var(--panel-radius);
424
429
  box-shadow: var(--panel-shadow);
430
+ overflow-y: auto;
425
431
  }
426
432
 
427
433
  div[data-fray-component="description-item"] {
package/EXPERIMENTAL.md DELETED
@@ -1,75 +0,0 @@
1
- # Fray experimental data APIs
2
-
3
- Everything imported from `@sylwellsoftware/fray/experimental` is outside Fray's stable
4
- alpha compatibility surface. It may change in any `0.x` release without a
5
- deprecation window. The stable package root does not export these symbols.
6
-
7
- `TreeView` is a controlled, single-select ARIA tree. Stable node keys reconcile
8
- selection and expansion across data replacement. Arrow keys navigate and
9
- expand/collapse, Home/End jump, Enter/Space select, and printable keys perform
10
- type-ahead. `TreeItem` supplies an optional declarative node form. The initial
11
- contract does not include virtualization, multi-selection, editing, or drag
12
- reordering.
13
-
14
- `Dialog` wraps the native modal element with a controlled boolean emitter,
15
- label/description relationships, cancel handling, initial focus, focus
16
- restoration, and deterministic cleanup. Applications provide actions and own
17
- all async work; the dialog does not infer promise or confirmation policy.
18
-
19
- ## Current behavior
20
-
21
- `ListView` and `DataTable` use stable item/row keys and expose their selected
22
- items through writable emitters. Single selection replaces the prior item.
23
- Multi-selection supports Control/Command toggles, Shift ranges, primary-button
24
- drag ranges, arrow/Home/End focus movement, and Space/Enter selection. A data
25
- refresh reconciles selected keys to the new row objects.
26
-
27
- `DataTable` requires an explicit `mode`:
28
-
29
- - `local` accepts an array or emitter, and performs sorting/filtering in the
30
- browser;
31
- - `remote` accepts a query emitter/handler or REST configuration, and sends
32
- sort/filter arguments through the documented table serializer.
33
-
34
- Filter state lives in the table's `filtersEmitter`, so opening a panel,
35
- changing a filter, rerendering, and refreshing data do not reset it. Remote
36
- tables distinguish these states:
37
-
38
- - initial/loading with no rows: status plus placeholder rows;
39
- - loading with retained rows: busy status plus the partial/previous rows;
40
- - ready with no rows: the configured empty message;
41
- - error with retained rows: an alert plus those rows;
42
- - error with no rows: an alert without a misleading empty message;
43
- - retryable query: a native Retry button that calls `query.retry()`.
44
-
45
- Pagination is not built in. A remote query may implement pagination arguments,
46
- but Fray does not currently supply pagination controls or a page model.
47
-
48
- ## Measured alpha boundary
49
-
50
- The alpha regression boundary is **1,000 rows with four to six simple columns
51
- on a modern desktop browser**. Larger datasets, expensive custom cell
52
- renderers, and mobile devices are not covered; paginate or filter them before
53
- rendering.
54
-
55
- The browser fixture measures a 1,000-row/four-column local table using stable
56
- keys. It times initial DOM creation, a full data refresh, numeric sorting, a
57
- filter that retains 500 rows, and one selection update. On the 2026-09-01 local
58
- arm64 macOS verification host with Playwright 1.62.1, the results were:
59
-
60
- | Engine | Initial | Rerender | Sort | Filter | Selection |
61
- | --- | ---: | ---: | ---: | ---: | ---: |
62
- | Chromium | 19.0 ms | 9.3 ms | 9.2 ms | 6.0 ms | 20.9 ms |
63
- | Firefox | 62.0 ms | 16.0 ms | 14.0 ms | 11.0 ms | 32.0 ms |
64
- | WebKit | 18.0 ms | 12.0 ms | 22.0 ms | 6.0 ms | 4.0 ms |
65
-
66
- These are synchronous headless-browser regression measurements, not a promise
67
- of end-to-end frame or device performance. The automated budget allows two
68
- seconds for initial creation and one second for each subsequent operation to
69
- remain robust on slower verification hosts while still catching a material
70
- regression.
71
-
72
- Virtualization is deliberately deferred: the measured boundary does not
73
- justify its lifecycle, focus, and accessibility complexity. Revisit it only
74
- with a demonstrated consumer above 1,000 rows and browser measurements showing
75
- that server-side pagination/filtering is insufficient.
@@ -1,212 +0,0 @@
1
- var N = Object.defineProperty;
2
- var I = (e, t, a) => t in e ? N(e, t, { enumerable: !0, configurable: !0, writable: !0, value: a }) : e[t] = a;
3
- var n = (e, t, a) => I(e, typeof t != "symbol" ? t + "" : t, a);
4
- import { C as k, j as y, c as x, a as T } from "./jsx-dev-runtime-DukiDpV9.js";
5
- import { Emitter as V } from "@sylwellsoftware/glue";
6
- let j = 1;
7
- function B(e, t) {
8
- return t != null && String(t).length > 0 ? String(t) : `fray-${e}-${j++}`;
9
- }
10
- function q(e, t, a, i) {
11
- if (t.valueEmitter != null)
12
- return R(t.valueEmitter, "valueEmitter"), t.valueEmitter;
13
- const s = t.defaultValue ?? t.value ?? t.initialValue ?? a, o = { owner: e, purpose: i };
14
- return new V(s, o);
15
- }
16
- function R(e, t = "emitter") {
17
- if (e == null || typeof e != "object" && typeof e != "function" || typeof Reflect.get(e, "get") != "function" || typeof Reflect.get(e, "set") != "function" || typeof Reflect.get(e, "subscribe") != "function")
18
- throw new TypeError(`${t} must be an emitter`);
19
- }
20
- function w(e) {
21
- return e.className ?? e.class ?? "";
22
- }
23
- function E(e, ...t) {
24
- if (e != null) {
25
- if (typeof e != "function") throw new TypeError("Control callback must be a function");
26
- e(...t);
27
- }
28
- }
29
- function F(e, t = "options") {
30
- if (!Array.isArray(e)) throw new TypeError(`${t} must be an array`);
31
- }
32
- function $(e) {
33
- return e === "" ? "prefer" : e === "!" ? "deny" : e === "_" ? "require" : e === "☐" ? "neutral" : String(e);
34
- }
35
- const b = {
36
- /** Deny mode: Excludes items that match the filter. */
37
- Deny: "!",
38
- /** Require mode: Includes only items that match the filter. */
39
- Require: "_",
40
- /** Prefer mode: If there are any filter options that are set to Prefer, at least one of the preferred filter options must match. Otherwise, it is treated as Neutral. */
41
- Prefer: "",
42
- /** Neutral mode: Does not affect the inclusion or exclusion of items. */
43
- Neutral: "☐"
44
- };
45
- class u extends k {
46
- constructor(a = {}) {
47
- super(a);
48
- n(this, "symbols");
49
- n(this, "valueEmitter");
50
- n(this, "semanticStateEmitter");
51
- const i = this.constructor;
52
- this.symbols = a.symbols ?? i.symbols, D(this.symbols);
53
- const s = a.initialSemanticState ?? i.defaultSemanticState ?? this.symbols[0][1], o = { ...a };
54
- o.defaultValue == null && a.initialSemanticState != null && (o.defaultValue = a.initialSemanticState), this.valueEmitter = q(
55
- this,
56
- o,
57
- s,
58
- "checkbox semantic state"
59
- ), this.semanticStateEmitter = this.valueEmitter;
60
- }
61
- initialize() {
62
- this.watch(this.valueEmitter);
63
- }
64
- cycleState(a = 1, i = null) {
65
- if (this.props.disabled) return;
66
- const s = this.symbols.findIndex(([, d]) => Object.is(d, this.valueEmitter.get())), c = ((s < 0 ? 0 : s) + a + this.symbols.length) % this.symbols.length, l = this.symbols[c][1];
67
- this.valueEmitter.set(l, "checkbox state changed"), E(this.props.onChange, l, i);
68
- }
69
- render() {
70
- const {
71
- label: a = this.props.value ?? "Option",
72
- disabled: i = !1,
73
- required: s = !1,
74
- name: o,
75
- value: c
76
- } = this.props, l = this.valueEmitter.get(), [d] = this.symbols.find(([, r]) => Object.is(r, l)) ?? ["?", l], f = $(l), m = l === b.Prefer || l === b.Require, h = this.Host;
77
- return /* @__PURE__ */ y(
78
- h,
79
- {
80
- className: w(this.props) || null,
81
- "data-disabled": i ? "" : null,
82
- "data-required": s ? "" : null,
83
- "data-state": f,
84
- children: /* @__PURE__ */ T(
85
- "button",
86
- {
87
- type: "button",
88
- role: "checkbox",
89
- disabled: i,
90
- name: o,
91
- value: c == null ? void 0 : String(c),
92
- "data-part": "control",
93
- "aria-checked": m ? "true" : "false",
94
- "aria-required": s ? "true" : null,
95
- "aria-label": `${a}: ${f}`,
96
- onClick: (r) => this.cycleState(1, r),
97
- onKeyDown: (r) => {
98
- r.key === "ArrowRight" || r.key === "ArrowDown" ? (r.preventDefault(), this.cycleState(1, r)) : (r.key === "ArrowLeft" || r.key === "ArrowUp") && (r.preventDefault(), this.cycleState(-1, r));
99
- },
100
- children: [
101
- /* @__PURE__ */ y("span", { "data-part": "symbol", "aria-hidden": "true", children: d }),
102
- /* @__PURE__ */ y("span", { "data-part": "label", children: a })
103
- ]
104
- }
105
- )
106
- }
107
- );
108
- }
109
- }
110
- n(u, "symbols", [
111
- ["☐", b.Neutral],
112
- ["✓", b.Prefer]
113
- ]), n(u, "defaultSemanticState", b.Neutral), n(u, "hostName", "checkbox"), n(u, "standaloneHostName", "check-box"), n(u, "baseStyles", [
114
- ["&", ["inputline"]],
115
- ['& > [data-part="control"]', ["input", "inputline"]],
116
- ["&[data-disabled]", ["disabled"]]
117
- ]), n(u, "css", x`
118
- & > [data-part="control"] {
119
- display: inline-flex;
120
- align-items: center;
121
- gap: 0.35em;
122
- width: auto;
123
- font-family: inherit;
124
- }
125
-
126
- & [data-part="symbol"] {
127
- display: inline-grid;
128
- width: 1em;
129
- height: 1em;
130
- line-height: 1;
131
- place-items: center;
132
- color: var(--fray-checkbox-symbol-color, currentColor);
133
- background: var(--fray-checkbox-box-background, transparent);
134
- border: var(--fray-checkbox-box-border, var(--cbx-o-border));
135
- border-radius: var(--cbx-border-radius, var(--fray-radius-sm));
136
- }
137
-
138
- & [data-part="control"][aria-checked="true"] [data-part="symbol"] {
139
- background: var(
140
- --fray-checkbox-box-background-checked,
141
- var(--fray-selection-background)
142
- );
143
- }
144
- `);
145
- function D(e) {
146
- if (!Array.isArray(e) || e.length === 0)
147
- throw new TypeError("Checkbox symbols must be a non-empty tuple array");
148
- for (const t of e)
149
- if (!Array.isArray(t) || t.length < 2)
150
- throw new TypeError("Checkbox symbols must be [symbol, state] tuples");
151
- }
152
- class S extends k {
153
- constructor(t = {}) {
154
- if (super(t), t.onClick != null && typeof t.onClick != "function")
155
- throw new TypeError("Button onClick must be a function");
156
- }
157
- render() {
158
- const {
159
- children: t = [],
160
- label: a,
161
- type: i = "button",
162
- disabled: s = !1,
163
- pressed: o,
164
- busy: c = !1,
165
- busyLabel: l,
166
- id: d,
167
- name: f,
168
- value: m,
169
- title: h,
170
- ariaLabel: r,
171
- onClick: v
172
- } = this.props, p = (Array.isArray(t) ? t.length > 0 : t != null && typeof t != "boolean") ? t : a ?? "", C = c ? l ?? p : p, g = s || c;
173
- return /* @__PURE__ */ y(
174
- "button",
175
- {
176
- id: d,
177
- name: f,
178
- value: m == null ? void 0 : String(m),
179
- title: h,
180
- type: i,
181
- disabled: g,
182
- className: w(this.props) || void 0,
183
- "data-fray-component": "button",
184
- "aria-label": r,
185
- "aria-pressed": o == null ? null : String(!!o),
186
- "aria-busy": c ? "true" : null,
187
- onClick: (A) => {
188
- g || E(v, A);
189
- },
190
- children: C
191
- }
192
- );
193
- }
194
- }
195
- n(S, "baseStyles", [
196
- ['button[data-fray-component="button"]', ["uiline", "button"]]
197
- ]), n(S, "css", x`
198
- button[data-fray-component="button"] {
199
- font-family: inherit;
200
- }
201
- `);
202
- export {
203
- S as B,
204
- u as C,
205
- b as F,
206
- q as a,
207
- B as b,
208
- w as c,
209
- F as d,
210
- E as i
211
- };
212
- //# sourceMappingURL=button-CqDGmkBt.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"button-CqDGmkBt.js","sources":["../src/Components/controlUtils.ts","../src/util/filterMode.ts","../src/Components/lineinputs/checkbox/Checkbox.tsx","../src/Components/menu/button.tsx"],"sourcesContent":["import {Emitter} from '@sylwellsoftware/glue'\nimport type {EmitterOptions, ReadableEmitter} from '@sylwellsoftware/glue'\n\nimport type {Component, ComponentProps} from './component.js'\n\nexport interface ValueEmitter<TValue> extends ReadableEmitter<TValue, unknown> {\n set(value: TValue, eventOrCause?: unknown): boolean\n}\n\nexport interface ValueControlProps<TValue> extends ComponentProps {\n valueEmitter?: ValueEmitter<TValue>\n value?: TValue\n defaultValue?: TValue\n initialValue?: TValue\n}\n\nlet nextControlId = 1\n\nexport function controlId(prefix: string, provided?: string | number | null): string {\n if (provided != null && String(provided).length > 0) return String(provided)\n return `fray-${prefix}-${nextControlId++}`\n}\n\nexport function createValueEmitter<TValue>(\n component: Component,\n props: ValueControlProps<TValue>,\n fallback: TValue,\n purpose: string,\n): ValueEmitter<TValue> {\n if (props.valueEmitter != null) {\n assertEmitter<TValue>(props.valueEmitter, 'valueEmitter')\n return props.valueEmitter\n }\n const initialValue = props.defaultValue\n ?? props.value\n ?? props.initialValue\n ?? fallback\n const options: EmitterOptions<TValue> = {owner: component, purpose}\n return new Emitter(initialValue, options)\n}\n\nexport function assertEmitter<TValue = unknown>(\n value: unknown,\n name = 'emitter',\n): asserts value is ValueEmitter<TValue> {\n if (value == null\n || (typeof value !== 'object' && typeof value !== 'function')\n || typeof Reflect.get(value, 'get') !== 'function'\n || typeof Reflect.get(value, 'set') !== 'function'\n || typeof Reflect.get(value, 'subscribe') !== 'function') {\n throw new TypeError(`${name} must be an emitter`)\n }\n}\n\nexport function classNames(...values: unknown[]): string {\n return values\n .flatMap((value) => typeof value === 'string' ? value.split(/\\s+/) : [])\n .filter(Boolean)\n .join(' ')\n}\n\nexport function componentClass(props: Pick<ComponentProps, 'class' | 'className'>): string {\n return props.className ?? props.class ?? ''\n}\n\nexport function invoke<TArguments extends unknown[]>(\n callback: ((...args: TArguments) => void) | null | undefined,\n ...args: TArguments\n): void {\n if (callback == null) return\n if (typeof callback !== 'function') throw new TypeError('Control callback must be a function')\n callback(...args)\n}\n\nexport function assertOptions<TOption>(\n options: unknown,\n name = 'options',\n): asserts options is TOption[] {\n if (!Array.isArray(options)) throw new TypeError(`${name} must be an array`)\n}\n\nexport function describeState(value: unknown): string {\n if (value === '') return 'prefer'\n if (value === '!') return 'deny'\n if (value === '_') return 'require'\n if (value === '☐') return 'neutral'\n return String(value)\n}\n","/** Represents the filter mode for a query. */\nexport const FilterMode = {\n /** Deny mode: Excludes items that match the filter. */\n Deny: '!',\n /** Require mode: Includes only items that match the filter. */\n Require: '_',\n /** Prefer mode: If there are any filter options that are set to Prefer, at least one of the preferred filter options must match. Otherwise, it is treated as Neutral. */\n Prefer: '',\n /** Neutral mode: Does not affect the inclusion or exclusion of items. */\n Neutral: '☐',\n} as const\n\nexport type FilterModeValue = typeof FilterMode[keyof typeof FilterMode]\n","import {Component, css} from '../../component.js'\nimport type {ComponentProps, FrayChild} from '../../component.js'\nimport {\n componentClass,\n createValueEmitter,\n describeState,\n invoke,\n} from '../../controlUtils.js'\nimport type {ValueControlProps, ValueEmitter} from '../../controlUtils.js'\nimport {FilterMode} from '../../../util/filterMode.js'\nimport type {FilterModeValue} from '../../../util/filterMode.js'\n\nexport type CheckboxValue = string | number\nexport type CheckboxSymbol<TValue extends CheckboxValue = FilterModeValue> = readonly [\n symbol: FrayChild,\n value: TValue,\n]\n\nexport interface CheckboxProps<TValue extends CheckboxValue = FilterModeValue>\n extends ValueControlProps<TValue> {\n symbols?: readonly CheckboxSymbol<TValue>[]\n initialSemanticState?: TValue\n label?: FrayChild\n disabled?: boolean\n required?: boolean\n name?: string\n onChange?: (value: TValue, event: Event | null) => void\n}\n\n/** Keyboard-operable semantic state cycler. */\nexport class Checkbox<TValue extends CheckboxValue = FilterModeValue>\n extends Component<CheckboxProps<TValue>> {\n static symbols: readonly CheckboxSymbol<FilterModeValue>[] = [\n ['☐', FilterMode.Neutral],\n ['✓', FilterMode.Prefer],\n ]\n static defaultSemanticState = FilterMode.Neutral\n\n readonly symbols: readonly CheckboxSymbol<TValue>[]\n readonly valueEmitter: ValueEmitter<TValue>\n readonly semanticStateEmitter: ValueEmitter<TValue>\n\n constructor(props: CheckboxProps<TValue> = {}) {\n super(props)\n const componentType = this.constructor as typeof Checkbox\n // Static members cannot carry the instance's generic state parameter;\n // subclasses validate the tuple values before this boundary is used.\n this.symbols = props.symbols\n ?? componentType.symbols as unknown as readonly CheckboxSymbol<TValue>[]\n validateSymbols(this.symbols)\n const fallback = props.initialSemanticState\n ?? componentType.defaultSemanticState as TValue\n ?? this.symbols[0]![1]\n const emitterProps: CheckboxProps<TValue> = {...props}\n if (emitterProps.defaultValue == null && props.initialSemanticState != null) {\n emitterProps.defaultValue = props.initialSemanticState\n }\n this.valueEmitter = createValueEmitter<TValue>(this, emitterProps, fallback,\n 'checkbox semantic state')\n // Compatibility alias used only by the experimental filter implementation.\n this.semanticStateEmitter = this.valueEmitter\n }\n\n initialize(): void {\n this.watch(this.valueEmitter)\n }\n\n cycleState(direction = 1, event: Event | null = null): void {\n if (this.props.disabled) return\n const currentIndex = this.symbols.findIndex(([, state]) =>\n Object.is(state, this.valueEmitter.get()))\n const baseIndex = currentIndex < 0 ? 0 : currentIndex\n const nextIndex = (baseIndex + direction + this.symbols.length) % this.symbols.length\n const nextValue = this.symbols[nextIndex]![1]\n this.valueEmitter.set(nextValue, 'checkbox state changed')\n invoke(this.props.onChange, nextValue, event)\n }\n\n render(): FrayChild {\n const {\n label = this.props.value ?? 'Option',\n disabled = false,\n required = false,\n name,\n value,\n } = this.props\n const semanticState = this.valueEmitter.get()\n const [symbol] = this.symbols.find(([, state]) => Object.is(state, semanticState))\n ?? ['?', semanticState]\n const stateName = describeState(semanticState)\n const checked = semanticState === FilterMode.Prefer\n || semanticState === FilterMode.Require\n\n const Host = this.Host\n return <Host\n className={componentClass(this.props) || null}\n data-disabled={disabled ? '' : null}\n data-required={required ? '' : null}\n data-state={stateName}\n >\n <button\n type=\"button\"\n role=\"checkbox\"\n disabled={disabled}\n name={name}\n value={value == null ? undefined : String(value)}\n data-part=\"control\"\n aria-checked={checked ? 'true' : 'false'}\n aria-required={required ? 'true' : null}\n aria-label={`${label}: ${stateName}`}\n onClick={(event: MouseEvent) => this.cycleState(1, event)}\n onKeyDown={(event: KeyboardEvent) => {\n if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {\n event.preventDefault()\n this.cycleState(1, event)\n } else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {\n event.preventDefault()\n this.cycleState(-1, event)\n }\n }}\n >\n <span data-part=\"symbol\" aria-hidden=\"true\">{symbol}</span>\n <span data-part=\"label\">{label}</span>\n </button>\n </Host>\n }\n\n static override hostName = 'checkbox'\n static override standaloneHostName = 'check-box'\n\n static baseStyles = [\n ['&', ['inputline']],\n ['& > [data-part=\"control\"]', ['input', 'inputline']],\n ['&[data-disabled]', ['disabled']],\n ]\n\n static css = css`\n & > [data-part=\"control\"] {\n display: inline-flex;\n align-items: center;\n gap: 0.35em;\n width: auto;\n font-family: inherit;\n }\n\n & [data-part=\"symbol\"] {\n display: inline-grid;\n width: 1em;\n height: 1em;\n line-height: 1;\n place-items: center;\n color: var(--fray-checkbox-symbol-color, currentColor);\n background: var(--fray-checkbox-box-background, transparent);\n border: var(--fray-checkbox-box-border, var(--cbx-o-border));\n border-radius: var(--cbx-border-radius, var(--fray-radius-sm));\n }\n\n & [data-part=\"control\"][aria-checked=\"true\"] [data-part=\"symbol\"] {\n background: var(\n --fray-checkbox-box-background-checked,\n var(--fray-selection-background)\n );\n }\n `\n}\n\nfunction validateSymbols<TValue extends CheckboxValue>(\n symbols: unknown,\n): asserts symbols is readonly CheckboxSymbol<TValue>[] {\n if (!Array.isArray(symbols) || symbols.length === 0) {\n throw new TypeError('Checkbox symbols must be a non-empty tuple array')\n }\n for (const tuple of symbols) {\n if (!Array.isArray(tuple) || tuple.length < 2) {\n throw new TypeError('Checkbox symbols must be [symbol, state] tuples')\n }\n }\n}\n","import {Component, css} from '../component.js'\nimport type {ComponentProps, FrayChild} from '../component.js'\nimport {componentClass, invoke} from '../controlUtils.js'\n\nexport interface ButtonProps extends ComponentProps {\n label?: FrayChild\n type?: 'button' | 'reset' | 'submit'\n disabled?: boolean\n pressed?: boolean\n busy?: boolean\n busyLabel?: FrayChild\n id?: string\n name?: string\n value?: string | number\n title?: string\n ariaLabel?: string\n onClick?: (event: MouseEvent) => void\n}\n\n/** Native actionable button primitive. */\nexport class Button extends Component<ButtonProps> {\n constructor(props: ButtonProps = {}) {\n super(props)\n if (props.onClick != null && typeof props.onClick !== 'function') {\n throw new TypeError('Button onClick must be a function')\n }\n }\n\n render(): FrayChild {\n const {\n children = [],\n label,\n type = 'button',\n disabled = false,\n pressed,\n busy = false,\n busyLabel,\n id,\n name,\n value,\n title,\n ariaLabel,\n onClick,\n } = this.props\n const hasChildren = Array.isArray(children)\n ? children.length > 0\n : children != null && typeof children !== 'boolean'\n const normalContent = hasChildren ? children : (label ?? '')\n const content = busy ? (busyLabel ?? normalContent) : normalContent\n const unavailable = disabled || busy\n\n return <button\n id={id}\n name={name}\n value={value == null ? undefined : String(value)}\n title={title}\n type={type}\n disabled={unavailable}\n className={componentClass(this.props) || undefined}\n data-fray-component=\"button\"\n aria-label={ariaLabel}\n aria-pressed={pressed == null ? null : String(Boolean(pressed))}\n aria-busy={busy ? 'true' : null}\n onClick={(event: MouseEvent) => {\n if (!unavailable) invoke(onClick, event)\n }}\n >{content}</button>\n }\n\n static baseStyles = [\n ['button[data-fray-component=\"button\"]', ['uiline', 'button']],\n ]\n\n static css = css`\n button[data-fray-component=\"button\"] {\n font-family: inherit;\n }\n `\n}\n"],"names":["nextControlId","controlId","prefix","provided","createValueEmitter","component","props","fallback","purpose","assertEmitter","initialValue","options","Emitter","value","name","componentClass","invoke","callback","args","assertOptions","describeState","FilterMode","Checkbox","Component","__publicField","componentType","validateSymbols","emitterProps","direction","event","currentIndex","state","nextIndex","nextValue","label","disabled","required","semanticState","symbol","stateName","checked","Host","jsx","jsxs","css","symbols","tuple","Button","children","type","pressed","busy","busyLabel","id","title","ariaLabel","onClick","normalContent","content","unavailable"],"mappings":"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"}
@@ -1,16 +0,0 @@
1
- /**
2
- * Experimental data APIs. These exports may change in any prerelease and are
3
- * intentionally excluded from the stable package barrel.
4
- */
5
- export * from './Components/Placeholder.js';
6
- export * from './Components/data/listview/listview.js';
7
- export * from './Components/data/selectionhandler.js';
8
- export * from './Components/data/table/DataTable.js';
9
- export * from './Components/data/table/FilterPanel.js';
10
- export * from './Components/data/table/TableHeader.js';
11
- export * from './Components/data/table/TableHeaderCell.js';
12
- export * from './Components/data/table/tableQuery.js';
13
- export * from './Components/data/treeview/treeitem.js';
14
- export * from './Components/data/treeview/treeview.js';
15
- export * from './Components/dialog/dialog.js';
16
- //# sourceMappingURL=experimental.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"experimental.d.ts","sourceRoot":"","sources":["../src/experimental.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wCAAwC,CAAA;AACtD,cAAc,uCAAuC,CAAA;AACrD,cAAc,sCAAsC,CAAA;AACpD,cAAc,wCAAwC,CAAA;AACtD,cAAc,wCAAwC,CAAA;AACtD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,uCAAuC,CAAA;AACrD,cAAc,wCAAwC,CAAA;AACtD,cAAc,wCAAwC,CAAA;AACtD,cAAc,+BAA+B,CAAA"}