@surflane/ui 0.1.0 → 0.2.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 (85) hide show
  1. package/README.md +8 -8
  2. package/dist/advanced-forms.d.ts +2 -2
  3. package/dist/advanced-forms.js +39 -39
  4. package/dist/app-shell.d.ts +1 -1
  5. package/dist/app-shell.js +11 -11
  6. package/dist/button.d.ts +5 -5
  7. package/dist/button.js +12 -12
  8. package/dist/chart.d.ts +3 -3
  9. package/dist/chart.js +36 -34
  10. package/dist/commands.d.ts +5 -5
  11. package/dist/commands.js +17 -17
  12. package/dist/content.d.ts +2 -2
  13. package/dist/content.js +66 -28
  14. package/dist/context-overlays.d.ts +3 -3
  15. package/dist/context-overlays.js +11 -11
  16. package/dist/data.d.ts +1 -1
  17. package/dist/data.js +18 -18
  18. package/dist/date-picker.d.ts +8 -8
  19. package/dist/date-picker.js +18 -18
  20. package/dist/dialog-focus.js +7 -7
  21. package/dist/dialog.d.ts +5 -5
  22. package/dist/dialog.js +16 -16
  23. package/dist/feedback.d.ts +5 -5
  24. package/dist/feedback.js +20 -20
  25. package/dist/file-upload.d.ts +9 -9
  26. package/dist/file-upload.js +64 -63
  27. package/dist/filter-bar.d.ts +1 -1
  28. package/dist/filter-bar.js +9 -9
  29. package/dist/form-state.d.ts +1 -1
  30. package/dist/form-state.js +11 -11
  31. package/dist/forms.d.ts +5 -5
  32. package/dist/forms.js +32 -32
  33. package/dist/foundations.d.ts +10 -10
  34. package/dist/foundations.js +26 -26
  35. package/dist/icon.d.ts +7 -7
  36. package/dist/icon.js +22 -22
  37. package/dist/index.d.ts +37 -37
  38. package/dist/index.js +38 -38
  39. package/dist/input-extensions.d.ts +3 -3
  40. package/dist/input-extensions.js +21 -21
  41. package/dist/input.d.ts +2 -2
  42. package/dist/input.js +7 -7
  43. package/dist/markdown.d.ts +2 -2
  44. package/dist/markdown.js +38 -38
  45. package/dist/menu.d.ts +2 -2
  46. package/dist/menu.js +19 -19
  47. package/dist/messages.d.ts +2 -2
  48. package/dist/messages.js +18 -18
  49. package/dist/navigation-menu.d.ts +2 -2
  50. package/dist/navigation-menu.js +16 -16
  51. package/dist/navigation.d.ts +5 -5
  52. package/dist/navigation.js +40 -40
  53. package/dist/otp-field.d.ts +1 -1
  54. package/dist/otp-field.js +14 -14
  55. package/dist/pagination.d.ts +2 -2
  56. package/dist/pagination.js +12 -12
  57. package/dist/panels.d.ts +8 -8
  58. package/dist/panels.js +39 -39
  59. package/dist/parts.d.ts +2 -2
  60. package/dist/parts.js +8 -8
  61. package/dist/popover.d.ts +3 -3
  62. package/dist/popover.js +6 -6
  63. package/dist/scroll-area.d.ts +1 -1
  64. package/dist/scroll-area.js +20 -20
  65. package/dist/select.d.ts +8 -8
  66. package/dist/select.js +21 -21
  67. package/dist/sizing.d.ts +3 -3
  68. package/dist/sizing.js +9 -9
  69. package/dist/slot.d.ts +1 -1
  70. package/dist/slot.js +4 -4
  71. package/dist/status.d.ts +4 -4
  72. package/dist/status.js +8 -8
  73. package/dist/syntax-engine.js +43 -43
  74. package/dist/syntax-highlighter.d.ts +2 -2
  75. package/dist/syntax-highlighter.js +32 -32
  76. package/dist/toast.d.ts +4 -4
  77. package/dist/toast.js +33 -33
  78. package/dist/tone-transition.d.ts +1 -1
  79. package/dist/tone-transition.js +17 -17
  80. package/dist/tooltip.d.ts +1 -1
  81. package/dist/tooltip.js +4 -4
  82. package/dist/tree.d.ts +4 -4
  83. package/dist/tree.js +60 -60
  84. package/package.json +2 -2
  85. package/src/styles.css +233 -142
package/dist/tree.js CHANGED
@@ -1,23 +1,23 @@
1
- "use client";
1
+ 'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { createElement as _createElement } from "react";
4
- import * as React from "react";
5
- import { useComponentSize } from "./sizing.js";
6
- import { buildProxiedInstance, syncDataLoaderFeature, } from "@headless-tree/core";
7
- import { useTree } from "@headless-tree/react";
8
- import { defaultRangeExtractor, useVirtualizer, } from "@tanstack/react-virtual";
9
- import { ScrollArea } from "./scroll-area.js";
10
- const normalize = (text) => text.normalize("NFKC").toLocaleLowerCase();
4
+ import * as React from 'react';
5
+ import { useComponentSize } from './sizing.js';
6
+ import { buildProxiedInstance, syncDataLoaderFeature, } from '@headless-tree/core';
7
+ import { useTree } from '@headless-tree/react';
8
+ import { defaultRangeExtractor, useVirtualizer, } from '@tanstack/react-virtual';
9
+ import { ScrollArea } from './scroll-area.js';
10
+ const normalize = (text) => text.normalize('NFKC').toLocaleLowerCase();
11
11
  /** Loaded, immutable hierarchy. Remote loading, permission checks and mutations remain caller-owned. */
12
- export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExpandedIdsChange, selectedIds, defaultSelectedIds = [], onSelectedIdsChange, selectionMode = "single", height = 320, rowHeight: explicitRowHeight, size, virtualized = true, emptyLabel = "No items.", dir, className, }) {
12
+ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExpandedIdsChange, selectedIds, defaultSelectedIds = [], onSelectedIdsChange, selectionMode = 'single', height = 320, rowHeight: explicitRowHeight, size, virtualized = true, emptyLabel = 'No items.', dir, className, }) {
13
13
  const scheme = useComponentSize(size);
14
14
  const touchFloor = React.useSyncExternalStore((listener) => {
15
- const query = matchMedia("(max-width: 760px), (pointer: coarse)");
16
- query.addEventListener("change", listener);
17
- return () => query.removeEventListener("change", listener);
18
- }, () => matchMedia("(max-width: 760px), (pointer: coarse)").matches, () => false);
15
+ const query = matchMedia('(max-width: 760px), (pointer: coarse)');
16
+ query.addEventListener('change', listener);
17
+ return () => query.removeEventListener('change', listener);
18
+ }, () => matchMedia('(max-width: 760px), (pointer: coarse)').matches, () => false);
19
19
  const rowHeight = explicitRowHeight ??
20
- Math.max(touchFloor && scheme ? 44 : 0, scheme === "small" ? 36 : scheme === "large" ? 52 : 44);
20
+ Math.max(touchFloor && scheme ? 44 : 0, scheme === 'small' ? 36 : scheme === 'large' ? 52 : 44);
21
21
  const rootId = React.useId();
22
22
  const model = React.useMemo(() => {
23
23
  const data = new Map();
@@ -42,7 +42,7 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
42
42
  const expanded = React.useMemo(() => [...new Set(expandedIds ?? localExpanded)].filter((id) => model.data.get(id)?.children?.length), [expandedIds, localExpanded, model]);
43
43
  const selected = React.useMemo(() => {
44
44
  const ids = [...new Set(selectedIds ?? localSelected)].filter((id) => model.data.has(id) && !model.data.get(id)?.disabled);
45
- return selectionMode === "single" ? ids.slice(-1) : ids;
45
+ return selectionMode === 'single' ? ids.slice(-1) : ids;
46
46
  }, [selectedIds, localSelected, model, selectionMode]);
47
47
  const visibleIds = React.useMemo(() => {
48
48
  const result = [], open = new Set(expanded);
@@ -66,7 +66,7 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
66
66
  const viewport = React.useRef(null), container = React.useRef(null);
67
67
  const virtualizerRef = React.useRef(null);
68
68
  const pendingFocus = React.useRef(null), focusWithin = React.useRef(false), anchor = React.useRef(null);
69
- const typeahead = React.useRef({ text: "", time: 0 });
69
+ const typeahead = React.useRef({ text: '', time: 0 });
70
70
  function changeExpanded(ids) {
71
71
  const next = [...new Set(ids)];
72
72
  if (expandedIds === undefined)
@@ -75,7 +75,7 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
75
75
  }
76
76
  function changeSelected(ids) {
77
77
  const allowed = [...new Set(ids)].filter((id) => model.data.has(id) && !model.data.get(id)?.disabled);
78
- const next = selectionMode === "single" ? allowed.slice(-1) : allowed;
78
+ const next = selectionMode === 'single' ? allowed.slice(-1) : allowed;
79
79
  if (selectedIds === undefined)
80
80
  setLocalSelected(next);
81
81
  onSelectedIdsChange?.(next);
@@ -91,14 +91,14 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
91
91
  getChildren: (id) => model.data.get(id)?.children?.map((node) => node.id) ?? [],
92
92
  },
93
93
  state: { expandedItems: expanded, focusedItem: focused },
94
- setExpandedItems: (update) => changeExpanded(typeof update === "function" ? update(expanded) : update),
95
- setFocusedItem: (update) => setLocalFocus(typeof update === "function" ? update(focused) : update),
94
+ setExpandedItems: (update) => changeExpanded(typeof update === 'function' ? update(expanded) : update),
95
+ setFocusedItem: (update) => setLocalFocus(typeof update === 'function' ? update(focused) : update),
96
96
  scrollToItem: (item) => virtualizerRef.current?.scrollToIndex(item.getItemMeta().index, {
97
- align: "auto",
97
+ align: 'auto',
98
98
  }),
99
99
  });
100
100
  const items = tree.getItems();
101
- const focusedIndex = visibleIds.indexOf(focused ?? "");
101
+ const focusedIndex = visibleIds.indexOf(focused ?? '');
102
102
  const virtualizer = useVirtualizer({
103
103
  count: items.length,
104
104
  getScrollElement: () => viewport.current,
@@ -121,7 +121,7 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
121
121
  pendingFocus.current = item.getId();
122
122
  item.setFocused();
123
123
  if (virtualized)
124
- virtualizer.scrollToIndex(item.getItemMeta().index, { align: "auto" });
124
+ virtualizer.scrollToIndex(item.getItemMeta().index, { align: 'auto' });
125
125
  else if (viewport.current) {
126
126
  const top = item.getItemMeta().index * rowHeight;
127
127
  if (top < viewport.current.scrollTop)
@@ -157,7 +157,7 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
157
157
  const id = item.getId();
158
158
  if (item.getItemData().disabled)
159
159
  return;
160
- if (selectionMode === "single")
160
+ if (selectionMode === 'single')
161
161
  changeSelected([id]);
162
162
  else if (range && anchor.current && visibleIds.includes(anchor.current)) {
163
163
  const a = visibleIds.indexOf(anchor.current), b = visibleIds.indexOf(id);
@@ -173,9 +173,9 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
173
173
  function keydown(event) {
174
174
  if (event.defaultPrevented ||
175
175
  event.nativeEvent.isComposing ||
176
- event.target.closest("button"))
176
+ event.target.closest('button'))
177
177
  return;
178
- const targetId = event.target.closest("[data-tree-id]")?.dataset.treeId;
178
+ const targetId = event.target.closest('[data-tree-id]')?.dataset.treeId;
179
179
  const item = targetId
180
180
  ? tree.getItemInstance(targetId)
181
181
  : focused
@@ -184,20 +184,20 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
184
184
  if (!item)
185
185
  return;
186
186
  if ([
187
- "ArrowDown",
188
- "ArrowUp",
189
- "ArrowLeft",
190
- "ArrowRight",
191
- "Home",
192
- "End",
187
+ 'ArrowDown',
188
+ 'ArrowUp',
189
+ 'ArrowLeft',
190
+ 'ArrowRight',
191
+ 'Home',
192
+ 'End',
193
193
  ].includes(event.key))
194
- typeahead.current = { text: "", time: 0 };
194
+ typeahead.current = { text: '', time: 0 };
195
195
  const index = item.getItemMeta().index;
196
- const rtl = getComputedStyle(event.currentTarget).direction === "rtl";
197
- const forward = rtl ? "ArrowLeft" : "ArrowRight", backward = rtl ? "ArrowRight" : "ArrowLeft";
196
+ const rtl = getComputedStyle(event.currentTarget).direction === 'rtl';
197
+ const forward = rtl ? 'ArrowLeft' : 'ArrowRight', backward = rtl ? 'ArrowRight' : 'ArrowLeft';
198
198
  if ((event.ctrlKey || event.metaKey) &&
199
- event.key.toLowerCase() === "a" &&
200
- selectionMode === "multiple") {
199
+ event.key.toLowerCase() === 'a' &&
200
+ selectionMode === 'multiple') {
201
201
  event.preventDefault();
202
202
  changeSelected(visibleIds);
203
203
  return;
@@ -205,26 +205,26 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
205
205
  if (event.ctrlKey || event.metaKey || event.altKey)
206
206
  return;
207
207
  if ([
208
- "ArrowDown",
209
- "ArrowUp",
210
- "Home",
211
- "End",
208
+ 'ArrowDown',
209
+ 'ArrowUp',
210
+ 'Home',
211
+ 'End',
212
212
  forward,
213
213
  backward,
214
- "Enter",
215
- " ",
216
- "*",
214
+ 'Enter',
215
+ ' ',
216
+ '*',
217
217
  ].includes(event.key))
218
218
  event.preventDefault();
219
- if (event.key === "ArrowDown" || event.key === "ArrowUp") {
220
- const next = items[index + (event.key === "ArrowDown" ? 1 : -1)];
219
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
220
+ const next = items[index + (event.key === 'ArrowDown' ? 1 : -1)];
221
221
  focusItem(next);
222
- if (event.shiftKey && selectionMode === "multiple" && next)
222
+ if (event.shiftKey && selectionMode === 'multiple' && next)
223
223
  select(next, true);
224
224
  }
225
- else if (event.key === "Home")
225
+ else if (event.key === 'Home')
226
226
  focusItem(items[0]);
227
- else if (event.key === "End")
227
+ else if (event.key === 'End')
228
228
  focusItem(items.at(-1));
229
229
  else if (event.key === forward &&
230
230
  !item.getItemData().disabled &&
@@ -240,9 +240,9 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
240
240
  else if (item.getItemMeta().level > 0)
241
241
  focusItem(item.getParent());
242
242
  }
243
- else if (event.key === "Enter" || event.key === " ")
243
+ else if (event.key === 'Enter' || event.key === ' ')
244
244
  select(item, event.shiftKey);
245
- else if (event.key === "*")
245
+ else if (event.key === '*')
246
246
  changeExpanded([
247
247
  ...expanded,
248
248
  ...items
@@ -252,7 +252,7 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
252
252
  .map((sibling) => sibling.getId()),
253
253
  ]);
254
254
  else if (event.key.length === 1) {
255
- const now = performance.now(), char = normalize(event.key), previous = now - typeahead.current.time < 700 ? typeahead.current.text : "";
255
+ const now = performance.now(), char = normalize(event.key), previous = now - typeahead.current.time < 700 ? typeahead.current.text : '';
256
256
  const prefix = previous === char ? char : previous + char;
257
257
  typeahead.current = { text: prefix, time: now };
258
258
  for (let offset = 1; offset <= items.length; offset++) {
@@ -271,16 +271,16 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
271
271
  .getVirtualItems()
272
272
  .map((row) => ({ index: row.index, start: row.start }))
273
273
  : items.map((_, index) => ({ index, start: index * rowHeight }));
274
- return (_jsx(ScrollArea, { orientation: "vertical", label: `${label} scroll area`, tabIndex: -1, ref: viewport, scrollChain: "contain", rootClassName: ["pui-tree-scroll", className].filter(Boolean).join(" "), dir: dir, rootStyle: { blockSize: height, direction: dir }, className: "pui-tree-viewport", children: items.length ? (_jsx("div", { ...containerProps, ref: (element) => {
274
+ return (_jsx(ScrollArea, { orientation: 'vertical', label: `${label} scroll area`, tabIndex: -1, ref: viewport, scrollChain: 'contain', rootClassName: ['pui-tree-scroll', className].filter(Boolean).join(' '), dir: dir, rootStyle: { blockSize: height, direction: dir }, className: 'pui-tree-viewport', children: items.length ? (_jsx("div", { ...containerProps, ref: (element) => {
275
275
  container.current = element;
276
276
  containerProps.ref(element);
277
- }, dir: dir, className: "pui-tree", "data-ui-size": scheme, "aria-multiselectable": selectionMode === "multiple" || undefined, onKeyDown: keydown, onFocusCapture: () => {
277
+ }, dir: dir, className: 'pui-tree', "data-ui-size": scheme, "aria-multiselectable": selectionMode === 'multiple' || undefined, onKeyDown: keydown, onFocusCapture: () => {
278
278
  focusWithin.current = true;
279
279
  }, onBlurCapture: (event) => {
280
280
  if (event.relatedTarget &&
281
281
  !event.currentTarget.contains(event.relatedTarget)) {
282
282
  focusWithin.current = false;
283
- typeahead.current.text = "";
283
+ typeahead.current.text = '';
284
284
  }
285
285
  }, style: {
286
286
  blockSize: virtualized
@@ -288,24 +288,24 @@ export function Tree({ nodes, label, expandedIds, defaultExpandedIds = [], onExp
288
288
  : items.length * rowHeight,
289
289
  }, children: rows.map(({ index, start }) => {
290
290
  const item = items[index], node = item.getItemData(), props = item.getProps();
291
- return (_createElement("div", { ...props, key: item.getId(), className: "pui-tree-item", "data-tree-id": node.id, "aria-disabled": node.disabled || undefined, "aria-selected": node.disabled ? undefined : selected.includes(node.id), title: node.label, onFocus: () => item.setFocused(), onClick: (event) => {
291
+ return (_createElement("div", { ...props, key: item.getId(), className: 'pui-tree-item', "data-tree-id": node.id, "aria-disabled": node.disabled || undefined, "aria-selected": node.disabled ? undefined : selected.includes(node.id), title: node.label, onFocus: () => item.setFocused(), onClick: (event) => {
292
292
  focusItem(item);
293
293
  select(item, event.shiftKey);
294
294
  }, style: {
295
- position: "absolute",
295
+ position: 'absolute',
296
296
  insetInline: 0,
297
297
  top: start,
298
298
  blockSize: rowHeight,
299
299
  paddingInlineStart: `calc(var(--space-2) + ${Math.min(item.getItemMeta().level, 8)} * var(--space-4))`,
300
300
  } },
301
- item.isFolder() ? (_jsx("button", { type: "button", className: "pui-tree-toggle", tabIndex: -1, disabled: node.disabled, "aria-label": `${item.isExpanded() ? "Collapse" : "Expand"} ${node.label}`, onClick: (event) => {
301
+ item.isFolder() ? (_jsx("button", { type: 'button', className: 'pui-tree-toggle', tabIndex: -1, disabled: node.disabled, "aria-label": `${item.isExpanded() ? 'Collapse' : 'Expand'} ${node.label}`, onClick: (event) => {
302
302
  event.stopPropagation();
303
303
  focusItem(item);
304
304
  if (item.isExpanded())
305
305
  item.collapse();
306
306
  else
307
307
  item.expand();
308
- }, children: _jsx("svg", { "aria-hidden": "true", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.6", "data-expanded": item.isExpanded() || undefined, children: _jsx("path", { d: "m9 5 7 7-7 7" }) }) })) : (_jsx("span", { className: "pui-tree-leaf", "aria-hidden": "true" })),
309
- _jsx("span", { className: "pui-tree-label", children: node.label })));
310
- }) })) : (_jsx("div", { role: "status", className: "pui-tree-empty", children: emptyLabel })) }));
308
+ }, children: _jsx("svg", { "aria-hidden": 'true', width: '14', height: '14', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '1.6', "data-expanded": item.isExpanded() || undefined, children: _jsx("path", { d: 'm9 5 7 7-7 7' }) }) })) : (_jsx("span", { className: 'pui-tree-leaf', "aria-hidden": 'true' })),
309
+ _jsx("span", { className: 'pui-tree-label', children: node.label })));
310
+ }) })) : (_jsx("div", { role: 'status', className: 'pui-tree-empty', children: emptyLabel })) }));
311
311
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@surflane/ui",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Surflane React components built on Base UI, with data, chart, code and Markdown components.",
5
5
  "keywords": [
6
6
  "design-system",
@@ -101,7 +101,7 @@
101
101
  "shiki": "4.5.0"
102
102
  },
103
103
  "peerDependencies": {
104
- "@surflane/design-tokens": "^0.1.0",
104
+ "@surflane/design-tokens": "^0.2.0",
105
105
  "react": "^19.0.0",
106
106
  "react-dom": "^19.0.0"
107
107
  },