@burdenoff/microfe-files 2026.527.1 → 2026.527.3

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 (49) hide show
  1. package/dist/files/components/ActionMenu.js +44 -40
  2. package/dist/files/components/ActionMenu.js.map +1 -1
  3. package/dist/files/components/ConfirmDialog.js +42 -40
  4. package/dist/files/components/ConfirmDialog.js.map +1 -1
  5. package/dist/files/components/CopyDialog.js +1 -0
  6. package/dist/files/components/CopyDialog.js.map +1 -1
  7. package/dist/files/components/FileBrowser.js +186 -170
  8. package/dist/files/components/FileBrowser.js.map +1 -1
  9. package/dist/files/components/FileCard.js.map +1 -1
  10. package/dist/files/components/FileInfoPanel.js +102 -102
  11. package/dist/files/components/FileInfoPanel.js.map +1 -1
  12. package/dist/files/components/FileListItem.js.map +1 -1
  13. package/dist/files/components/FolderCard.js +147 -161
  14. package/dist/files/components/FolderCard.js.map +1 -1
  15. package/dist/files/components/MoveDialog.js +9 -12
  16. package/dist/files/components/MoveDialog.js.map +1 -1
  17. package/dist/files/components/SearchBar.js +125 -117
  18. package/dist/files/components/SearchBar.js.map +1 -1
  19. package/dist/files/components/ShareDialog.js +5 -0
  20. package/dist/files/components/ShareDialog.js.map +1 -1
  21. package/dist/files/components/Toast.js +27 -24
  22. package/dist/files/components/Toast.js.map +1 -1
  23. package/dist/files/components/UploadQueue.js +1 -1
  24. package/dist/files/components/UploadQueue.js.map +1 -1
  25. package/dist/files/components/viewers/AudioPlayer.js +3 -0
  26. package/dist/files/components/viewers/AudioPlayer.js.map +1 -1
  27. package/dist/files/components/viewers/TextViewer.js +1 -0
  28. package/dist/files/components/viewers/TextViewer.js.map +1 -1
  29. package/dist/files/components/viewers/VideoPlayer.js +3 -0
  30. package/dist/files/components/viewers/VideoPlayer.js.map +1 -1
  31. package/dist/files/hooks/useCreateFolder.js +15 -7
  32. package/dist/files/hooks/useCreateFolder.js.map +1 -1
  33. package/dist/files/hooks/useKeyboardNavigation.js +51 -51
  34. package/dist/files/hooks/useKeyboardNavigation.js.map +1 -1
  35. package/dist/files/hooks/useMoveFile.js +1 -2
  36. package/dist/files/hooks/useMoveFile.js.map +1 -1
  37. package/dist/files/hooks/useMoveFolder.js +0 -2
  38. package/dist/files/hooks/useMoveFolder.js.map +1 -1
  39. package/dist/files/hooks/useStarredItems.js +4 -3
  40. package/dist/files/hooks/useStarredItems.js.map +1 -1
  41. package/dist/files/hooks/useToggleStar.js +10 -10
  42. package/dist/files/hooks/useToggleStar.js.map +1 -1
  43. package/dist/files/pages/BrowserPage.js +312 -302
  44. package/dist/files/pages/BrowserPage.js.map +1 -1
  45. package/dist/files/pages/ShareAccessPage.js +1 -0
  46. package/dist/files/pages/ShareAccessPage.js.map +1 -1
  47. package/dist/files/utils/quotaUtils.js +14 -0
  48. package/dist/files/utils/quotaUtils.js.map +1 -0
  49. package/package.json +2 -2
@@ -1,10 +1,10 @@
1
1
  import { tWithFallback as e } from "../utils/i18n.js";
2
- import { useCallback as t, useEffect as n, useState as r } from "react";
3
- import { Filter as i, Search as a, X as o } from "lucide-react";
4
- import { jsx as s, jsxs as c } from "react/jsx-runtime";
5
- import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
2
+ import { useCallback as t, useEffect as n, useEffectEvent as r, useState as i } from "react";
3
+ import { Filter as a, Search as o, X as s } from "lucide-react";
4
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
5
+ import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
6
6
  //#region src/files/components/SearchBar.tsx
7
- var u = {
7
+ var d = {
8
8
  image: [
9
9
  "image/jpeg",
10
10
  "image/png",
@@ -37,217 +37,225 @@ var u = {
37
37
  "application/x-rar-compressed"
38
38
  ]
39
39
  };
40
- function d({ onSearch: d, placeholder: f = "Search files and folders...", initialQuery: p = "", showFilters: m = !0 }) {
41
- let { t: h } = l(), [g, _] = r(p), [v, y] = r(!1), [b, x] = r({}), S = b.status, C = b.status, w = b.visibility, T = b.fileType ? u[b.fileType] : void 0;
40
+ function f({ onSearch: f, placeholder: p = "Search files and folders...", initialQuery: m = "", showFilters: h = !0 }) {
41
+ let { t: g } = u(), [_, v] = i(m), [y, b] = i(!1), [x, S] = i({}), C = x.status, w = x.status, T = x.visibility, E = x.fileType ? d[x.fileType] : void 0;
42
+ n(() => {
43
+ v(m);
44
+ }, [m]);
45
+ let D = r(() => {
46
+ (_.length >= 2 || _.length === 0) && f(_, {
47
+ fileFilter: {
48
+ ...E && { mimeTypes: E },
49
+ ...C && { status: C },
50
+ ...T && { visibility: T },
51
+ ...x.starred !== void 0 && { starred: x.starred }
52
+ },
53
+ folderFilter: {
54
+ ...w && { status: w },
55
+ ...x.starred !== void 0 && { starred: x.starred }
56
+ }
57
+ });
58
+ });
42
59
  n(() => {
43
- _(p);
44
- }, [p]), n(() => {
45
60
  let e = setTimeout(() => {
46
- (g.length >= 2 || g.length === 0) && d(g, {
47
- fileFilter: {
48
- ...T && { mimeTypes: T },
49
- ...S && { status: S },
50
- ...w && { visibility: w },
51
- ...b.starred !== void 0 && { starred: b.starred }
52
- },
53
- folderFilter: {
54
- ...C && { status: C },
55
- ...b.starred !== void 0 && { starred: b.starred }
56
- }
57
- });
61
+ D();
58
62
  }, 300);
59
63
  return () => clearTimeout(e);
60
64
  }, [
61
- S,
65
+ C,
66
+ E,
62
67
  T,
63
68
  w,
64
- C,
65
- b,
66
- d,
67
- g
69
+ x,
70
+ _
68
71
  ]);
69
- let E = t(() => {
70
- _(""), x({}), d("");
71
- }, [d]), D = Object.values(b).filter((e) => e !== void 0).length;
72
- return /* @__PURE__ */ c("div", {
72
+ let O = t(() => {
73
+ v(""), S({}), f("");
74
+ }, [f]), k = Object.values(x).filter((e) => e !== void 0).length;
75
+ return /* @__PURE__ */ l("div", {
73
76
  className: "relative",
74
- children: [/* @__PURE__ */ c("div", {
77
+ children: [/* @__PURE__ */ l("div", {
75
78
  className: "relative flex items-center",
76
79
  children: [
77
- /* @__PURE__ */ s(a, { className: "absolute left-3 size-4 text-text-tertiary" }),
78
- /* @__PURE__ */ s("label", {
80
+ /* @__PURE__ */ c(o, { className: "absolute left-3 size-4 text-text-tertiary" }),
81
+ /* @__PURE__ */ c("label", {
79
82
  htmlFor: "files-search-input",
80
83
  className: "sr-only",
81
- children: e(h, "files.search.input.label", "Search files and folders")
84
+ children: e(g, "files.search.input.label", "Search files and folders")
82
85
  }),
83
- /* @__PURE__ */ s("input", {
86
+ /* @__PURE__ */ c("input", {
84
87
  id: "files-search-input",
85
88
  type: "text",
86
- value: g,
87
- onChange: (e) => _(e.target.value),
88
- placeholder: f,
89
+ value: _,
90
+ onChange: (e) => v(e.target.value),
91
+ placeholder: p,
92
+ "aria-label": e(g, "files.search.input.label", "Search files and folders"),
89
93
  className: "w-full pl-[3.25rem] pr-20 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border focus:border-action-primary-border transition-colors duration-200"
90
94
  }),
91
- /* @__PURE__ */ c("div", {
95
+ /* @__PURE__ */ l("div", {
92
96
  className: "absolute right-2 flex items-center gap-1",
93
- children: [g && /* @__PURE__ */ s("button", {
97
+ children: [_ && /* @__PURE__ */ c("button", {
94
98
  type: "button",
95
- onClick: E,
99
+ onClick: O,
96
100
  className: "p-1.5 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200",
97
- title: e(h, "files.search.actions.clearSearch", "Clear search"),
98
- "aria-label": e(h, "files.search.actions.clearSearch", "Clear search"),
99
- children: /* @__PURE__ */ s(o, { className: "size-4" })
100
- }), m && /* @__PURE__ */ c("button", {
101
+ title: e(g, "files.search.actions.clearSearch", "Clear search"),
102
+ "aria-label": e(g, "files.search.actions.clearSearch", "Clear search"),
103
+ children: /* @__PURE__ */ c(s, { className: "size-4" })
104
+ }), h && /* @__PURE__ */ l("button", {
101
105
  type: "button",
102
- onClick: () => y(!v),
103
- "aria-expanded": v,
106
+ onClick: () => b(!y),
107
+ "aria-expanded": y,
104
108
  "aria-controls": "files-search-filter-panel",
105
- "aria-label": e(h, "files.search.filters.toggleAria", "Toggle filters"),
106
- className: `p-1.5 rounded transition-colors duration-200 relative ${v || D > 0 ? "text-text-link bg-bg-accent hover:bg-action-primary-bg/20" : "text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover"}`,
107
- title: e(h, "files.search.filters.title", "Filters"),
108
- children: [/* @__PURE__ */ s(i, { className: "size-4" }), D > 0 && /* @__PURE__ */ s("span", {
109
+ "aria-label": e(g, "files.search.filters.toggleAria", "Toggle filters"),
110
+ className: `p-1.5 rounded transition-colors duration-200 relative ${y || k > 0 ? "text-text-link bg-bg-accent hover:bg-action-primary-bg/20" : "text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover"}`,
111
+ title: e(g, "files.search.filters.title", "Filters"),
112
+ children: [/* @__PURE__ */ c(a, { className: "size-4" }), k > 0 && /* @__PURE__ */ c("span", {
109
113
  className: "absolute -top-1 -right-1 size-4 bg-action-primary-bg text-text-inverse text-[10px] font-bold rounded-full flex items-center justify-center",
110
- children: D
114
+ children: k
111
115
  })]
112
116
  })]
113
117
  })
114
118
  ]
115
- }), v && /* @__PURE__ */ s("div", {
119
+ }), y && /* @__PURE__ */ c("div", {
116
120
  id: "files-search-filter-panel",
117
121
  className: "absolute top-full left-0 right-0 mt-2 p-4 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10 animate-in fade-in duration-200",
118
- children: /* @__PURE__ */ c("div", {
122
+ children: /* @__PURE__ */ l("div", {
119
123
  className: "space-y-4",
120
124
  children: [
121
- /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("label", {
125
+ /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
122
126
  className: "block text-sm font-medium text-text-primary mb-1",
123
- children: e(h, "files.search.filters.fileType.label", "File Type")
124
- }), /* @__PURE__ */ c("select", {
125
- value: b.fileType || "",
126
- onChange: (e) => x({
127
- ...b,
127
+ children: e(g, "files.search.filters.fileType.label", "File Type")
128
+ }), /* @__PURE__ */ l("select", {
129
+ value: x.fileType || "",
130
+ onChange: (e) => S({
131
+ ...x,
128
132
  fileType: e.target.value || void 0
129
133
  }),
134
+ "aria-label": e(g, "files.search.filters.fileType.label", "File Type"),
130
135
  className: "w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border transition-colors duration-200",
131
136
  children: [
132
- /* @__PURE__ */ s("option", {
137
+ /* @__PURE__ */ c("option", {
133
138
  value: "",
134
- children: e(h, "files.search.filters.fileType.options.all", "All types")
139
+ children: e(g, "files.search.filters.fileType.options.all", "All types")
135
140
  }),
136
- /* @__PURE__ */ s("option", {
141
+ /* @__PURE__ */ c("option", {
137
142
  value: "image",
138
- children: e(h, "files.search.filters.fileType.options.image", "Images")
143
+ children: e(g, "files.search.filters.fileType.options.image", "Images")
139
144
  }),
140
- /* @__PURE__ */ s("option", {
145
+ /* @__PURE__ */ c("option", {
141
146
  value: "video",
142
- children: e(h, "files.search.filters.fileType.options.video", "Videos")
147
+ children: e(g, "files.search.filters.fileType.options.video", "Videos")
143
148
  }),
144
- /* @__PURE__ */ s("option", {
149
+ /* @__PURE__ */ c("option", {
145
150
  value: "document",
146
- children: e(h, "files.search.filters.fileType.options.document", "Documents")
151
+ children: e(g, "files.search.filters.fileType.options.document", "Documents")
147
152
  }),
148
- /* @__PURE__ */ s("option", {
153
+ /* @__PURE__ */ c("option", {
149
154
  value: "pdf",
150
- children: e(h, "files.search.filters.fileType.options.pdf", "PDFs")
155
+ children: e(g, "files.search.filters.fileType.options.pdf", "PDFs")
151
156
  }),
152
- /* @__PURE__ */ s("option", {
157
+ /* @__PURE__ */ c("option", {
153
158
  value: "archive",
154
- children: e(h, "files.search.filters.fileType.options.archive", "Archives")
159
+ children: e(g, "files.search.filters.fileType.options.archive", "Archives")
155
160
  })
156
161
  ]
157
162
  })] }),
158
- /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("label", {
163
+ /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
159
164
  className: "block text-sm font-medium text-text-primary mb-1",
160
- children: e(h, "files.search.filters.status.label", "Status")
161
- }), /* @__PURE__ */ c("select", {
162
- value: b.status || "",
163
- onChange: (e) => x({
164
- ...b,
165
+ children: e(g, "files.search.filters.status.label", "Status")
166
+ }), /* @__PURE__ */ l("select", {
167
+ value: x.status || "",
168
+ onChange: (e) => S({
169
+ ...x,
165
170
  status: e.target.value || void 0
166
171
  }),
172
+ "aria-label": e(g, "files.search.filters.status.label", "Status"),
167
173
  className: "w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border transition-colors duration-200",
168
174
  children: [
169
- /* @__PURE__ */ s("option", {
175
+ /* @__PURE__ */ c("option", {
170
176
  value: "",
171
- children: e(h, "files.search.filters.status.options.all", "All statuses")
177
+ children: e(g, "files.search.filters.status.options.all", "All statuses")
172
178
  }),
173
- /* @__PURE__ */ s("option", {
179
+ /* @__PURE__ */ c("option", {
174
180
  value: "ACTIVE",
175
- children: e(h, "files.search.filters.status.options.active", "Active")
181
+ children: e(g, "files.search.filters.status.options.active", "Active")
176
182
  }),
177
- /* @__PURE__ */ s("option", {
183
+ /* @__PURE__ */ c("option", {
178
184
  value: "ARCHIVED",
179
- children: e(h, "files.search.filters.status.options.archived", "Archived")
185
+ children: e(g, "files.search.filters.status.options.archived", "Archived")
180
186
  }),
181
- /* @__PURE__ */ s("option", {
187
+ /* @__PURE__ */ c("option", {
182
188
  value: "DELETED",
183
- children: e(h, "files.search.filters.status.options.deleted", "Deleted")
189
+ children: e(g, "files.search.filters.status.options.deleted", "Deleted")
184
190
  })
185
191
  ]
186
192
  })] }),
187
- /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("label", {
193
+ /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
188
194
  className: "block text-sm font-medium text-text-primary mb-1",
189
- children: e(h, "files.search.filters.visibility.label", "Visibility")
190
- }), /* @__PURE__ */ c("select", {
191
- value: b.visibility || "",
192
- onChange: (e) => x({
193
- ...b,
195
+ children: e(g, "files.search.filters.visibility.label", "Visibility")
196
+ }), /* @__PURE__ */ l("select", {
197
+ value: x.visibility || "",
198
+ onChange: (e) => S({
199
+ ...x,
194
200
  visibility: e.target.value || void 0
195
201
  }),
202
+ "aria-label": e(g, "files.search.filters.visibility.label", "Visibility"),
196
203
  className: "w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border transition-colors duration-200",
197
204
  children: [
198
- /* @__PURE__ */ s("option", {
205
+ /* @__PURE__ */ c("option", {
199
206
  value: "",
200
- children: e(h, "files.search.filters.visibility.options.all", "All visibility")
207
+ children: e(g, "files.search.filters.visibility.options.all", "All visibility")
201
208
  }),
202
- /* @__PURE__ */ s("option", {
209
+ /* @__PURE__ */ c("option", {
203
210
  value: "PRIVATE",
204
- children: e(h, "files.search.filters.visibility.options.private", "Private")
211
+ children: e(g, "files.search.filters.visibility.options.private", "Private")
205
212
  }),
206
- /* @__PURE__ */ s("option", {
213
+ /* @__PURE__ */ c("option", {
207
214
  value: "TEAM",
208
- children: e(h, "files.search.filters.visibility.options.team", "Team")
215
+ children: e(g, "files.search.filters.visibility.options.team", "Team")
209
216
  }),
210
- /* @__PURE__ */ s("option", {
217
+ /* @__PURE__ */ c("option", {
211
218
  value: "WORKSPACE",
212
- children: e(h, "files.search.filters.visibility.options.workspace", "Workspace")
219
+ children: e(g, "files.search.filters.visibility.options.workspace", "Workspace")
213
220
  }),
214
- /* @__PURE__ */ s("option", {
221
+ /* @__PURE__ */ c("option", {
215
222
  value: "PUBLIC",
216
- children: e(h, "files.search.filters.visibility.options.public", "Public")
223
+ children: e(g, "files.search.filters.visibility.options.public", "Public")
217
224
  })
218
225
  ]
219
226
  })] }),
220
- /* @__PURE__ */ c("div", {
227
+ /* @__PURE__ */ l("div", {
221
228
  className: "flex items-center",
222
- children: [/* @__PURE__ */ s("input", {
229
+ children: [/* @__PURE__ */ c("input", {
223
230
  type: "checkbox",
224
231
  id: "starred-filter",
225
- checked: b.starred || !1,
226
- onChange: (e) => x({
227
- ...b,
232
+ checked: x.starred || !1,
233
+ onChange: (e) => S({
234
+ ...x,
228
235
  starred: e.target.checked || void 0
229
236
  }),
237
+ "aria-label": e(g, "files.search.filters.starred.label", "Starred only"),
230
238
  className: "size-4 text-action-primary-bg border-border-default rounded focus:ring-action-primary-border transition-colors duration-200"
231
- }), /* @__PURE__ */ s("label", {
239
+ }), /* @__PURE__ */ c("label", {
232
240
  htmlFor: "starred-filter",
233
241
  className: "ml-2 text-sm text-text-primary",
234
- children: e(h, "files.search.filters.starredOnly", "Starred only")
242
+ children: e(g, "files.search.filters.starredOnly", "Starred only")
235
243
  })]
236
244
  }),
237
- /* @__PURE__ */ c("div", {
245
+ /* @__PURE__ */ l("div", {
238
246
  className: "flex justify-end gap-2 pt-2 border-t border-border-default",
239
- children: [/* @__PURE__ */ s("button", {
247
+ children: [/* @__PURE__ */ c("button", {
240
248
  type: "button",
241
249
  onClick: () => {
242
- x({}), y(!1);
250
+ S({}), b(!1);
243
251
  },
244
252
  className: "px-3 py-1.5 text-sm text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200",
245
- children: e(h, "files.search.filters.actions.clear", "Clear filters")
246
- }), /* @__PURE__ */ s("button", {
253
+ children: e(g, "files.search.filters.actions.clear", "Clear filters")
254
+ }), /* @__PURE__ */ c("button", {
247
255
  type: "button",
248
- onClick: () => y(!1),
256
+ onClick: () => b(!1),
249
257
  className: "px-3 py-1.5 text-sm bg-action-primary-bg text-text-inverse rounded hover:bg-action-primary-bg-hover transition-colors duration-200",
250
- children: e(h, "files.search.filters.actions.apply", "Apply")
258
+ children: e(g, "files.search.filters.actions.apply", "Apply")
251
259
  })]
252
260
  })
253
261
  ]
@@ -256,6 +264,6 @@ function d({ onSearch: d, placeholder: f = "Search files and folders...", initia
256
264
  });
257
265
  }
258
266
  //#endregion
259
- export { d as SearchBar };
267
+ export { f as SearchBar };
260
268
 
261
269
  //# sourceMappingURL=SearchBar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SearchBar.js","names":[],"sources":["../../../src/files/components/SearchBar.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from \"react\";\nimport { Search, X, Filter } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport type { FileFilterInput, FolderFilterInput } from \"../graphql-types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface SearchBarProps {\n onSearch: (\n query: string,\n filters?: {\n fileFilter?: FileFilterInput;\n folderFilter?: FolderFilterInput;\n },\n ) => void;\n placeholder?: string;\n initialQuery?: string;\n showFilters?: boolean;\n}\n\nconst FILE_TYPE_MIME_MAP: Record<string, string[]> = {\n image: [\n \"image/jpeg\",\n \"image/png\",\n \"image/gif\",\n \"image/webp\",\n \"image/svg+xml\",\n ],\n video: [\"video/mp4\", \"video/webm\", \"video/quicktime\"],\n document: [\n \"application/msword\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \"application/vnd.ms-excel\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"application/vnd.ms-powerpoint\",\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \"text/plain\",\n \"text/csv\",\n \"application/json\",\n ],\n pdf: [\"application/pdf\"],\n archive: [\n \"application/zip\",\n \"application/x-tar\",\n \"application/x-7z-compressed\",\n \"application/gzip\",\n \"application/x-rar-compressed\",\n ],\n};\n\nexport function SearchBar({\n onSearch,\n placeholder = \"Search files and folders...\",\n initialQuery = \"\",\n showFilters = true,\n}: SearchBarProps) {\n const { t } = useI18n();\n const [query, setQuery] = useState(initialQuery);\n const [showFilterPanel, setShowFilterPanel] = useState(false);\n const [filters, setFilters] = useState<{\n fileType?: string;\n status?: string;\n visibility?: string;\n starred?: boolean;\n }>({});\n const fileStatus = filters.status as FileFilterInput[\"status\"] | undefined;\n const folderStatus = filters.status as\n | FolderFilterInput[\"status\"]\n | undefined;\n const fileVisibility = filters.visibility as\n | FileFilterInput[\"visibility\"]\n | undefined;\n const fileMimeTypes = filters.fileType\n ? FILE_TYPE_MIME_MAP[filters.fileType]\n : undefined;\n\n useEffect(() => {\n setQuery(initialQuery);\n }, [initialQuery]);\n\n // Debounced search\n useEffect(() => {\n const timer = setTimeout(() => {\n if (query.length >= 2 || query.length === 0) {\n const fileFilter: FileFilterInput = {\n ...(fileMimeTypes && { mimeTypes: fileMimeTypes }),\n ...(fileStatus && { status: fileStatus }),\n ...(fileVisibility && { visibility: fileVisibility }),\n ...(filters.starred !== undefined && { starred: filters.starred }),\n };\n\n const folderFilter: FolderFilterInput = {\n ...(folderStatus && { status: folderStatus }),\n ...(filters.starred !== undefined && { starred: filters.starred }),\n };\n\n onSearch(query, { fileFilter, folderFilter });\n }\n }, 300);\n\n return () => clearTimeout(timer);\n }, [\n fileStatus,\n fileMimeTypes,\n fileVisibility,\n folderStatus,\n filters,\n onSearch,\n query,\n ]);\n\n const handleClear = useCallback(() => {\n setQuery(\"\");\n setFilters({});\n onSearch(\"\");\n }, [onSearch]);\n\n const activeFilterCount = Object.values(filters).filter(\n (v) => v !== undefined,\n ).length;\n\n return (\n <div className=\"relative\">\n {/* Search Input */}\n <div className=\"relative flex items-center\">\n <Search className=\"absolute left-3 size-4 text-text-tertiary\" />\n <label htmlFor=\"files-search-input\" className=\"sr-only\">\n {tWithFallback(\n t,\n \"files.search.input.label\",\n \"Search files and folders\",\n )}\n </label>\n <input\n id=\"files-search-input\"\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={placeholder}\n className=\"w-full pl-[3.25rem] pr-20 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border focus:border-action-primary-border transition-colors duration-200\"\n />\n <div className=\"absolute right-2 flex items-center gap-1\">\n {query && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"p-1.5 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n title={tWithFallback(\n t,\n \"files.search.actions.clearSearch\",\n \"Clear search\",\n )}\n aria-label={tWithFallback(\n t,\n \"files.search.actions.clearSearch\",\n \"Clear search\",\n )}\n >\n <X className=\"size-4\" />\n </button>\n )}\n {showFilters && (\n <button\n type=\"button\"\n onClick={() => setShowFilterPanel(!showFilterPanel)}\n aria-expanded={showFilterPanel}\n aria-controls=\"files-search-filter-panel\"\n aria-label={tWithFallback(\n t,\n \"files.search.filters.toggleAria\",\n \"Toggle filters\",\n )}\n className={`p-1.5 rounded transition-colors duration-200 relative ${\n showFilterPanel || activeFilterCount > 0\n ? \"text-text-link bg-bg-accent hover:bg-action-primary-bg/20\"\n : \"text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover\"\n }`}\n title={tWithFallback(t, \"files.search.filters.title\", \"Filters\")}\n >\n <Filter className=\"size-4\" />\n {activeFilterCount > 0 && (\n <span className=\"absolute -top-1 -right-1 size-4 bg-action-primary-bg text-text-inverse text-[10px] font-bold rounded-full flex items-center justify-center\">\n {activeFilterCount}\n </span>\n )}\n </button>\n )}\n </div>\n </div>\n\n {/* Filter Panel */}\n {showFilterPanel && (\n <div\n id=\"files-search-filter-panel\"\n className=\"absolute top-full left-0 right-0 mt-2 p-4 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10 animate-in fade-in duration-200\"\n >\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.label\",\n \"File Type\",\n )}\n </label>\n <select\n value={filters.fileType || \"\"}\n onChange={(e) =>\n setFilters({\n ...filters,\n fileType: e.target.value || undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border transition-colors duration-200\"\n >\n <option value=\"\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.all\",\n \"All types\",\n )}\n </option>\n <option value=\"image\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.image\",\n \"Images\",\n )}\n </option>\n <option value=\"video\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.video\",\n \"Videos\",\n )}\n </option>\n <option value=\"document\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.document\",\n \"Documents\",\n )}\n </option>\n <option value=\"pdf\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.pdf\",\n \"PDFs\",\n )}\n </option>\n <option value=\"archive\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.archive\",\n \"Archives\",\n )}\n </option>\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tWithFallback(\n t,\n \"files.search.filters.status.label\",\n \"Status\",\n )}\n </label>\n <select\n value={filters.status || \"\"}\n onChange={(e) =>\n setFilters({\n ...filters,\n status: e.target.value || undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border transition-colors duration-200\"\n >\n <option value=\"\">\n {tWithFallback(\n t,\n \"files.search.filters.status.options.all\",\n \"All statuses\",\n )}\n </option>\n <option value=\"ACTIVE\">\n {tWithFallback(\n t,\n \"files.search.filters.status.options.active\",\n \"Active\",\n )}\n </option>\n <option value=\"ARCHIVED\">\n {tWithFallback(\n t,\n \"files.search.filters.status.options.archived\",\n \"Archived\",\n )}\n </option>\n <option value=\"DELETED\">\n {tWithFallback(\n t,\n \"files.search.filters.status.options.deleted\",\n \"Deleted\",\n )}\n </option>\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.label\",\n \"Visibility\",\n )}\n </label>\n <select\n value={filters.visibility || \"\"}\n onChange={(e) =>\n setFilters({\n ...filters,\n visibility: e.target.value || undefined,\n })\n }\n className=\"w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border transition-colors duration-200\"\n >\n <option value=\"\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.all\",\n \"All visibility\",\n )}\n </option>\n <option value=\"PRIVATE\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.private\",\n \"Private\",\n )}\n </option>\n <option value=\"TEAM\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.team\",\n \"Team\",\n )}\n </option>\n <option value=\"WORKSPACE\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.workspace\",\n \"Workspace\",\n )}\n </option>\n <option value=\"PUBLIC\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.public\",\n \"Public\",\n )}\n </option>\n </select>\n </div>\n\n <div className=\"flex items-center\">\n <input\n type=\"checkbox\"\n id=\"starred-filter\"\n checked={filters.starred || false}\n onChange={(e) =>\n setFilters({\n ...filters,\n starred: e.target.checked || undefined,\n })\n }\n className=\"size-4 text-action-primary-bg border-border-default rounded focus:ring-action-primary-border transition-colors duration-200\"\n />\n <label\n htmlFor=\"starred-filter\"\n className=\"ml-2 text-sm text-text-primary\"\n >\n {tWithFallback(\n t,\n \"files.search.filters.starredOnly\",\n \"Starred only\",\n )}\n </label>\n </div>\n\n <div className=\"flex justify-end gap-2 pt-2 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={() => {\n setFilters({});\n setShowFilterPanel(false);\n }}\n className=\"px-3 py-1.5 text-sm text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n >\n {tWithFallback(\n t,\n \"files.search.filters.actions.clear\",\n \"Clear filters\",\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setShowFilterPanel(false)}\n className=\"px-3 py-1.5 text-sm bg-action-primary-bg text-text-inverse rounded hover:bg-action-primary-bg-hover transition-colors duration-200\"\n >\n {tWithFallback(\n t,\n \"files.search.filters.actions.apply\",\n \"Apply\",\n )}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SearchBar.js","names":[],"sources":["../../../src/files/components/SearchBar.tsx"],"sourcesContent":["import { useState, useEffect, useEffectEvent, useCallback } from \"react\";\nimport { Search, X, Filter } from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport type { FileFilterInput, FolderFilterInput } from \"../graphql-types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface SearchBarProps {\n onSearch: (\n query: string,\n filters?: {\n fileFilter?: FileFilterInput;\n folderFilter?: FolderFilterInput;\n },\n ) => void;\n placeholder?: string;\n initialQuery?: string;\n showFilters?: boolean;\n}\n\nconst FILE_TYPE_MIME_MAP: Record<string, string[]> = {\n image: [\n \"image/jpeg\",\n \"image/png\",\n \"image/gif\",\n \"image/webp\",\n \"image/svg+xml\",\n ],\n video: [\"video/mp4\", \"video/webm\", \"video/quicktime\"],\n document: [\n \"application/msword\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \"application/vnd.ms-excel\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"application/vnd.ms-powerpoint\",\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \"text/plain\",\n \"text/csv\",\n \"application/json\",\n ],\n pdf: [\"application/pdf\"],\n archive: [\n \"application/zip\",\n \"application/x-tar\",\n \"application/x-7z-compressed\",\n \"application/gzip\",\n \"application/x-rar-compressed\",\n ],\n};\n\nexport function SearchBar({\n onSearch,\n placeholder = \"Search files and folders...\",\n initialQuery = \"\",\n showFilters = true,\n}: SearchBarProps) {\n const { t } = useI18n();\n const [query, setQuery] = useState(initialQuery);\n const [showFilterPanel, setShowFilterPanel] = useState(false);\n const [filters, setFilters] = useState<{\n fileType?: string;\n status?: string;\n visibility?: string;\n starred?: boolean;\n }>({});\n const fileStatus = filters.status as FileFilterInput[\"status\"] | undefined;\n const folderStatus = filters.status as\n | FolderFilterInput[\"status\"]\n | undefined;\n const fileVisibility = filters.visibility as\n | FileFilterInput[\"visibility\"]\n | undefined;\n const fileMimeTypes = filters.fileType\n ? FILE_TYPE_MIME_MAP[filters.fileType]\n : undefined;\n\n useEffect(() => {\n setQuery(initialQuery);\n }, [initialQuery]);\n\n const runSearch = useEffectEvent(() => {\n if (query.length >= 2 || query.length === 0) {\n const fileFilter: FileFilterInput = {\n ...(fileMimeTypes && { mimeTypes: fileMimeTypes }),\n ...(fileStatus && { status: fileStatus }),\n ...(fileVisibility && { visibility: fileVisibility }),\n ...(filters.starred !== undefined && { starred: filters.starred }),\n };\n\n const folderFilter: FolderFilterInput = {\n ...(folderStatus && { status: folderStatus }),\n ...(filters.starred !== undefined && { starred: filters.starred }),\n };\n\n onSearch(query, { fileFilter, folderFilter });\n }\n });\n\n // Debounced search\n useEffect(() => {\n const timer = setTimeout(() => {\n runSearch();\n }, 300);\n\n return () => clearTimeout(timer);\n }, [fileStatus, fileMimeTypes, fileVisibility, folderStatus, filters, query]);\n\n const handleClear = useCallback(() => {\n setQuery(\"\");\n setFilters({});\n onSearch(\"\");\n }, [onSearch]);\n\n const activeFilterCount = Object.values(filters).filter(\n (v) => v !== undefined,\n ).length;\n\n return (\n <div className=\"relative\">\n {/* Search Input */}\n <div className=\"relative flex items-center\">\n <Search className=\"absolute left-3 size-4 text-text-tertiary\" />\n <label htmlFor=\"files-search-input\" className=\"sr-only\">\n {tWithFallback(\n t,\n \"files.search.input.label\",\n \"Search files and folders\",\n )}\n </label>\n <input\n id=\"files-search-input\"\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={placeholder}\n aria-label={tWithFallback(\n t,\n \"files.search.input.label\",\n \"Search files and folders\",\n )}\n className=\"w-full pl-[3.25rem] pr-20 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border focus:border-action-primary-border transition-colors duration-200\"\n />\n <div className=\"absolute right-2 flex items-center gap-1\">\n {query && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"p-1.5 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n title={tWithFallback(\n t,\n \"files.search.actions.clearSearch\",\n \"Clear search\",\n )}\n aria-label={tWithFallback(\n t,\n \"files.search.actions.clearSearch\",\n \"Clear search\",\n )}\n >\n <X className=\"size-4\" />\n </button>\n )}\n {showFilters && (\n <button\n type=\"button\"\n onClick={() => setShowFilterPanel(!showFilterPanel)}\n aria-expanded={showFilterPanel}\n aria-controls=\"files-search-filter-panel\"\n aria-label={tWithFallback(\n t,\n \"files.search.filters.toggleAria\",\n \"Toggle filters\",\n )}\n className={`p-1.5 rounded transition-colors duration-200 relative ${\n showFilterPanel || activeFilterCount > 0\n ? \"text-text-link bg-bg-accent hover:bg-action-primary-bg/20\"\n : \"text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover\"\n }`}\n title={tWithFallback(t, \"files.search.filters.title\", \"Filters\")}\n >\n <Filter className=\"size-4\" />\n {activeFilterCount > 0 && (\n <span className=\"absolute -top-1 -right-1 size-4 bg-action-primary-bg text-text-inverse text-[10px] font-bold rounded-full flex items-center justify-center\">\n {activeFilterCount}\n </span>\n )}\n </button>\n )}\n </div>\n </div>\n\n {/* Filter Panel */}\n {showFilterPanel && (\n <div\n id=\"files-search-filter-panel\"\n className=\"absolute top-full left-0 right-0 mt-2 p-4 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10 animate-in fade-in duration-200\"\n >\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.label\",\n \"File Type\",\n )}\n </label>\n <select\n value={filters.fileType || \"\"}\n onChange={(e) =>\n setFilters({\n ...filters,\n fileType: e.target.value || undefined,\n })\n }\n aria-label={tWithFallback(\n t,\n \"files.search.filters.fileType.label\",\n \"File Type\",\n )}\n className=\"w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border transition-colors duration-200\"\n >\n <option value=\"\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.all\",\n \"All types\",\n )}\n </option>\n <option value=\"image\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.image\",\n \"Images\",\n )}\n </option>\n <option value=\"video\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.video\",\n \"Videos\",\n )}\n </option>\n <option value=\"document\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.document\",\n \"Documents\",\n )}\n </option>\n <option value=\"pdf\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.pdf\",\n \"PDFs\",\n )}\n </option>\n <option value=\"archive\">\n {tWithFallback(\n t,\n \"files.search.filters.fileType.options.archive\",\n \"Archives\",\n )}\n </option>\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tWithFallback(\n t,\n \"files.search.filters.status.label\",\n \"Status\",\n )}\n </label>\n <select\n value={filters.status || \"\"}\n onChange={(e) =>\n setFilters({\n ...filters,\n status: e.target.value || undefined,\n })\n }\n aria-label={tWithFallback(\n t,\n \"files.search.filters.status.label\",\n \"Status\",\n )}\n className=\"w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border transition-colors duration-200\"\n >\n <option value=\"\">\n {tWithFallback(\n t,\n \"files.search.filters.status.options.all\",\n \"All statuses\",\n )}\n </option>\n <option value=\"ACTIVE\">\n {tWithFallback(\n t,\n \"files.search.filters.status.options.active\",\n \"Active\",\n )}\n </option>\n <option value=\"ARCHIVED\">\n {tWithFallback(\n t,\n \"files.search.filters.status.options.archived\",\n \"Archived\",\n )}\n </option>\n <option value=\"DELETED\">\n {tWithFallback(\n t,\n \"files.search.filters.status.options.deleted\",\n \"Deleted\",\n )}\n </option>\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.label\",\n \"Visibility\",\n )}\n </label>\n <select\n value={filters.visibility || \"\"}\n onChange={(e) =>\n setFilters({\n ...filters,\n visibility: e.target.value || undefined,\n })\n }\n aria-label={tWithFallback(\n t,\n \"files.search.filters.visibility.label\",\n \"Visibility\",\n )}\n className=\"w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-border transition-colors duration-200\"\n >\n <option value=\"\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.all\",\n \"All visibility\",\n )}\n </option>\n <option value=\"PRIVATE\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.private\",\n \"Private\",\n )}\n </option>\n <option value=\"TEAM\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.team\",\n \"Team\",\n )}\n </option>\n <option value=\"WORKSPACE\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.workspace\",\n \"Workspace\",\n )}\n </option>\n <option value=\"PUBLIC\">\n {tWithFallback(\n t,\n \"files.search.filters.visibility.options.public\",\n \"Public\",\n )}\n </option>\n </select>\n </div>\n\n <div className=\"flex items-center\">\n <input\n type=\"checkbox\"\n id=\"starred-filter\"\n checked={filters.starred || false}\n onChange={(e) =>\n setFilters({\n ...filters,\n starred: e.target.checked || undefined,\n })\n }\n aria-label={tWithFallback(\n t,\n \"files.search.filters.starred.label\",\n \"Starred only\",\n )}\n className=\"size-4 text-action-primary-bg border-border-default rounded focus:ring-action-primary-border transition-colors duration-200\"\n />\n <label\n htmlFor=\"starred-filter\"\n className=\"ml-2 text-sm text-text-primary\"\n >\n {tWithFallback(\n t,\n \"files.search.filters.starredOnly\",\n \"Starred only\",\n )}\n </label>\n </div>\n\n <div className=\"flex justify-end gap-2 pt-2 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={() => {\n setFilters({});\n setShowFilterPanel(false);\n }}\n className=\"px-3 py-1.5 text-sm text-text-primary hover:bg-action-ghost-bg-hover rounded transition-colors duration-200\"\n >\n {tWithFallback(\n t,\n \"files.search.filters.actions.clear\",\n \"Clear filters\",\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setShowFilterPanel(false)}\n className=\"px-3 py-1.5 text-sm bg-action-primary-bg text-text-inverse rounded hover:bg-action-primary-bg-hover transition-colors duration-200\"\n >\n {tWithFallback(\n t,\n \"files.search.filters.actions.apply\",\n \"Apply\",\n )}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -85,6 +85,7 @@ function g({ item: g, itemType: _, onClose: v, onCreateShare: y, isLoading: b })
85
85
  min: "0",
86
86
  value: A,
87
87
  onChange: (e) => j(Number(e.target.value)),
88
+ "aria-label": e(x, "files.shareDialog.downloads.label", "Maximum downloads"),
88
89
  placeholder: e(x, "files.shareDialog.downloads.placeholder", "Unlimited"),
89
90
  className: "w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:border-action-primary-border text-sm transition-colors duration-200"
90
91
  })] }),
@@ -99,6 +100,7 @@ function g({ item: g, itemType: _, onClose: v, onCreateShare: y, isLoading: b })
99
100
  type: "checkbox",
100
101
  checked: M,
101
102
  onChange: (e) => N(e.target.checked),
103
+ "aria-label": e(x, "files.shareDialog.password.require", "Require password"),
102
104
  className: "rounded transition-colors duration-200"
103
105
  }), /* @__PURE__ */ p("span", {
104
106
  className: "text-sm text-text-secondary",
@@ -109,6 +111,7 @@ function g({ item: g, itemType: _, onClose: v, onCreateShare: y, isLoading: b })
109
111
  type: "password",
110
112
  value: P,
111
113
  onChange: (e) => F(e.target.value),
114
+ "aria-label": e(x, "files.shareDialog.password.label", "Password protection"),
112
115
  placeholder: e(x, "files.shareDialog.password.placeholder", "Enter password"),
113
116
  className: "w-full mt-2 px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:border-action-primary-border text-sm transition-colors duration-200"
114
117
  }), /* @__PURE__ */ p("p", {
@@ -125,6 +128,7 @@ function g({ item: g, itemType: _, onClose: v, onCreateShare: y, isLoading: b })
125
128
  type: "email",
126
129
  value: I,
127
130
  onChange: (e) => L(e.target.value),
131
+ "aria-label": e(x, "files.shareDialog.invite.label", "Invite specific person (optional)"),
128
132
  placeholder: "user@example.com",
129
133
  className: "w-full px-3 py-2 border border-border-default rounded-lg focus:outline-none focus:border-action-primary-border text-sm transition-colors duration-200"
130
134
  }),
@@ -185,6 +189,7 @@ function g({ item: g, itemType: _, onClose: v, onCreateShare: y, isLoading: b })
185
189
  type: "text",
186
190
  value: S || "",
187
191
  readOnly: !0,
192
+ "aria-label": e(x, "files.shareDialog.success.linkCreated", "Share link"),
188
193
  className: "flex-1 px-3 py-2 bg-bg-surface border border-status-success-border rounded-lg text-sm"
189
194
  }), /* @__PURE__ */ p("button", {
190
195
  type: "button",