@green-on-grey/ui-kit 1.8.0 → 1.10.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.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { a as e, c as t, d as n, i as r, l as i, n as a, o, r as s, s as c, t as l, u } from "./ui-DvmjcG-d.js";
2
- import { n as d, t as f } from "./i18n-BJ8rsBp6.js";
3
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
4
- import { useCallback as h, useEffect as g, useRef as _, useState as v } from "react";
1
+ import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, t as u, u as d } from "./ui-sV5t0cp1.js";
2
+ import { n as f, t as p } from "./i18n-BJ8rsBp6.js";
3
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
4
+ import { useCallback as g, useEffect as _, useState as v } from "react";
5
5
  //#region src/components/Button.tsx
6
6
  function y({ variant: e, size: t, className: n, type: r = "button", ...i }) {
7
7
  let a = [
@@ -10,7 +10,7 @@ function y({ variant: e, size: t, className: n, type: r = "button", ...i }) {
10
10
  t,
11
11
  n
12
12
  ].filter(Boolean).join(" ");
13
- return /* @__PURE__ */ p("button", {
13
+ return /* @__PURE__ */ m("button", {
14
14
  type: r,
15
15
  className: a,
16
16
  ...i
@@ -23,7 +23,7 @@ function b({ label: e, fill: t, on: n, className: r, type: i = "button", ...a })
23
23
  n && "on",
24
24
  r
25
25
  ].filter(Boolean).join(" ");
26
- return /* @__PURE__ */ p("button", {
26
+ return /* @__PURE__ */ m("button", {
27
27
  type: i,
28
28
  className: o,
29
29
  "aria-label": e,
@@ -31,37 +31,13 @@ function b({ label: e, fill: t, on: n, className: r, type: i = "button", ...a })
31
31
  });
32
32
  }
33
33
  //#endregion
34
- //#region src/components/Tabs.tsx
35
- function x({ items: e, value: t, onChange: n, label: r }) {
36
- let i = _(null);
37
- return /* @__PURE__ */ p("div", {
38
- className: "tabs",
39
- role: "tablist",
40
- "aria-label": r,
41
- ref: i,
42
- onKeyDown: (r) => {
43
- let a = e.findIndex((e) => e.key === t), o = r.key === "ArrowRight" ? (a + 1) % e.length : r.key === "ArrowLeft" ? (a - 1 + e.length) % e.length : r.key === "Home" ? 0 : r.key === "End" ? e.length - 1 : -1;
44
- o < 0 || (r.preventDefault(), n(e[o].key), i.current?.querySelectorAll("[role=\"tab\"]")[o]?.focus());
45
- },
46
- children: e.map((e) => /* @__PURE__ */ p("button", {
47
- type: "button",
48
- role: "tab",
49
- "aria-selected": e.key === t,
50
- tabIndex: e.key === t ? 0 : -1,
51
- className: e.key === t ? "on" : void 0,
52
- onClick: () => n(e.key),
53
- children: e.label
54
- }, e.key))
55
- });
56
- }
57
- //#endregion
58
34
  //#region src/components/Menu.tsx
59
- function S({ onClose: e, label: t, className: n, children: r }) {
60
- let i = c(!0, e);
61
- return g(() => {
35
+ function x({ onClose: e, label: t, className: n, children: r }) {
36
+ let i = l(!0, e);
37
+ return _(() => {
62
38
  let e = document.activeElement;
63
39
  return () => e?.focus?.();
64
- }, []), /* @__PURE__ */ p("div", {
40
+ }, []), /* @__PURE__ */ m("div", {
65
41
  className: `menu${n ? ` ${n}` : ""}`,
66
42
  role: "dialog",
67
43
  "aria-label": t,
@@ -71,68 +47,68 @@ function S({ onClose: e, label: t, className: n, children: r }) {
71
47
  }
72
48
  //#endregion
73
49
  //#region src/components/TopBar.tsx
74
- function C({ logo: e, name: t, home: r = "/", sections: i, Link: a, center: o, actions: s, avatar: l, profileMenu: u, menu: f }) {
75
- let g = d(), [_, y] = v(!1), [b, x] = v(!1), S = h(() => x(!1), []), C = h(() => y(!1), []), w = c(b, S), T = i.map((e) => /* @__PURE__ */ p(a, {
50
+ function S({ logo: e, name: t, home: n = "/", sections: i, Link: a, center: o, actions: s, avatar: c, profileMenu: u, menu: d }) {
51
+ let p = f(), [_, y] = v(!1), [b, x] = v(!1), S = g(() => x(!1), []), C = g(() => y(!1), []), w = l(b, S), T = i.map((e) => /* @__PURE__ */ m(a, {
76
52
  href: e.href,
77
53
  className: e.active ? "on" : void 0,
78
54
  "aria-current": e.active ? "page" : void 0,
79
55
  onClick: S,
80
56
  children: e.label
81
57
  }, e.key));
82
- return /* @__PURE__ */ m("div", {
58
+ return /* @__PURE__ */ h("div", {
83
59
  className: "topbar",
84
60
  children: [
85
- /* @__PURE__ */ m(a, {
86
- href: r,
61
+ /* @__PURE__ */ h(a, {
62
+ href: n,
87
63
  className: "brand",
88
- children: [/* @__PURE__ */ p("img", {
64
+ children: [/* @__PURE__ */ m("img", {
89
65
  src: e,
90
66
  alt: ""
91
- }), /* @__PURE__ */ p("span", {
67
+ }), /* @__PURE__ */ m("span", {
92
68
  className: "hide-m",
93
69
  children: t
94
70
  })]
95
71
  }),
96
- /* @__PURE__ */ p("nav", {
72
+ /* @__PURE__ */ m("nav", {
97
73
  className: "nav hide-m",
98
- "aria-label": g("topbar.sections"),
74
+ "aria-label": p("topbar.sections"),
99
75
  children: T
100
76
  }),
101
77
  o,
102
- /* @__PURE__ */ m("div", {
78
+ /* @__PURE__ */ h("div", {
103
79
  className: "top-actions",
104
80
  children: [
105
81
  s,
106
- /* @__PURE__ */ p("button", {
82
+ /* @__PURE__ */ m("button", {
107
83
  className: "avatar",
108
84
  style: _ ? { boxShadow: "0 0 0 2px var(--violet)" } : void 0,
109
85
  onClick: () => {
110
86
  x(!1), y((e) => !e);
111
87
  },
112
- "aria-label": g("topbar.profile"),
88
+ "aria-label": p("topbar.profile"),
113
89
  "aria-expanded": _,
114
- children: l
90
+ children: c
115
91
  }),
116
- /* @__PURE__ */ m("div", {
92
+ /* @__PURE__ */ h("div", {
117
93
  className: "burger",
118
94
  ref: w,
119
- children: [/* @__PURE__ */ p("button", {
95
+ children: [/* @__PURE__ */ m("button", {
120
96
  className: `iconbtn${b ? " on" : ""}`,
121
97
  onClick: () => {
122
98
  y(!1), x((e) => !e);
123
99
  },
124
- "aria-label": f?.label ?? g("topbar.sections"),
100
+ "aria-label": d?.label ?? p("topbar.sections"),
125
101
  "aria-expanded": b,
126
102
  "aria-controls": "nav-sections",
127
- children: /* @__PURE__ */ p(n, { name: b ? "x" : "menu" })
128
- }), b && (f ? /* @__PURE__ */ p("div", {
103
+ children: /* @__PURE__ */ m(r, { name: b ? "x" : "menu" })
104
+ }), b && (d ? /* @__PURE__ */ m("div", {
129
105
  id: "nav-sections",
130
106
  className: "navmenu",
131
- children: f.render(S)
132
- }) : /* @__PURE__ */ p("nav", {
107
+ children: d.render(S)
108
+ }) : /* @__PURE__ */ m("nav", {
133
109
  id: "nav-sections",
134
110
  className: "navmenu",
135
- "aria-label": g("topbar.sections"),
111
+ "aria-label": p("topbar.sections"),
136
112
  children: T
137
113
  }))]
138
114
  })
@@ -143,6 +119,6 @@ function C({ logo: e, name: t, home: r = "/", sections: i, Link: a, center: o, a
143
119
  });
144
120
  }
145
121
  //#endregion
146
- export { l as Avatar, y as Button, a as Empty, u as GitHubIcon, n as Icon, b as IconButton, s as Loading, i as Markdown, S as Menu, r as Modal, e as Switch, x as Tabs, o as ToastProvider, C as TopBar, f as UIKIT_NS, c as useOutside, t as useToast };
122
+ export { u as Avatar, y as Button, o as Empty, n as GitHubIcon, r as Icon, b as IconButton, c as Loading, d as Markdown, x as Menu, i as Modal, e as Switch, a as Tabs, s as ToastProvider, S as TopBar, p as UIKIT_NS, l as useOutside, t as useToast };
147
123
 
148
124
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["Switch","useToast","Icon","Modal","Markdown","Empty","Loading","useOutside","Avatar","useKitT","UIKIT_NS","Button","rest","cls","variant","size","className","IconButton","fill","on","label","Tabs","ref","useRef","i","items","it","value","to","e","onChange","Menu","onClose","useEffect","opener","TopBar","t","profileOpen","setProfileOpen","useState","sectionsOpen","setSectionsOpen","closeSections","useCallback","closeProfile","links","sections","Link","s","home","logo","name","center","actions","v","avatar","menu","profileMenu","GitHubIcon","ToastProvider"],"sources":["../src/components/Button.tsx","../src/components/Tabs.tsx","../src/components/Menu.tsx","../src/components/TopBar.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes } from \"react\";\n\ntype Native = ButtonHTMLAttributes<HTMLButtonElement>;\n\n/** `button.btn` with its variants. The classes stay a legitimate way to use a\n * button (FTR.NAB.CMN-0005 tech, decision 1); the component is for new code. */\nexport function Button({ variant, size, className, type = \"button\", ...rest }: Native & {\n variant?: \"primary\" | \"ghost\" | \"danger\"; size?: \"sm\";\n}) {\n const cls = [\"btn\", variant, size, className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} {...rest} />;\n}\n\n/** `button.iconbtn`: a button with an icon only, so the label is required. */\nexport function IconButton({ label, fill, on, className, type = \"button\", ...rest }: Omit<Native, \"aria-label\"> & {\n label: string; fill?: boolean; on?: boolean;\n}) {\n const cls = [\"iconbtn\", fill && \"fill\", on && \"on\", className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} aria-label={label} {...rest} />;\n}\n","import { useRef, type KeyboardEvent, type ReactNode } from \"react\";\n\n/** `.tabs` with the keyboard of a tab list: arrows, Home and End move the choice. */\nexport function Tabs<K extends string>({ items, value, onChange, label }: {\n items: { key: K; label: ReactNode }[]; value: K; onChange: (key: K) => void; label?: string;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const onKey = (e: KeyboardEvent) => {\n const i = items.findIndex((it) => it.key === value);\n const to = e.key === \"ArrowRight\" ? (i + 1) % items.length\n : e.key === \"ArrowLeft\" ? (i - 1 + items.length) % items.length\n : e.key === \"Home\" ? 0 : e.key === \"End\" ? items.length - 1 : -1;\n if (to < 0) return;\n e.preventDefault();\n onChange(items[to].key);\n ref.current?.querySelectorAll<HTMLElement>('[role=\"tab\"]')[to]?.focus();\n };\n return (\n <div className=\"tabs\" role=\"tablist\" aria-label={label} ref={ref} onKeyDown={onKey}>\n {items.map((it) => (\n <button key={it.key} type=\"button\" role=\"tab\" aria-selected={it.key === value} tabIndex={it.key === value ? 0 : -1}\n className={it.key === value ? \"on\" : undefined} onClick={() => onChange(it.key)}>\n {it.label}\n </button>\n ))}\n </div>\n );\n}\n","import { useEffect, type ReactNode } from \"react\";\nimport { useOutside } from \"./ui\";\n\n/** `.menu`: a popover closed by Escape and by a click outside; it is mounted while\n * open. `onClose` must keep its identity between renders. What is inside\n * (sections `.sec`, lines `.line`, actions `.action`) belongs to the product. */\nexport function Menu({ onClose, label, className, children }: {\n onClose: () => void; label?: string; className?: string; children: ReactNode;\n}) {\n const ref = useOutside<HTMLDivElement>(true, onClose);\n // the focus returns to what opened the menu (CMP-05)\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n return () => opener?.focus?.();\n }, []);\n return (\n <div className={`menu${className ? ` ${className}` : \"\"}`} role=\"dialog\" aria-label={label} ref={ref}>\n {children}\n </div>\n );\n}\n","import { useCallback, useState, type ReactNode } from \"react\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\nimport { useOutside } from \"./ui\";\n\n/** The link of the product: the kit does not depend on a router (arch §4.2). */\nexport type LinkComponent = (props: {\n href: string; className?: string; onClick?: () => void; \"aria-current\"?: \"page\"; children: ReactNode;\n}) => ReactNode;\n\nexport interface TopBarSection { key: string; label: ReactNode; href: string; active: boolean }\n\n/** The top bar (FTR.NAB.CMN-0005 R5, design §4): the logo and the name, the\n * sections in a row and behind the burger on a phone, the actions of the product,\n * the avatar that opens the profile menu. The profile menu and the list of\n * sections are never open together. A part of the product with its own\n * navigation (the administration) puts it behind the burger in place of the\n * sections: `menu`, with the side panel marked `in-burger`, hidden on a phone. */\nexport function TopBar({ logo, name, home = \"/\", sections, Link, center, actions, avatar, profileMenu, menu }: {\n logo: string; name: string; home?: string; sections: TopBarSection[]; Link: LinkComponent;\n /** Between the sections and the actions: the search of Hammurapi. */\n center?: ReactNode;\n /** Before the avatar. */\n actions?: ReactNode;\n avatar: ReactNode;\n profileMenu: (close: () => void) => ReactNode;\n /** The burger of a phone in place of the sections: the navigation of the current part of the product and\n * its name, which the burger is called by. */\n menu?: { label: string; render: (close: () => void) => ReactNode };\n}) {\n const t = useKitT();\n const [profileOpen, setProfileOpen] = useState(false);\n const [sectionsOpen, setSectionsOpen] = useState(false);\n const closeSections = useCallback(() => setSectionsOpen(false), []);\n const closeProfile = useCallback(() => setProfileOpen(false), []);\n const ref = useOutside<HTMLDivElement>(sectionsOpen, closeSections);\n const links = sections.map((s) => (\n <Link key={s.key} href={s.href} className={s.active ? \"on\" : undefined} aria-current={s.active ? \"page\" : undefined} onClick={closeSections}>\n {s.label}\n </Link>\n ));\n return (\n <div className=\"topbar\">\n <Link href={home} className=\"brand\">\n <img src={logo} alt=\"\" />\n <span className=\"hide-m\">{name}</span>\n </Link>\n <nav className=\"nav hide-m\" aria-label={t(\"topbar.sections\")}>{links}</nav>\n {center}\n <div className=\"top-actions\">\n {actions}\n <button className=\"avatar\" style={profileOpen ? { boxShadow: \"0 0 0 2px var(--violet)\" } : undefined}\n onClick={() => { setSectionsOpen(false); setProfileOpen((v) => !v); }} aria-label={t(\"topbar.profile\")} aria-expanded={profileOpen}>\n {avatar}\n </button>\n <div className=\"burger\" ref={ref}>\n <button className={`iconbtn${sectionsOpen ? \" on\" : \"\"}`} onClick={() => { setProfileOpen(false); setSectionsOpen((v) => !v); }}\n aria-label={menu?.label ?? t(\"topbar.sections\")} aria-expanded={sectionsOpen} aria-controls=\"nav-sections\">\n <Icon name={sectionsOpen ? \"x\" : \"menu\"} />\n </button>\n {sectionsOpen && (menu\n ? <div id=\"nav-sections\" className=\"navmenu\">{menu.render(closeSections)}</div>\n : <nav id=\"nav-sections\" className=\"navmenu\" aria-label={t(\"topbar.sections\")}>{links}</nav>)}\n </div>\n </div>\n {profileOpen && profileMenu(closeProfile)}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["Switch","useToast","GitHubIcon","Icon","Tabs","Empty","ToastProvider","Loading","useOutside","Avatar","Markdown","useKitT","UIKIT_NS","Button","rest","cls","variant","size","className","IconButton","fill","on","label","Menu","ref","onClose","useEffect","opener","TopBar","t","profileOpen","setProfileOpen","useState","sectionsOpen","setSectionsOpen","closeSections","useCallback","closeProfile","links","sections","Link","s","home","logo","name","center","actions","v","avatar","menu","profileMenu","Modal"],"sources":["../src/components/Button.tsx","../src/components/Menu.tsx","../src/components/TopBar.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes } from \"react\";\n\ntype Native = ButtonHTMLAttributes<HTMLButtonElement>;\n\n/** `button.btn` with its variants. The classes stay a legitimate way to use a\n * button (FTR.NAB.CMN-0005 tech, decision 1); the component is for new code. */\nexport function Button({ variant, size, className, type = \"button\", ...rest }: Native & {\n variant?: \"primary\" | \"ghost\" | \"danger\"; size?: \"sm\";\n}) {\n const cls = [\"btn\", variant, size, className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} {...rest} />;\n}\n\n/** `button.iconbtn`: a button with an icon only, so the label is required. */\nexport function IconButton({ label, fill, on, className, type = \"button\", ...rest }: Omit<Native, \"aria-label\"> & {\n label: string; fill?: boolean; on?: boolean;\n}) {\n const cls = [\"iconbtn\", fill && \"fill\", on && \"on\", className].filter(Boolean).join(\" \");\n return <button type={type} className={cls} aria-label={label} {...rest} />;\n}\n","import { useEffect, type ReactNode } from \"react\";\nimport { useOutside } from \"./ui\";\n\n/** `.menu`: a popover closed by Escape and by a click outside; it is mounted while\n * open. `onClose` must keep its identity between renders. What is inside\n * (sections `.sec`, lines `.line`, actions `.action`) belongs to the product. */\nexport function Menu({ onClose, label, className, children }: {\n onClose: () => void; label?: string; className?: string; children: ReactNode;\n}) {\n const ref = useOutside<HTMLDivElement>(true, onClose);\n // the focus returns to what opened the menu (CMP-05)\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n return () => opener?.focus?.();\n }, []);\n return (\n <div className={`menu${className ? ` ${className}` : \"\"}`} role=\"dialog\" aria-label={label} ref={ref}>\n {children}\n </div>\n );\n}\n","import { useCallback, useState, type ReactNode } from \"react\";\nimport { useKitT } from \"../i18n\";\nimport { Icon } from \"./Icon\";\nimport { useOutside } from \"./ui\";\n\n/** The link of the product: the kit does not depend on a router (arch §4.2). */\nexport type LinkComponent = (props: {\n href: string; className?: string; onClick?: () => void; \"aria-current\"?: \"page\"; children: ReactNode;\n}) => ReactNode;\n\nexport interface TopBarSection { key: string; label: ReactNode; href: string; active: boolean }\n\n/** The top bar (FTR.NAB.CMN-0005 R5, design §4): the logo and the name, the\n * sections in a row and behind the burger on a phone, the actions of the product,\n * the avatar that opens the profile menu. The profile menu and the list of\n * sections are never open together. A part of the product with its own\n * navigation (the administration) puts it behind the burger in place of the\n * sections: `menu`, with the side panel marked `in-burger`, hidden on a phone. */\nexport function TopBar({ logo, name, home = \"/\", sections, Link, center, actions, avatar, profileMenu, menu }: {\n logo: string; name: string; home?: string; sections: TopBarSection[]; Link: LinkComponent;\n /** Between the sections and the actions: the search of Hammurapi. */\n center?: ReactNode;\n /** Before the avatar. */\n actions?: ReactNode;\n avatar: ReactNode;\n profileMenu: (close: () => void) => ReactNode;\n /** The burger of a phone in place of the sections: the navigation of the current part of the product and\n * its name, which the burger is called by. */\n menu?: { label: string; render: (close: () => void) => ReactNode };\n}) {\n const t = useKitT();\n const [profileOpen, setProfileOpen] = useState(false);\n const [sectionsOpen, setSectionsOpen] = useState(false);\n const closeSections = useCallback(() => setSectionsOpen(false), []);\n const closeProfile = useCallback(() => setProfileOpen(false), []);\n const ref = useOutside<HTMLDivElement>(sectionsOpen, closeSections);\n const links = sections.map((s) => (\n <Link key={s.key} href={s.href} className={s.active ? \"on\" : undefined} aria-current={s.active ? \"page\" : undefined} onClick={closeSections}>\n {s.label}\n </Link>\n ));\n return (\n <div className=\"topbar\">\n <Link href={home} className=\"brand\">\n <img src={logo} alt=\"\" />\n <span className=\"hide-m\">{name}</span>\n </Link>\n <nav className=\"nav hide-m\" aria-label={t(\"topbar.sections\")}>{links}</nav>\n {center}\n <div className=\"top-actions\">\n {actions}\n <button className=\"avatar\" style={profileOpen ? { boxShadow: \"0 0 0 2px var(--violet)\" } : undefined}\n onClick={() => { setSectionsOpen(false); setProfileOpen((v) => !v); }} aria-label={t(\"topbar.profile\")} aria-expanded={profileOpen}>\n {avatar}\n </button>\n <div className=\"burger\" ref={ref}>\n <button className={`iconbtn${sectionsOpen ? \" on\" : \"\"}`} onClick={() => { setProfileOpen(false); setSectionsOpen((v) => !v); }}\n aria-label={menu?.label ?? t(\"topbar.sections\")} aria-expanded={sectionsOpen} aria-controls=\"nav-sections\">\n <Icon name={sectionsOpen ? \"x\" : \"menu\"} />\n </button>\n {sectionsOpen && (menu\n ? <div id=\"nav-sections\" className=\"navmenu\">{menu.render(closeSections)}</div>\n : <nav id=\"nav-sections\" className=\"navmenu\" aria-label={t(\"topbar.sections\")}>{links}</nav>)}\n </div>\n </div>\n {profileOpen && profileMenu(closeProfile)}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -90,6 +90,25 @@ export declare const resources: {
90
90
  rows: string;
91
91
  source: string;
92
92
  page: string;
93
+ converted: string;
94
+ pagesShown: string;
95
+ firstPages: string;
96
+ cols: string;
97
+ preparing: string;
98
+ preparingHint: string;
99
+ unavailable: string;
100
+ formulaHint: string;
101
+ sheets: string;
102
+ reasons: {
103
+ too_large: string;
104
+ timeout: string;
105
+ broken: string;
106
+ busy: string;
107
+ };
108
+ };
109
+ notice: {
110
+ more: string;
111
+ less: string;
93
112
  };
94
113
  };
95
114
  agent: {
@@ -193,6 +212,25 @@ export declare const resources: {
193
212
  rows: string;
194
213
  source: string;
195
214
  page: string;
215
+ converted: string;
216
+ pagesShown: string;
217
+ firstPages: string;
218
+ cols: string;
219
+ preparing: string;
220
+ preparingHint: string;
221
+ unavailable: string;
222
+ formulaHint: string;
223
+ sheets: string;
224
+ reasons: {
225
+ too_large: string;
226
+ timeout: string;
227
+ broken: string;
228
+ busy: string;
229
+ };
230
+ };
231
+ notice: {
232
+ more: string;
233
+ less: string;
196
234
  };
197
235
  };
198
236
  agent: {
@@ -296,6 +334,25 @@ export declare const resources: {
296
334
  rows: string;
297
335
  source: string;
298
336
  page: string;
337
+ converted: string;
338
+ pagesShown: string;
339
+ firstPages: string;
340
+ cols: string;
341
+ preparing: string;
342
+ preparingHint: string;
343
+ unavailable: string;
344
+ formulaHint: string;
345
+ sheets: string;
346
+ reasons: {
347
+ too_large: string;
348
+ timeout: string;
349
+ broken: string;
350
+ busy: string;
351
+ };
352
+ };
353
+ notice: {
354
+ more: string;
355
+ less: string;
299
356
  };
300
357
  };
301
358
  agent: {
@@ -399,6 +456,25 @@ export declare const resources: {
399
456
  rows: string;
400
457
  source: string;
401
458
  page: string;
459
+ converted: string;
460
+ pagesShown: string;
461
+ firstPages: string;
462
+ cols: string;
463
+ preparing: string;
464
+ preparingHint: string;
465
+ unavailable: string;
466
+ formulaHint: string;
467
+ sheets: string;
468
+ reasons: {
469
+ too_large: string;
470
+ timeout: string;
471
+ broken: string;
472
+ busy: string;
473
+ };
474
+ };
475
+ notice: {
476
+ more: string;
477
+ less: string;
402
478
  };
403
479
  };
404
480
  agent: {
@@ -502,6 +578,25 @@ export declare const resources: {
502
578
  rows: string;
503
579
  source: string;
504
580
  page: string;
581
+ converted: string;
582
+ pagesShown: string;
583
+ firstPages: string;
584
+ cols: string;
585
+ preparing: string;
586
+ preparingHint: string;
587
+ unavailable: string;
588
+ formulaHint: string;
589
+ sheets: string;
590
+ reasons: {
591
+ too_large: string;
592
+ timeout: string;
593
+ broken: string;
594
+ busy: string;
595
+ };
596
+ };
597
+ notice: {
598
+ more: string;
599
+ less: string;
505
600
  };
506
601
  };
507
602
  agent: {
package/dist/locales.js CHANGED
@@ -88,7 +88,26 @@ var t = {
88
88
  notUtf8: "The file is not in UTF-8 — download it",
89
89
  rows: "Showing {shown} of {total, plural, one {# row} other {# rows}}",
90
90
  source: "Code",
91
- page: "Page"
91
+ page: "Page",
92
+ converted: "Preview · converted from {format}",
93
+ pagesShown: "Showing {shown} of {total} pages",
94
+ firstPages: "Showing the first {shown} pages",
95
+ cols: "and {shown} of {total} columns",
96
+ preparing: "Preparing the preview…",
97
+ preparingHint: "Usually a few seconds",
98
+ unavailable: "Preview unavailable",
99
+ formulaHint: "The value is calculated when opened in Excel",
100
+ sheets: "Sheets",
101
+ reasons: {
102
+ too_large: "The file is over {limit} MB",
103
+ timeout: "Took longer than 30 seconds",
104
+ broken: "The file is damaged or the format is not supported",
105
+ busy: "The service is busy, try again later"
106
+ }
107
+ },
108
+ notice: {
109
+ more: "Show in full",
110
+ less: "Collapse"
92
111
  }
93
112
  },
94
113
  agent: {
@@ -189,7 +208,26 @@ var t = {
189
208
  notUtf8: "Файл не в кодировке UTF-8 — скачайте его",
190
209
  rows: "Показаны {shown} из {total, plural, one {# строки} other {# строк}}",
191
210
  source: "Код",
192
- page: "Страница"
211
+ page: "Страница",
212
+ converted: "Предпросмотр · сконвертировано из {format}",
213
+ pagesShown: "Показаны {shown} из {total} страниц",
214
+ firstPages: "Показаны первые {shown} страниц",
215
+ cols: "и {shown} из {total} столбцов",
216
+ preparing: "Готовим предпросмотр…",
217
+ preparingHint: "Обычно несколько секунд",
218
+ unavailable: "Предпросмотр недоступен",
219
+ formulaHint: "Значение посчитается при открытии в Excel",
220
+ sheets: "Листы",
221
+ reasons: {
222
+ too_large: "Файл больше {limit} МБ",
223
+ timeout: "Не успели за 30 секунд",
224
+ broken: "Файл повреждён или формат не поддерживается",
225
+ busy: "Сервис занят, попробуйте позже"
226
+ }
227
+ },
228
+ notice: {
229
+ more: "Показать полностью",
230
+ less: "Свернуть"
193
231
  }
194
232
  },
195
233
  agent: {
@@ -290,7 +328,26 @@ var t = {
290
328
  notUtf8: "Die Datei ist nicht in UTF-8 — bitte herunterladen",
291
329
  rows: "{shown} von {total, plural, one {# Zeile} other {# Zeilen}} angezeigt",
292
330
  source: "Code",
293
- page: "Seite"
331
+ page: "Seite",
332
+ converted: "Vorschau · konvertiert aus {format}",
333
+ pagesShown: "{shown} von {total} Seiten werden angezeigt",
334
+ firstPages: "Die ersten {shown} Seiten werden angezeigt",
335
+ cols: "und {shown} von {total} Spalten",
336
+ preparing: "Vorschau wird vorbereitet…",
337
+ preparingHint: "Meist nur wenige Sekunden",
338
+ unavailable: "Vorschau nicht verfügbar",
339
+ formulaHint: "Der Wert wird beim Öffnen in Excel berechnet",
340
+ sheets: "Blätter",
341
+ reasons: {
342
+ too_large: "Die Datei ist größer als {limit} MB",
343
+ timeout: "Hat länger als 30 Sekunden gedauert",
344
+ broken: "Die Datei ist beschädigt oder das Format wird nicht unterstützt",
345
+ busy: "Der Dienst ist ausgelastet, versuchen Sie es später erneut"
346
+ }
347
+ },
348
+ notice: {
349
+ more: "Vollständig anzeigen",
350
+ less: "Einklappen"
294
351
  }
295
352
  },
296
353
  agent: {
@@ -391,7 +448,26 @@ var t = {
391
448
  notUtf8: "El archivo no está en UTF-8: descárguelo",
392
449
  rows: "Se muestran {shown} de {total, plural, one {# fila} other {# filas}}",
393
450
  source: "Código",
394
- page: "Página"
451
+ page: "Página",
452
+ converted: "Vista previa · convertido desde {format}",
453
+ pagesShown: "Se muestran {shown} de {total} páginas",
454
+ firstPages: "Se muestran las primeras {shown} páginas",
455
+ cols: "y {shown} de {total} columnas",
456
+ preparing: "Preparando la vista previa…",
457
+ preparingHint: "Suele tardar unos segundos",
458
+ unavailable: "Vista previa no disponible",
459
+ formulaHint: "El valor se calcula al abrir el archivo en Excel",
460
+ sheets: "Hojas",
461
+ reasons: {
462
+ too_large: "El archivo supera {limit} MB",
463
+ timeout: "Tardó más de 30 segundos",
464
+ broken: "El archivo está dañado o el formato no es compatible",
465
+ busy: "El servicio está ocupado, inténtalo más tarde"
466
+ }
467
+ },
468
+ notice: {
469
+ more: "Mostrar completo",
470
+ less: "Contraer"
395
471
  }
396
472
  },
397
473
  agent: {
@@ -492,7 +568,26 @@ var t = {
492
568
  notUtf8: "文件不是 UTF-8 编码,请下载",
493
569
  rows: "显示 {total} 行中的 {shown} 行",
494
570
  source: "代码",
495
- page: "页面"
571
+ page: "页面",
572
+ converted: "预览 · 由 {format} 转换",
573
+ pagesShown: "显示 {shown} / {total} 页",
574
+ firstPages: "显示前 {shown} 页",
575
+ cols: "以及 {shown} / {total} 列",
576
+ preparing: "正在准备预览…",
577
+ preparingHint: "通常只需几秒",
578
+ unavailable: "无法预览",
579
+ formulaHint: "在 Excel 中打开时计算该值",
580
+ sheets: "工作表",
581
+ reasons: {
582
+ too_large: "文件大于 {limit} MB",
583
+ timeout: "超过 30 秒未完成",
584
+ broken: "文件已损坏或格式不受支持",
585
+ busy: "服务繁忙,请稍后重试"
586
+ }
587
+ },
588
+ notice: {
589
+ more: "显示全部",
590
+ less: "收起"
496
591
  }
497
592
  },
498
593
  agent: {