tree-element 0.3.0 → 0.3.1

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/README.md CHANGED
@@ -88,7 +88,7 @@ new TreeElement({
88
88
  | `autoOpen` | `false` | `true` opens everything, a number opens that many levels (`0` is the first level) |
89
89
  | `buttonLeft` | `true` | Put the open/close button left of the title |
90
90
  | `classPrefix` | `"tree-element"` | The prefix of all css classes |
91
- | `closedIcon` | `►` (`◄` in rtl) | Html string or element |
91
+ | `closedIcon` | svg triangle ▶ (◀ rtl) | Html string or element |
92
92
  | `commonClassName` | `"tree-element-common"` | The class that every element gets |
93
93
  | `data` | | The nodes to display |
94
94
  | `dataFilter` | | Transforms the response of `dataUrl` into node data |
@@ -97,7 +97,7 @@ new TreeElement({
97
97
  | `keyboardSupport` | `true` | Navigate with the keyboard |
98
98
  | `nodeClass` | `Node` | Subclass of `Node` to use for nodes |
99
99
  | `openFolderDelay` | `500` | Milliseconds before a folder opens while dragging over it. `false` disables it |
100
- | `openedIcon` | `▼` | Html string or element |
100
+ | `openedIcon` | svg triangle ▼ | Html string or element |
101
101
  | `rtl` | `data-rtl` attribute | Right-to-left rendering |
102
102
  | `saveState` | `false` | `true`, or a string to use as the storage key |
103
103
  | `selectable` | `true` | Allow selecting nodes |
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- Tree-element 0.3.0
2
+ Tree-element 0.3.1
3
3
 
4
4
  Copyright 2026 Marco Braak
5
5
 
package/lib/options.d.ts CHANGED
@@ -77,8 +77,8 @@ export interface TreeElementOptions {
77
77
  *
78
78
  * Type: `HTMLElement | string`
79
79
  *
80
- * @defaultValue `"►"` (`►`), or `"◀"` (`◀`) when `rtl` is
81
- * true.
80
+ * @defaultValue An svg triangle pointing right, or left when `rtl` is
81
+ * true. It is sized in em and filled with `currentColor`.
82
82
  * @group Appearance
83
83
  */
84
84
  closedIcon?: IconElement;
@@ -238,7 +238,8 @@ export interface TreeElementOptions {
238
238
  *
239
239
  * Type: `HTMLElement | string`
240
240
  *
241
- * @defaultValue `"▼"` (`▼`)
241
+ * @defaultValue An svg triangle pointing down, sized in em and filled with
242
+ * `currentColor`.
242
243
  * @group Appearance
243
244
  */
244
245
  openedIcon?: IconElement;
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  declare class RequestUrl {
2
- private isAbsolute;
3
2
  private url;
4
3
  constructor(inputUrl: string);
5
4
  setSearchParam(key: string, value: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"requestUrl.d.ts","sourceRoot":"","sources":["../src/requestUrl.ts"],"names":[],"mappings":"AAQA,cAAM,UAAU;IACd,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,GAAG,CAAM;gBAEL,QAAQ,EAAE,MAAM;IAU5B,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAIzC,KAAK;CAKN;AAED,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"requestUrl.d.ts","sourceRoot":"","sources":["../src/requestUrl.ts"],"names":[],"mappings":"AAGA,cAAM,UAAU;IACd,OAAO,CAAC,GAAG,CAAM;gBAEL,QAAQ,EAAE,MAAM;IAI5B,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAIzC,KAAK;CAGN;AAED,eAAe,UAAU,CAAC"}
package/lib/requestUrl.js CHANGED
@@ -1,24 +1,15 @@
1
- // Url class for absolute and relative urls.
1
+ // Url of a request. A relative url is resolved against the page, like a link
2
+ // or `fetch` would, so it also works when the page is in a subdirectory.
2
3
 
3
- let isAbsoluteUrl = inputUrl => {
4
- return URL.canParse(inputUrl);
5
- };
6
- let LOCALHOST = "http://localhost";
7
4
  class RequestUrl {
8
5
  constructor(inputUrl) {
9
- if (isAbsoluteUrl(inputUrl)) {
10
- this._url = new URL(inputUrl);
11
- this._isAbsolute = true;
12
- } else {
13
- this._url = new URL(inputUrl, LOCALHOST);
14
- this._isAbsolute = false;
15
- }
6
+ this._url = new URL(inputUrl, document.baseURI);
16
7
  }
17
8
  _setSearchParam(key, value) {
18
9
  this._url.searchParams.set(key, value);
19
10
  }
20
11
  _value() {
21
- return this._isAbsolute ? this._url.href : this._url.href.slice(LOCALHOST.length);
12
+ return this._url.href;
22
13
  }
23
14
  }
24
15
 
@@ -1 +1 @@
1
- {"version":3,"file":"requestUrl.js","sources":["../src/requestUrl.ts"],"sourcesContent":["// Url class for absolute and relative urls.\n\nconst isAbsoluteUrl = (inputUrl: string) => {\n return URL.canParse(inputUrl);\n};\n\nconst LOCALHOST = \"http://localhost\";\n\nclass RequestUrl {\n private isAbsolute: boolean;\n private url: URL;\n\n constructor(inputUrl: string) {\n if (isAbsoluteUrl(inputUrl)) {\n this.url = new URL(inputUrl);\n this.isAbsolute = true;\n } else {\n this.url = new URL(inputUrl, LOCALHOST);\n this.isAbsolute = false;\n }\n }\n\n setSearchParam(key: string, value: string) {\n this.url.searchParams.set(key, value);\n }\n\n value() {\n return this.isAbsolute\n ? this.url.href\n : this.url.href.slice(LOCALHOST.length);\n }\n}\n\nexport default RequestUrl;\n"],"names":["url","isAbsolute","setSearchParam","value"],"mappings":"AAAA;;AAEA,IAAM,aAAa,GAAI,QAAgB,IAAK;AAC1C,EAAA,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAC/B,CAAC;AAED,IAAM,SAAS,GAAG,kBAAkB;AAEpC,MAAM,UAAU,CAAC;EAIf,WAAW,CAAC,QAAgB,EAAE;AAC5B,IAAA,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE;AAC3B,MAAA,IAAI,CAACA,IAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC;MAC5B,IAAI,CAACC,WAAU,GAAG,IAAI;AACxB,IAAA,CAAC,MAAM;MACL,IAAI,CAACD,IAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC;MACvC,IAAI,CAACC,WAAU,GAAG,KAAK;AACzB,IAAA;AACF,EAAA;AAEAC,EAAAA,eAAcA,CAAC,GAAW,EAAE,KAAa,EAAE;IACzC,IAAI,CAACF,IAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC;AACvC,EAAA;AAEAG,EAAAA,MAAKA,GAAG;IACN,OAAO,IAAI,CAACF,WAAU,GAClB,IAAI,CAACD,IAAG,CAAC,IAAI,GACb,IAAI,CAACA,IAAG,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AAC3C,EAAA;AACF;;"}
1
+ {"version":3,"file":"requestUrl.js","sources":["../src/requestUrl.ts"],"sourcesContent":["// Url of a request. A relative url is resolved against the page, like a link\n// or `fetch` would, so it also works when the page is in a subdirectory.\n\nclass RequestUrl {\n private url: URL;\n\n constructor(inputUrl: string) {\n this.url = new URL(inputUrl, document.baseURI);\n }\n\n setSearchParam(key: string, value: string) {\n this.url.searchParams.set(key, value);\n }\n\n value() {\n return this.url.href;\n }\n}\n\nexport default RequestUrl;\n"],"names":["url","setSearchParam","value"],"mappings":"AAAA;AACA;;AAEA,MAAM,UAAU,CAAC;EAGf,WAAW,CAAC,QAAgB,EAAE;IAC5B,IAAI,CAACA,IAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC;AAChD,EAAA;AAEAC,EAAAA,eAAcA,CAAC,GAAW,EAAE,KAAa,EAAE;IACzC,IAAI,CAACD,IAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC;AACvC,EAAA;AAEAE,EAAAA,MAAKA,GAAG;AACN,IAAA,OAAO,IAAI,CAACF,IAAG,CAAC,IAAI;AACtB,EAAA;AACF;;"}
@@ -1,4 +1,7 @@
1
1
  import type { TreeElementOptions } from "./options.js";
2
+ export declare const triangleDown: string;
3
+ export declare const triangleLeft: string;
4
+ export declare const triangleRight: string;
2
5
  declare const setDefaultOptions: (htmlElement: HTMLElement, inputOptions: Partial<TreeElementOptions>) => TreeElementOptions;
3
6
  export default setDefaultOptions;
4
7
  //# sourceMappingURL=setDefaultOptions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setDefaultOptions.d.ts","sourceRoot":"","sources":["../src/setDefaultOptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AA6CpD,QAAA,MAAM,iBAAiB,GACrB,aAAa,WAAW,EACxB,cAAc,OAAO,CAAC,kBAAkB,CAAC,KACxC,kBAaF,CAAC;AA4BF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"setDefaultOptions.d.ts","sourceRoot":"","sources":["../src/setDefaultOptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAapD,eAAO,MAAM,YAAY,QAAkC,CAAC;AAC5D,eAAO,MAAM,YAAY,QAAgC,CAAC;AAC1D,eAAO,MAAM,aAAa,QAAgC,CAAC;AAsC3D,QAAA,MAAM,iBAAiB,GACrB,aAAa,WAAW,EACxB,cAAc,OAAO,CAAC,kBAAkB,CAAC,KACxC,kBAaF,CAAC;AAuBF,eAAe,iBAAiB,CAAC"}
@@ -1,6 +1,15 @@
1
1
  import { DEFAULT_CLASS_PREFIX } from './classNames.js';
2
2
  import { Node } from './node.js';
3
3
 
4
+ /* The default icons are svg instead of text: the triangle characters come
5
+ * from different fonts on each platform, so they differ in shape and size.
6
+ * They are sized in em to follow the font size, and use currentColor to follow
7
+ * --tree-element-toggler-color.
8
+ */
9
+ let triangle = points => `<svg width="0.7em" height="0.7em" viewBox="0 0 10 10" focusable="false"><polygon points="${points}" fill="currentColor"/></svg>`;
10
+ let triangleDown = triangle("0.5,1.5 9.5,1.5 5,9");
11
+ let triangleLeft = triangle("9,0.5 9,9.5 1.5,5");
12
+ let triangleRight = triangle("1,0.5 1,9.5 8.5,5");
4
13
  let defaults = {
5
14
  animationSpeed: "fast",
6
15
  autoEscape: true,
@@ -9,9 +18,7 @@ let defaults = {
9
18
  buttonLeft: true,
10
19
  classPrefix: DEFAULT_CLASS_PREFIX,
11
20
  // the prefix of all css classes
12
- // The symbol to use for a closed node - ► BLACK RIGHT-POINTING POINTER
13
- // https://www.fileformat.info/info/unicode/char/25ba/index.htm
14
- // closedIcon: undefined,
21
+ // closedIcon: undefined, // the default is a triangle; see getDefaultClosedIcon
15
22
  // commonClassName: undefined, // the class of every element; the default is "<classPrefix>-common"
16
23
  // data: undefined,
17
24
  // dataFilter: undefined,
@@ -28,11 +35,9 @@ let defaults = {
28
35
  // onGetStateFromStorage: undefined,
29
36
  // onIsMoveHandle: undefined,
30
37
  // onSetStateFromStorage: undefined,
31
- // openedIcon: undefined,
38
+ // openedIcon: undefined, // the default is a triangle pointing down
32
39
  openFolderDelay: 500,
33
40
  // The delay for opening a folder during drag and drop; the value is in milliseconds
34
- // The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE
35
- // https://www.fileformat.info/info/unicode/char/25bc/index.htm
36
41
  // rtl: undefined, // right-to-left support; true / false (default)
37
42
  saveState: false,
38
43
  // true / false / string (local storage key; the default key is "tree")
@@ -55,7 +60,7 @@ let setDefaultOptions = (htmlElement, inputOptions) => {
55
60
  options.dataUrl ??= htmlElement.dataset.url;
56
61
  options.rtl ??= getRtlOptionFromHTMLElement(htmlElement);
57
62
  options.closedIcon ??= getDefaultClosedIcon(options);
58
- options.openedIcon ??= "&#x25bc;";
63
+ options.openedIcon ??= triangleDown;
59
64
  return options;
60
65
  };
61
66
 
@@ -63,12 +68,7 @@ let setDefaultOptions = (htmlElement, inputOptions) => {
63
68
  let getDefaultAnimationSpeed = () => prefersReducedMotion() ? 0 : defaults.animationSpeed;
64
69
  let prefersReducedMotion = () => typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
65
70
  let getDefaultClosedIcon = options => {
66
- if (options.rtl) {
67
- // triangle to the left
68
- return "&#x25c0;";
69
- }
70
- // triangle to the right
71
- return "&#x25ba;";
71
+ return options.rtl ? triangleLeft : triangleRight;
72
72
  };
73
73
  let getRtlOptionFromHTMLElement = htmlElement => {
74
74
  let dataRtl = htmlElement.dataset.rtl;
@@ -78,5 +78,5 @@ let getRtlOptionFromHTMLElement = htmlElement => {
78
78
  return dataRtl === "false" ? false : Boolean(dataRtl);
79
79
  };
80
80
 
81
- export { setDefaultOptions as default };
81
+ export { setDefaultOptions as default, triangleDown, triangleLeft, triangleRight };
82
82
  //# sourceMappingURL=setDefaultOptions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"setDefaultOptions.js","sources":["../src/setDefaultOptions.ts"],"sourcesContent":["import type { AnimationSpeed } from \"./animation\";\nimport type { TreeElementOptions } from \"./options\";\n\nimport { DEFAULT_CLASS_PREFIX } from \"./classNames\";\nimport { Node } from \"./node\";\n\nconst defaults: TreeElementOptions = {\n animationSpeed: \"fast\",\n autoEscape: true,\n autoOpen: false, // true / false / int (open n levels starting at 0)\n buttonLeft: true,\n classPrefix: DEFAULT_CLASS_PREFIX, // the prefix of all css classes\n // The symbol to use for a closed node - ► BLACK RIGHT-POINTING POINTER\n // https://www.fileformat.info/info/unicode/char/25ba/index.htm\n // closedIcon: undefined,\n // commonClassName: undefined, // the class of every element; the default is \"<classPrefix>-common\"\n // data: undefined,\n // dataFilter: undefined,\n // dataUrl: undefined,\n dragAndDrop: false,\n keyboardSupport: true,\n nodeClass: Node,\n // onCanMove: undefined, // Can this node be moved?\n // onCanMoveTo: undefined, // Can this node be moved to this position? function(moved_node, target_node, position)\n // onCanSelectNode: undefined,\n // onCreateLi: undefined,\n // onDragMove: undefined,\n // onDragStop: undefined,\n // onGetStateFromStorage: undefined,\n // onIsMoveHandle: undefined,\n // onSetStateFromStorage: undefined,\n // openedIcon: undefined,\n openFolderDelay: 500, // The delay for opening a folder during drag and drop; the value is in milliseconds\n // The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE\n // https://www.fileformat.info/info/unicode/char/25bc/index.htm\n // rtl: undefined, // right-to-left support; true / false (default)\n saveState: false, // true / false / string (local storage key; the default key is \"tree\")\n selectable: true,\n showEmptyFolder: false,\n slide: true, // must display slide animation?\n startDndDelay: 300, // The delay for starting dnd (in milliseconds)\n tabIndex: 0,\n // treeClassName: undefined, // the class of the root element; the default is classPrefix\n useContextMenu: true,\n};\n\nconst setDefaultOptions = (\n htmlElement: HTMLElement,\n inputOptions: Partial<TreeElementOptions>,\n): TreeElementOptions => {\n const options = {\n ...defaults,\n ...inputOptions,\n animationSpeed: inputOptions.animationSpeed ?? getDefaultAnimationSpeed(),\n };\n\n options.dataUrl ??= htmlElement.dataset.url;\n options.rtl ??= getRtlOptionFromHTMLElement(htmlElement);\n options.closedIcon ??= getDefaultClosedIcon(options);\n options.openedIcon ??= \"&#x25bc;\";\n\n return options;\n};\n\n// No animation when the user asked the system for reduced motion\nconst getDefaultAnimationSpeed = (): AnimationSpeed =>\n prefersReducedMotion() ? 0 : defaults.animationSpeed;\n\nconst prefersReducedMotion = (): boolean =>\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\nconst getDefaultClosedIcon = (options: TreeElementOptions): string => {\n if (options.rtl) {\n // triangle to the left\n return \"&#x25c0;\";\n }\n // triangle to the right\n return \"&#x25ba;\";\n};\n\nconst getRtlOptionFromHTMLElement = (htmlElement: HTMLElement): boolean => {\n const dataRtl = htmlElement.dataset.rtl;\n\n if (dataRtl == \"\") {\n return true;\n }\n return dataRtl === \"false\" ? false : Boolean(dataRtl);\n};\n\nexport default setDefaultOptions;\n"],"names":[],"mappings":";;;AAMA,IAAM,QAA4B,GAAG;AACnC,EAAA,cAAc,EAAE,MAAM;AACtB,EAAA,UAAU,EAAE,IAAI;AAChB,EAAA,QAAQ,EAAE,KAAK;AAAE;AACjB,EAAA,UAAU,EAAE,IAAI;AAChB,EAAA,WAAW,EAAE,oBAAoB;AAAE;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA,WAAW,EAAE,KAAK;AAClB,EAAA,eAAe,EAAE,IAAI;AACrB,EAAA,SAAS,EAAE,IAAI;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA,eAAe,EAAE,GAAG;AAAE;AACtB;AACA;AACA;AACA,EAAA,SAAS,EAAE,KAAK;AAAE;AAClB,EAAA,UAAU,EAAE,IAAI;AAChB,EAAA,eAAe,EAAE,KAAK;AACtB,EAAA,KAAK,EAAE,IAAI;AAAE;AACb,EAAA,aAAa,EAAE,GAAG;AAAE;AACpB,EAAA,QAAQ,EAAE,CAAC;AACX;AACA,EAAA,cAAc,EAAE;AAClB,CAAC;AAED,IAAM,iBAAiB,GAAG,CACxB,WAAwB,EACxB,YAAyC,KAClB;AACvB,EAAA,IAAM,OAAO,GAAG;AACd,IAAA,GAAG,QAAQ;AACX,IAAA,GAAG,YAAY;AACf,IAAA,cAAc,EAAE,YAAY,CAAC,cAAc,IAAI,wBAAwB;GACxE;AAED,EAAA,OAAO,CAAC,OAAO,KAAK,WAAW,CAAC,OAAO,CAAC,GAAG;AAC3C,EAAA,OAAO,CAAC,GAAG,KAAK,2BAA2B,CAAC,WAAW,CAAC;AACxD,EAAA,OAAO,CAAC,UAAU,KAAK,oBAAoB,CAAC,OAAO,CAAC;EACpD,OAAO,CAAC,UAAU,KAAK,UAAU;AAEjC,EAAA,OAAO,OAAO;AAChB;;AAEA;AACA,IAAM,wBAAwB,GAAG,MAC/B,oBAAoB,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,cAAc;AAEtD,IAAM,oBAAoB,GAAG,MAC3B,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU,IACvC,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,OAAO;AAE/D,IAAM,oBAAoB,GAAI,OAA2B,IAAa;EACpE,IAAI,OAAO,CAAC,GAAG,EAAE;AACf;AACA,IAAA,OAAO,UAAU;AACnB,EAAA;AACA;AACA,EAAA,OAAO,UAAU;AACnB,CAAC;AAED,IAAM,2BAA2B,GAAI,WAAwB,IAAc;AACzE,EAAA,IAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG;EAEvC,IAAI,OAAO,IAAI,EAAE,EAAE;AACjB,IAAA,OAAO,IAAI;AACb,EAAA;EACA,OAAO,OAAO,KAAK,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;AACvD,CAAC;;"}
1
+ {"version":3,"file":"setDefaultOptions.js","sources":["../src/setDefaultOptions.ts"],"sourcesContent":["import type { AnimationSpeed } from \"./animation\";\nimport type { TreeElementOptions } from \"./options\";\n\nimport { DEFAULT_CLASS_PREFIX } from \"./classNames\";\nimport { Node } from \"./node\";\n\n/* The default icons are svg instead of text: the triangle characters come\n * from different fonts on each platform, so they differ in shape and size.\n * They are sized in em to follow the font size, and use currentColor to follow\n * --tree-element-toggler-color.\n */\nconst triangle = (points: string): string =>\n `<svg width=\"0.7em\" height=\"0.7em\" viewBox=\"0 0 10 10\" focusable=\"false\"><polygon points=\"${points}\" fill=\"currentColor\"/></svg>`;\n\nexport const triangleDown = triangle(\"0.5,1.5 9.5,1.5 5,9\");\nexport const triangleLeft = triangle(\"9,0.5 9,9.5 1.5,5\");\nexport const triangleRight = triangle(\"1,0.5 1,9.5 8.5,5\");\n\nconst defaults: TreeElementOptions = {\n animationSpeed: \"fast\",\n autoEscape: true,\n autoOpen: false, // true / false / int (open n levels starting at 0)\n buttonLeft: true,\n classPrefix: DEFAULT_CLASS_PREFIX, // the prefix of all css classes\n // closedIcon: undefined, // the default is a triangle; see getDefaultClosedIcon\n // commonClassName: undefined, // the class of every element; the default is \"<classPrefix>-common\"\n // data: undefined,\n // dataFilter: undefined,\n // dataUrl: undefined,\n dragAndDrop: false,\n keyboardSupport: true,\n nodeClass: Node,\n // onCanMove: undefined, // Can this node be moved?\n // onCanMoveTo: undefined, // Can this node be moved to this position? function(moved_node, target_node, position)\n // onCanSelectNode: undefined,\n // onCreateLi: undefined,\n // onDragMove: undefined,\n // onDragStop: undefined,\n // onGetStateFromStorage: undefined,\n // onIsMoveHandle: undefined,\n // onSetStateFromStorage: undefined,\n // openedIcon: undefined, // the default is a triangle pointing down\n openFolderDelay: 500, // The delay for opening a folder during drag and drop; the value is in milliseconds\n // rtl: undefined, // right-to-left support; true / false (default)\n saveState: false, // true / false / string (local storage key; the default key is \"tree\")\n selectable: true,\n showEmptyFolder: false,\n slide: true, // must display slide animation?\n startDndDelay: 300, // The delay for starting dnd (in milliseconds)\n tabIndex: 0,\n // treeClassName: undefined, // the class of the root element; the default is classPrefix\n useContextMenu: true,\n};\n\nconst setDefaultOptions = (\n htmlElement: HTMLElement,\n inputOptions: Partial<TreeElementOptions>,\n): TreeElementOptions => {\n const options = {\n ...defaults,\n ...inputOptions,\n animationSpeed: inputOptions.animationSpeed ?? getDefaultAnimationSpeed(),\n };\n\n options.dataUrl ??= htmlElement.dataset.url;\n options.rtl ??= getRtlOptionFromHTMLElement(htmlElement);\n options.closedIcon ??= getDefaultClosedIcon(options);\n options.openedIcon ??= triangleDown;\n\n return options;\n};\n\n// No animation when the user asked the system for reduced motion\nconst getDefaultAnimationSpeed = (): AnimationSpeed =>\n prefersReducedMotion() ? 0 : defaults.animationSpeed;\n\nconst prefersReducedMotion = (): boolean =>\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\nconst getDefaultClosedIcon = (options: TreeElementOptions): string => {\n return options.rtl ? triangleLeft : triangleRight;\n};\n\nconst getRtlOptionFromHTMLElement = (htmlElement: HTMLElement): boolean => {\n const dataRtl = htmlElement.dataset.rtl;\n\n if (dataRtl == \"\") {\n return true;\n }\n return dataRtl === \"false\" ? false : Boolean(dataRtl);\n};\n\nexport default setDefaultOptions;\n"],"names":[],"mappings":";;;AAMA;AACA;AACA;AACA;AACA;AACA,IAAM,QAAQ,GAAI,MAAc,IAC9B,CAAA,yFAAA,EAA4F,MAAM,CAAA,6BAAA,CAA+B;IAEtH,YAAY,GAAG,QAAQ,CAAC,qBAAqB;IAC7C,YAAY,GAAG,QAAQ,CAAC,mBAAmB;IAC3C,aAAa,GAAG,QAAQ,CAAC,mBAAmB;AAEzD,IAAM,QAA4B,GAAG;AACnC,EAAA,cAAc,EAAE,MAAM;AACtB,EAAA,UAAU,EAAE,IAAI;AAChB,EAAA,QAAQ,EAAE,KAAK;AAAE;AACjB,EAAA,UAAU,EAAE,IAAI;AAChB,EAAA,WAAW,EAAE,oBAAoB;AAAE;AACnC;AACA;AACA;AACA;AACA;AACA,EAAA,WAAW,EAAE,KAAK;AAClB,EAAA,eAAe,EAAE,IAAI;AACrB,EAAA,SAAS,EAAE,IAAI;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA,eAAe,EAAE,GAAG;AAAE;AACtB;AACA,EAAA,SAAS,EAAE,KAAK;AAAE;AAClB,EAAA,UAAU,EAAE,IAAI;AAChB,EAAA,eAAe,EAAE,KAAK;AACtB,EAAA,KAAK,EAAE,IAAI;AAAE;AACb,EAAA,aAAa,EAAE,GAAG;AAAE;AACpB,EAAA,QAAQ,EAAE,CAAC;AACX;AACA,EAAA,cAAc,EAAE;AAClB,CAAC;AAED,IAAM,iBAAiB,GAAG,CACxB,WAAwB,EACxB,YAAyC,KAClB;AACvB,EAAA,IAAM,OAAO,GAAG;AACd,IAAA,GAAG,QAAQ;AACX,IAAA,GAAG,YAAY;AACf,IAAA,cAAc,EAAE,YAAY,CAAC,cAAc,IAAI,wBAAwB;GACxE;AAED,EAAA,OAAO,CAAC,OAAO,KAAK,WAAW,CAAC,OAAO,CAAC,GAAG;AAC3C,EAAA,OAAO,CAAC,GAAG,KAAK,2BAA2B,CAAC,WAAW,CAAC;AACxD,EAAA,OAAO,CAAC,UAAU,KAAK,oBAAoB,CAAC,OAAO,CAAC;EACpD,OAAO,CAAC,UAAU,KAAK,YAAY;AAEnC,EAAA,OAAO,OAAO;AAChB;;AAEA;AACA,IAAM,wBAAwB,GAAG,MAC/B,oBAAoB,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,cAAc;AAEtD,IAAM,oBAAoB,GAAG,MAC3B,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU,IACvC,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,OAAO;AAE/D,IAAM,oBAAoB,GAAI,OAA2B,IAAa;AACpE,EAAA,OAAO,OAAO,CAAC,GAAG,GAAG,YAAY,GAAG,aAAa;AACnD,CAAC;AAED,IAAM,2BAA2B,GAAI,WAAwB,IAAc;AACzE,EAAA,IAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG;EAEvC,IAAI,OAAO,IAAI,EAAE,EAAE;AACjB,IAAA,OAAO,IAAI;AACb,EAAA;EACA,OAAO,OAAO,KAAK,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;AACvD,CAAC;;"}
package/lib/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- declare const version = "0.3.0";
1
+ declare const version = "0.3.1";
2
2
  export default version;
3
3
  //# sourceMappingURL=version.d.ts.map
package/lib/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Generated by config/generateVersion.mjs. Do not edit.
2
- let version = "0.3.0";
2
+ let version = "0.3.1";
3
3
 
4
4
  export { version as default };
5
5
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["// Generated by config/generateVersion.mjs. Do not edit.\nconst version = \"0.3.0\";\n\nexport default version;\n"],"names":[],"mappings":"AAAA;AACA,IAAM,OAAO,GAAG;;"}
1
+ {"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["// Generated by config/generateVersion.mjs. Do not edit.\nconst version = \"0.3.1\";\n\nexport default version;\n"],"names":[],"mappings":"AAAA;AACA,IAAM,OAAO,GAAG;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-element",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Tree widget in plain javascript",
5
5
  "keywords": [
6
6
  "tree"
@@ -63,13 +63,13 @@
63
63
  "devDependencies": {
64
64
  "@axe-core/playwright": "^4.13.0",
65
65
  "@babel/cli": "^8.0.6",
66
- "@babel/core": "^8.0.6",
67
- "@babel/preset-env": "^8.0.6",
68
- "@babel/preset-typescript": "^8.0.1",
66
+ "@babel/core": "^8.0.7",
67
+ "@babel/preset-env": "^8.0.7",
68
+ "@babel/preset-typescript": "^8.0.7",
69
69
  "@cspell/eslint-plugin": "^10.3.6",
70
70
  "@eslint/css": "^2.0.0",
71
71
  "@eslint/js": "^10.0.1",
72
- "@playwright/test": "^1.63.0",
72
+ "@playwright/test": "^1.64.0",
73
73
  "@rollup/plugin-babel": "^7.1.0",
74
74
  "@rollup/plugin-node-resolve": "^16.0.3",
75
75
  "@rollup/plugin-terser": "^1.0.0",
@@ -77,12 +77,12 @@
77
77
  "@testing-library/jest-dom": "^7.0.1",
78
78
  "@testing-library/user-event": "^14.6.7",
79
79
  "@types/debug": "^4.1.13",
80
- "@types/node": "^26.6.4",
80
+ "@types/node": "^26.6.5",
81
81
  "@vitest/coverage-istanbul": "^5.0.3",
82
82
  "@vitest/eslint-plugin": "^1.6.27",
83
- "axe-core": "^4.13.0",
83
+ "axe-core": "^4.14.0",
84
84
  "babel-plugin-istanbul": "^8.0.0",
85
- "babel-plugin-prefix-private-members": "^0.3.0",
85
+ "babel-plugin-prefix-private-members": "^0.3.1",
86
86
  "eslint": "^10.12.0",
87
87
  "eslint-import-resolver-typescript": "^4.4.5",
88
88
  "eslint-plugin-compat": "^7.0.2",
@@ -91,32 +91,32 @@
91
91
  "eslint-plugin-jest-extended": "github:mbraak/eslint-plugin-jest-extended#modernize",
92
92
  "eslint-plugin-no-unsanitized": "^4.1.5",
93
93
  "eslint-plugin-perfectionist": "^5.12.1",
94
- "eslint-plugin-playwright": "^2.12.0",
94
+ "eslint-plugin-playwright": "^2.12.1",
95
95
  "eslint-plugin-testing-library": "^7.16.2",
96
96
  "eslint-plugin-tsdoc": "^0.5.4",
97
97
  "eslint-plugin-unicorn": "^77.0.0",
98
98
  "jest-extended": "^7.0.0",
99
- "jsdom": "^30.1.1",
99
+ "jsdom": "^30.1.2",
100
100
  "jsdom-testing-mocks": "^1.16.0",
101
101
  "jsonfile": "^6.2.1",
102
102
  "kiira": "^0.6.0",
103
103
  "kiira-core": "^0.6.0",
104
104
  "lodash": "^4.18.1",
105
- "msw": "^3.0.2",
106
- "postcss": "^8.5.28",
105
+ "msw": "^3.0.3",
106
+ "postcss": "^8.5.29",
107
107
  "postcss-cli": "^12.0.0",
108
108
  "postcss-import": "^17.0.0",
109
109
  "postcss-load-config": "^6.0.1",
110
110
  "postcss-nested": "^8.0.1",
111
- "prettier": "^3.9.9",
112
- "rollup": "^4.64.0",
111
+ "prettier": "^3.9.10",
112
+ "rollup": "^4.64.5",
113
113
  "rollup-plugin-serve": "^3.0.0",
114
114
  "rollup-plugin-tsconfig-paths": "^1.5.2",
115
115
  "tslib": "^2.8.1",
116
116
  "typedoc": "^0.28.20",
117
117
  "typedoc-plugin-markdown": "^4.13.1",
118
118
  "typescript": "^6.0.3",
119
- "typescript-eslint": "^8.71.0",
119
+ "typescript-eslint": "^8.71.1",
120
120
  "vitepress": "^1.6.4",
121
121
  "vitest": "^5.0.3"
122
122
  }
package/src/options.ts CHANGED
@@ -97,8 +97,8 @@ export interface TreeElementOptions {
97
97
  *
98
98
  * Type: `HTMLElement | string`
99
99
  *
100
- * @defaultValue `"&#x25ba;"` (`►`), or `"&#x25c0;"` (`◀`) when `rtl` is
101
- * true.
100
+ * @defaultValue An svg triangle pointing right, or left when `rtl` is
101
+ * true. It is sized in em and filled with `currentColor`.
102
102
  * @group Appearance
103
103
  */
104
104
  closedIcon?: IconElement;
@@ -258,7 +258,8 @@ export interface TreeElementOptions {
258
258
  *
259
259
  * Type: `HTMLElement | string`
260
260
  *
261
- * @defaultValue `"&#x25bc;"` (`▼`)
261
+ * @defaultValue An svg triangle pointing down, sized in em and filled with
262
+ * `currentColor`.
262
263
  * @group Appearance
263
264
  */
264
265
  openedIcon?: IconElement;
package/src/requestUrl.ts CHANGED
@@ -1,23 +1,11 @@
1
- // Url class for absolute and relative urls.
2
-
3
- const isAbsoluteUrl = (inputUrl: string) => {
4
- return URL.canParse(inputUrl);
5
- };
6
-
7
- const LOCALHOST = "http://localhost";
1
+ // Url of a request. A relative url is resolved against the page, like a link
2
+ // or `fetch` would, so it also works when the page is in a subdirectory.
8
3
 
9
4
  class RequestUrl {
10
- private isAbsolute: boolean;
11
5
  private url: URL;
12
6
 
13
7
  constructor(inputUrl: string) {
14
- if (isAbsoluteUrl(inputUrl)) {
15
- this.url = new URL(inputUrl);
16
- this.isAbsolute = true;
17
- } else {
18
- this.url = new URL(inputUrl, LOCALHOST);
19
- this.isAbsolute = false;
20
- }
8
+ this.url = new URL(inputUrl, document.baseURI);
21
9
  }
22
10
 
23
11
  setSearchParam(key: string, value: string) {
@@ -25,9 +13,7 @@ class RequestUrl {
25
13
  }
26
14
 
27
15
  value() {
28
- return this.isAbsolute
29
- ? this.url.href
30
- : this.url.href.slice(LOCALHOST.length);
16
+ return this.url.href;
31
17
  }
32
18
  }
33
19
 
@@ -4,15 +4,25 @@ import type { TreeElementOptions } from "./options";
4
4
  import { DEFAULT_CLASS_PREFIX } from "./classNames";
5
5
  import { Node } from "./node";
6
6
 
7
+ /* The default icons are svg instead of text: the triangle characters come
8
+ * from different fonts on each platform, so they differ in shape and size.
9
+ * They are sized in em to follow the font size, and use currentColor to follow
10
+ * --tree-element-toggler-color.
11
+ */
12
+ const triangle = (points: string): string =>
13
+ `<svg width="0.7em" height="0.7em" viewBox="0 0 10 10" focusable="false"><polygon points="${points}" fill="currentColor"/></svg>`;
14
+
15
+ export const triangleDown = triangle("0.5,1.5 9.5,1.5 5,9");
16
+ export const triangleLeft = triangle("9,0.5 9,9.5 1.5,5");
17
+ export const triangleRight = triangle("1,0.5 1,9.5 8.5,5");
18
+
7
19
  const defaults: TreeElementOptions = {
8
20
  animationSpeed: "fast",
9
21
  autoEscape: true,
10
22
  autoOpen: false, // true / false / int (open n levels starting at 0)
11
23
  buttonLeft: true,
12
24
  classPrefix: DEFAULT_CLASS_PREFIX, // the prefix of all css classes
13
- // The symbol to use for a closed node - ► BLACK RIGHT-POINTING POINTER
14
- // https://www.fileformat.info/info/unicode/char/25ba/index.htm
15
- // closedIcon: undefined,
25
+ // closedIcon: undefined, // the default is a triangle; see getDefaultClosedIcon
16
26
  // commonClassName: undefined, // the class of every element; the default is "<classPrefix>-common"
17
27
  // data: undefined,
18
28
  // dataFilter: undefined,
@@ -29,10 +39,8 @@ const defaults: TreeElementOptions = {
29
39
  // onGetStateFromStorage: undefined,
30
40
  // onIsMoveHandle: undefined,
31
41
  // onSetStateFromStorage: undefined,
32
- // openedIcon: undefined,
42
+ // openedIcon: undefined, // the default is a triangle pointing down
33
43
  openFolderDelay: 500, // The delay for opening a folder during drag and drop; the value is in milliseconds
34
- // The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE
35
- // https://www.fileformat.info/info/unicode/char/25bc/index.htm
36
44
  // rtl: undefined, // right-to-left support; true / false (default)
37
45
  saveState: false, // true / false / string (local storage key; the default key is "tree")
38
46
  selectable: true,
@@ -57,7 +65,7 @@ const setDefaultOptions = (
57
65
  options.dataUrl ??= htmlElement.dataset.url;
58
66
  options.rtl ??= getRtlOptionFromHTMLElement(htmlElement);
59
67
  options.closedIcon ??= getDefaultClosedIcon(options);
60
- options.openedIcon ??= "&#x25bc;";
68
+ options.openedIcon ??= triangleDown;
61
69
 
62
70
  return options;
63
71
  };
@@ -71,12 +79,7 @@ const prefersReducedMotion = (): boolean =>
71
79
  window.matchMedia("(prefers-reduced-motion: reduce)").matches;
72
80
 
73
81
  const getDefaultClosedIcon = (options: TreeElementOptions): string => {
74
- if (options.rtl) {
75
- // triangle to the left
76
- return "&#x25c0;";
77
- }
78
- // triangle to the right
79
- return "&#x25ba;";
82
+ return options.rtl ? triangleLeft : triangleRight;
80
83
  };
81
84
 
82
85
  const getRtlOptionFromHTMLElement = (htmlElement: HTMLElement): boolean => {
package/src/version.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  // Generated by config/generateVersion.mjs. Do not edit.
2
- const version = "0.3.0";
2
+ const version = "0.3.1";
3
3
 
4
4
  export default version;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Tree-element 0.3.0
2
+ Tree-element 0.3.1
3
3
 
4
4
  Copyright 2026 Marco Braak
5
5
 
@@ -2426,27 +2426,18 @@ var TreeElement = (function () {
2426
2426
  }
2427
2427
  }
2428
2428
 
2429
- // Url class for absolute and relative urls.
2429
+ // Url of a request. A relative url is resolved against the page, like a link
2430
+ // or `fetch` would, so it also works when the page is in a subdirectory.
2430
2431
 
2431
- let isAbsoluteUrl = inputUrl => {
2432
- return URL.canParse(inputUrl);
2433
- };
2434
- let LOCALHOST = "http://localhost";
2435
2432
  class RequestUrl {
2436
2433
  constructor(inputUrl) {
2437
- if (isAbsoluteUrl(inputUrl)) {
2438
- this._url = new URL(inputUrl);
2439
- this._isAbsolute = true;
2440
- } else {
2441
- this._url = new URL(inputUrl, LOCALHOST);
2442
- this._isAbsolute = false;
2443
- }
2434
+ this._url = new URL(inputUrl, document.baseURI);
2444
2435
  }
2445
2436
  _setSearchParam(key, value) {
2446
2437
  this._url.searchParams.set(key, value);
2447
2438
  }
2448
2439
  _value() {
2449
- return this._isAbsolute ? this._url.href : this._url.href.slice(LOCALHOST.length);
2440
+ return this._url.href;
2450
2441
  }
2451
2442
  }
2452
2443
 
@@ -2998,6 +2989,15 @@ var TreeElement = (function () {
2998
2989
  }
2999
2990
  }
3000
2991
 
2992
+ /* The default icons are svg instead of text: the triangle characters come
2993
+ * from different fonts on each platform, so they differ in shape and size.
2994
+ * They are sized in em to follow the font size, and use currentColor to follow
2995
+ * --tree-element-toggler-color.
2996
+ */
2997
+ let triangle = points => `<svg width="0.7em" height="0.7em" viewBox="0 0 10 10" focusable="false"><polygon points="${points}" fill="currentColor"/></svg>`;
2998
+ let triangleDown = triangle("0.5,1.5 9.5,1.5 5,9");
2999
+ let triangleLeft = triangle("9,0.5 9,9.5 1.5,5");
3000
+ let triangleRight = triangle("1,0.5 1,9.5 8.5,5");
3001
3001
  let defaults = {
3002
3002
  animationSpeed: "fast",
3003
3003
  autoEscape: true,
@@ -3006,9 +3006,7 @@ var TreeElement = (function () {
3006
3006
  buttonLeft: true,
3007
3007
  classPrefix: DEFAULT_CLASS_PREFIX,
3008
3008
  // the prefix of all css classes
3009
- // The symbol to use for a closed node - ► BLACK RIGHT-POINTING POINTER
3010
- // https://www.fileformat.info/info/unicode/char/25ba/index.htm
3011
- // closedIcon: undefined,
3009
+ // closedIcon: undefined, // the default is a triangle; see getDefaultClosedIcon
3012
3010
  // commonClassName: undefined, // the class of every element; the default is "<classPrefix>-common"
3013
3011
  // data: undefined,
3014
3012
  // dataFilter: undefined,
@@ -3025,11 +3023,9 @@ var TreeElement = (function () {
3025
3023
  // onGetStateFromStorage: undefined,
3026
3024
  // onIsMoveHandle: undefined,
3027
3025
  // onSetStateFromStorage: undefined,
3028
- // openedIcon: undefined,
3026
+ // openedIcon: undefined, // the default is a triangle pointing down
3029
3027
  openFolderDelay: 500,
3030
3028
  // The delay for opening a folder during drag and drop; the value is in milliseconds
3031
- // The symbol to use for an open node - ▼ BLACK DOWN-POINTING TRIANGLE
3032
- // https://www.fileformat.info/info/unicode/char/25bc/index.htm
3033
3029
  // rtl: undefined, // right-to-left support; true / false (default)
3034
3030
  saveState: false,
3035
3031
  // true / false / string (local storage key; the default key is "tree")
@@ -3052,7 +3048,7 @@ var TreeElement = (function () {
3052
3048
  options.dataUrl ??= htmlElement.dataset.url;
3053
3049
  options.rtl ??= getRtlOptionFromHTMLElement(htmlElement);
3054
3050
  options.closedIcon ??= getDefaultClosedIcon(options);
3055
- options.openedIcon ??= "&#x25bc;";
3051
+ options.openedIcon ??= triangleDown;
3056
3052
  return options;
3057
3053
  };
3058
3054
 
@@ -3060,12 +3056,7 @@ var TreeElement = (function () {
3060
3056
  let getDefaultAnimationSpeed = () => prefersReducedMotion() ? 0 : defaults.animationSpeed;
3061
3057
  let prefersReducedMotion = () => typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
3062
3058
  let getDefaultClosedIcon = options => {
3063
- if (options.rtl) {
3064
- // triangle to the left
3065
- return "&#x25c0;";
3066
- }
3067
- // triangle to the right
3068
- return "&#x25ba;";
3059
+ return options.rtl ? triangleLeft : triangleRight;
3069
3060
  };
3070
3061
  let getRtlOptionFromHTMLElement = htmlElement => {
3071
3062
  let dataRtl = htmlElement.dataset.rtl;
@@ -3087,7 +3078,7 @@ var TreeElement = (function () {
3087
3078
  };
3088
3079
 
3089
3080
  // Generated by config/generateVersion.mjs. Do not edit.
3090
- let version = "0.3.0";
3081
+ let version = "0.3.1";
3091
3082
 
3092
3083
  // The types that appear in the public api. Consumers cannot import them from
3093
3084
  // the submodules directly, because those are not exposed in package.json.