bruh 1.13.1 → 2.0.0-beta.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.
Files changed (84) hide show
  1. package/dist/browser/jsx-runtime.mjs +2 -0
  2. package/dist/browser/jsx-runtime.mjs.map +1 -0
  3. package/dist/browser.mjs +174 -0
  4. package/dist/browser.mjs.map +1 -0
  5. package/dist/cli/node.mjs +16 -0
  6. package/dist/cli/node.mjs.map +1 -0
  7. package/dist/components/aside-toc.mjs +162 -0
  8. package/dist/components/aside-toc.mjs.map +1 -0
  9. package/dist/components/custom-elements.mjs +52 -0
  10. package/dist/components/custom-elements.mjs.map +1 -0
  11. package/dist/components/intl/date-time.mjs +219 -0
  12. package/dist/components/intl/date-time.mjs.map +1 -0
  13. package/dist/components/intl/display-name.mjs +71 -0
  14. package/dist/components/intl/display-name.mjs.map +1 -0
  15. package/dist/components/intl/language-picker.mjs +102 -0
  16. package/dist/components/intl/language-picker.mjs.map +1 -0
  17. package/dist/components/intl/list.mjs +80 -0
  18. package/dist/components/intl/list.mjs.map +1 -0
  19. package/dist/components/intl/number.mjs +118 -0
  20. package/dist/components/intl/number.mjs.map +1 -0
  21. package/dist/components/intl/plural.mjs +82 -0
  22. package/dist/components/intl/plural.mjs.map +1 -0
  23. package/dist/components/intl/utils.mjs +197 -0
  24. package/dist/components/intl/utils.mjs.map +1 -0
  25. package/dist/components/optimized-picture/hydrate.mjs +10 -0
  26. package/dist/components/optimized-picture/hydrate.mjs.map +1 -0
  27. package/dist/components/optimized-picture/server.mjs +28 -0
  28. package/dist/components/optimized-picture/server.mjs.map +1 -0
  29. package/dist/components/utils.mjs +4 -0
  30. package/dist/components/utils.mjs.map +1 -0
  31. package/dist/media/images/node.mjs +41 -0
  32. package/dist/media/images/node.mjs.map +1 -0
  33. package/dist/polyfills/weakref.mjs +16 -0
  34. package/dist/polyfills/weakref.mjs.map +1 -0
  35. package/dist/reactive/sync/transport/websocket/browser.mjs +52 -0
  36. package/dist/reactive/sync/transport/websocket/browser.mjs.map +1 -0
  37. package/dist/reactive.mjs +160 -0
  38. package/dist/reactive.mjs.map +1 -0
  39. package/dist/server/jsx-runtime.mjs +2 -0
  40. package/dist/server/jsx-runtime.mjs.map +1 -0
  41. package/dist/server.mjs +346 -0
  42. package/dist/server.mjs.map +1 -0
  43. package/dist/types/cli/index.d.mts +2 -0
  44. package/dist/types/components/aside-toc/index.d.ts +45 -0
  45. package/dist/types/components/custom-elements.d.mts +83 -0
  46. package/dist/types/components/intl/date-time.d.ts +138 -0
  47. package/dist/types/components/intl/display-name.d.ts +45 -0
  48. package/dist/types/components/intl/language-picker.d.ts +35 -0
  49. package/dist/types/components/intl/list.d.ts +41 -0
  50. package/dist/types/components/intl/number.d.ts +81 -0
  51. package/dist/types/components/intl/plural.d.ts +60 -0
  52. package/dist/types/components/intl/utils.d.mts +30 -0
  53. package/dist/types/components/optimized-picture/hydrate.d.mts +2 -0
  54. package/dist/types/components/optimized-picture/server.d.ts +8 -0
  55. package/dist/types/components/utils.d.mts +5 -0
  56. package/dist/types/dom/browser/jsx-runtime.d.mts +3 -0
  57. package/dist/types/dom/index.browser.d.mts +127 -0
  58. package/dist/types/dom/index.server.d.mts +174 -0
  59. package/dist/types/dom/server/jsx-runtime.d.mts +3 -0
  60. package/dist/types/dom/types.d.mts +9 -0
  61. package/dist/types/media/images.node.d.mts +1 -0
  62. package/dist/types/polyfills/weakref.d.mts +4 -0
  63. package/dist/types/reactive/index.d.mts +91 -0
  64. package/dist/types/reactive/sync/transport/websocket/browser.d.mts +11 -0
  65. package/dist/types/utils/browser.d.mts +2 -0
  66. package/dist/types/utils/index.d.mts +122 -0
  67. package/dist/utils/browser.mjs +27 -0
  68. package/dist/utils/browser.mjs.map +1 -0
  69. package/dist/utils.mjs +287 -0
  70. package/dist/utils.mjs.map +1 -0
  71. package/package.json +122 -19
  72. package/dist/bruh.es.js +0 -226
  73. package/dist/bruh.es.js.map +0 -1
  74. package/dist/bruh.umd.js +0 -2
  75. package/dist/bruh.umd.js.map +0 -1
  76. package/src/cli/index.mjs +0 -19
  77. package/src/components/optimized-picture/hydrate.mjs +0 -10
  78. package/src/components/optimized-picture/render.mjs +0 -26
  79. package/src/dom/index.browser.mjs +0 -270
  80. package/src/dom/index.server.mjs +0 -280
  81. package/src/index.browser.mjs +0 -3
  82. package/src/media/images.node.mjs +0 -70
  83. package/src/reactive/index.mjs +0 -160
  84. package/src/util/index.mjs +0 -42
@@ -0,0 +1,2 @@
1
+ export { Fragment, jsx, jsx as jsxDEV, jsx as jsxs } from '../browser.mjs';
2
+ //# sourceMappingURL=jsx-runtime.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx-runtime.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,174 @@
1
+ import { isReactive, reactiveDo } from './reactive.mjs';
2
+
3
+ const terminalBruhChildToNode = (child) => {
4
+ if (child instanceof Node)
5
+ return child;
6
+ else if (child == null || typeof child === "boolean")
7
+ return document.createComment(child + "");
8
+ else
9
+ return document.createTextNode(child + "");
10
+ };
11
+ const reactiveTerminalBruhChildToNode = (child) => {
12
+ let node = terminalBruhChildToNode(child.value);
13
+ const stopReacting = child.addReaction(() => {
14
+ if (!node.parentNode) {
15
+ stopReacting();
16
+ return;
17
+ }
18
+ const oldNode = node;
19
+ const child_ = child;
20
+ if (child.value != null && typeof child.value === "object" && Symbol.iterator in child.value) {
21
+ stopReacting();
22
+ oldNode.replaceWith(...reactiveIterableBruhChildToNodes(child_));
23
+ } else {
24
+ node = terminalBruhChildToNode(child_.value);
25
+ oldNode.replaceWith(node);
26
+ }
27
+ });
28
+ return node;
29
+ };
30
+ function* reactiveIterableBruhChildToNodes(child) {
31
+ const first = document.createComment("[");
32
+ const last = document.createComment("]");
33
+ const stopReacting = child.addReaction(() => {
34
+ if (!first.parentNode) {
35
+ stopReacting();
36
+ return;
37
+ }
38
+ const range = document.createRange();
39
+ range.setStartAfter(first);
40
+ if (child.value != null && typeof child.value === "object" && Symbol.iterator in child.value) {
41
+ const child_ = child;
42
+ range.setEndBefore(last);
43
+ range.deleteContents();
44
+ first.after(...bruhChildrenToNodes(child_.value));
45
+ } else {
46
+ const child_ = child;
47
+ stopReacting();
48
+ range.setEndAfter(last);
49
+ range.deleteContents();
50
+ first.replaceWith(reactiveTerminalBruhChildToNode(child_));
51
+ }
52
+ });
53
+ yield first;
54
+ yield* bruhChildrenToNodes(child.value);
55
+ yield last;
56
+ }
57
+ function* bruhChildrenToNodes(children) {
58
+ const partiallyFlattened = Array.isArray(children) ? children.flat(Infinity) : children;
59
+ for (const child of partiallyFlattened) {
60
+ if (!isReactive(child)) {
61
+ if (child != null && typeof child === "object" && Symbol.iterator in child)
62
+ yield* bruhChildrenToNodes(child);
63
+ else
64
+ yield terminalBruhChildToNode(child);
65
+ } else {
66
+ if (child.value != null && typeof child.value === "object" && Symbol.iterator in child.value)
67
+ yield* reactiveIterableBruhChildToNodes(child);
68
+ else
69
+ yield reactiveTerminalBruhChildToNode(child);
70
+ }
71
+ }
72
+ }
73
+ const isElementWithStyle = (element) => (
74
+ // @ts-ignore
75
+ element.style instanceof CSSStyleDeclaration
76
+ );
77
+ const applyStyles = (element, styles) => {
78
+ for (const property in styles) {
79
+ const property_ = property;
80
+ reactiveDo(styles[property_], (value) => {
81
+ if (value != null && typeof value !== "boolean")
82
+ element.style.setProperty(property, value + "");
83
+ else
84
+ element.style.removeProperty(property);
85
+ });
86
+ }
87
+ };
88
+ const applyClasses = (element, classes) => {
89
+ for (const name in classes)
90
+ reactiveDo(classes[name], (value) => {
91
+ element.classList.toggle(name, value === true);
92
+ });
93
+ };
94
+ const applyAttributes = (element, attributes) => {
95
+ for (const name in attributes)
96
+ reactiveDo(attributes[name], (value) => {
97
+ if (typeof value === "boolean")
98
+ element.toggleAttribute(name, value);
99
+ else if (value != null)
100
+ element.setAttribute(name, value + "");
101
+ else
102
+ element.removeAttribute(name);
103
+ });
104
+ };
105
+ const t = (textContent) => {
106
+ if (!isReactive(textContent))
107
+ return document.createTextNode(textContent + "");
108
+ const node = document.createTextNode(textContent.value + "");
109
+ textContent.addReaction(() => {
110
+ node.textContent = textContent.value + "";
111
+ });
112
+ return node;
113
+ };
114
+ const jsx = (nameOrComponent, props_, key) => {
115
+ if (key !== void 0)
116
+ props_.key = key;
117
+ if (typeof nameOrComponent !== "string") {
118
+ const component = nameOrComponent;
119
+ const props2 = props_;
120
+ return component(props2);
121
+ }
122
+ const name = nameOrComponent;
123
+ const props = props_;
124
+ let options = {};
125
+ if (typeof props.bruh === "object" && !isReactive(props.bruh)) {
126
+ options = props.bruh;
127
+ delete props.bruh;
128
+ }
129
+ const { namespace } = options;
130
+ const element = namespace ? document.createElementNS(namespace, name) : document.createElement(name);
131
+ if ("children" in props) {
132
+ element.append(
133
+ ...bruhChildrenToNodes(
134
+ props.children != null && typeof props.children === "object" && Symbol.iterator in props.children ? props.children : [props.children]
135
+ )
136
+ );
137
+ delete props.children;
138
+ }
139
+ if ("style" in props && props.style != null && typeof props.style === "object" && !isReactive(props.style) && isElementWithStyle(element)) {
140
+ applyStyles(element, props.style);
141
+ delete props.style;
142
+ }
143
+ if ("class" in props && props.class != null && typeof props.class === "object" && !isReactive(props.class)) {
144
+ applyClasses(element, props.class);
145
+ delete props.class;
146
+ }
147
+ for (const name_ in props) {
148
+ const name2 = name_;
149
+ if (typeof props[name2] === "function" && name2.startsWith("on")) {
150
+ element.addEventListener(name2.slice(2), props[name2]);
151
+ delete props[name2];
152
+ }
153
+ }
154
+ applyAttributes(element, props);
155
+ return element;
156
+ };
157
+ const Fragment = (props) => props.children;
158
+ class BruhText extends HTMLElement {
159
+ static hydrated = {};
160
+ constructor() {
161
+ super();
162
+ const textNode = document.createTextNode(this.textContent);
163
+ const tag = this.getAttribute("tag");
164
+ if (tag) {
165
+ const set = BruhText.hydrated[tag] ??= /* @__PURE__ */ new Set();
166
+ set.add(textNode);
167
+ }
168
+ this.replaceWith(textNode);
169
+ }
170
+ }
171
+ customElements.define("bruh-text", BruhText);
172
+
173
+ export { BruhText, Fragment, applyAttributes, applyClasses, applyStyles, bruhChildrenToNodes, jsx, t };
174
+ //# sourceMappingURL=browser.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.mjs","sources":["../src/dom/index.browser.mts"],"sourcesContent":["import { isReactive, reactiveDo } from \"../reactive/index.mts\"\nimport type { Reactive, MaybeReactive } from \"../reactive/index.mts\"\nimport type {\n PropertyWiseOr,\n LikelyAsString,\n LikelyAsAbsent,\n LikelyAsBoolean\n} from \"./types.mts\"\nimport type { PropertiesHyphen as Styles } from \"csstype\"\nimport type {\n ElementType,\n\n HTMLTag,\n SVGTag,\n MathMLTag,\n\n Namespace,\n HTMLNamespace,\n SVGNamespace,\n MathMLNamespace,\n\n ElementToEventMap,\n ElementToAttributes\n} from \"html-info\"\n\nexport type TerminalBruhChild =\n | Node\n | LikelyAsString\n | LikelyAsAbsent\n\nexport type TerminalBruhChildOutputNode<Child extends TerminalBruhChild>\n = Child extends Node\n ? Child\n : Child extends LikelyAsString\n ? Text\n : Child extends LikelyAsAbsent\n ? Comment\n : Node\n\n// disallow a reactive from directly holding a reactive\nexport type FlatBruhChild =\n | MaybeReactive<TerminalBruhChild>\n | Reactive<TerminalBruhChild | Iterable<BruhChild>>\n\nexport type BruhChild =\n | FlatBruhChild\n | Iterable<BruhChild>\n\nexport type StylesToApply = {\n [Property in keyof Styles]: MaybeReactive<Styles[Property] | LikelyAsAbsent>\n}\n\nexport interface ClassesToApply {\n [className: string]: MaybeReactive<LikelyAsBoolean>\n}\n\nexport type AttributesToApply<\n Name extends string,\n NS extends Namespace = HTMLNamespace\n> = {\n [Attribute in keyof ElementToAttributes<Name, NS>]?:\n MaybeReactive<ElementToAttributes<Name, NS>[Attribute] | LikelyAsBoolean>\n}\n\ntype EventMapToListenerProps<EventMap> = {\n [E in ((keyof EventMap) & string) as `on${E}`]:\n (event: EventMap[E]) => void\n}\n\ntype AttributeMapToProps<AttributeMap> = {\n [Attribute in keyof AttributeMap]:\n MaybeReactive<AttributeMap[Attribute] | LikelyAsBoolean>\n | ( Attribute extends \"style\"\n ? StylesToApply\n : Attribute extends \"class\"\n ? ClassesToApply\n : never\n )\n}\n\nexport interface BruhOptions {\n namespace?: Namespace\n}\n\ninterface BaseBruhProps {\n bruh?: BruhOptions,\n children?: BruhChild\n}\n\nexport type BruhProps<\n Name extends string,\n NS extends string = HTMLNamespace\n>\n = BaseBruhProps\n & (\n NS extends HTMLNamespace\n ? { bruh?: { namespace?: HTMLNamespace } }\n : { bruh: { namespace: NS } }\n )\n & Partial<\n EventMapToListenerProps<ElementToEventMap<Name, NS>> &\n AttributeMapToProps<ElementToAttributes<Name, NS>>\n >\n\nexport type HTMLTagToBruhProps = { [Name in HTMLTag]: BruhProps<Name, HTMLNamespace> }\nexport type SVGTagToBruhProps = { [Name in SVGTag]: BruhProps<Name, SVGNamespace> }\nexport type MathMLTagToBruhProps = { [Name in MathMLTag]: BruhProps<Name, MathMLNamespace> }\n\nexport type TagToBruhProps =\n PropertyWiseOr<\n HTMLTagToBruhProps,\n PropertyWiseOr<\n SVGTagToBruhProps,\n MathMLTagToBruhProps\n >\n >\n\nexport namespace JSX {\n /** @see https://www.typescriptlang.org/docs/handbook/jsx.html#children-type-checking */\n export interface ElementChildrenAttribute { children: {} }\n\n /** @see https://www.typescriptlang.org/docs/handbook/jsx.html#attribute-type-checking */\n export interface IntrinsicElements extends TagToBruhProps {}\n\n export type Element = any\n\n export type ElementType = HTMLTag | SVGTag | MathMLTag | ((props: any) => Element)\n}\n\n// Coerces input into a DOM node, if it isn't already one\nconst terminalBruhChildToNode: {\n <Child extends TerminalBruhChild>(child: Child): TerminalBruhChildOutputNode<Child>\n} = (child: TerminalBruhChild): any => {\n // Existing DOM nodes are untouched\n if (child instanceof Node)\n return child\n // Nullish and booleans are ignored\n else if (child == null || typeof child === \"boolean\")\n return document.createComment(child + \"\")\n // Anything else is treated as text\n else\n return document.createTextNode(child + \"\")\n}\n\n// Auto-swapping single reactive node\nconst reactiveTerminalBruhChildToNode: {\n <Child extends TerminalBruhChild>(child: Reactive<Child>): TerminalBruhChildOutputNode<Child>\n} = (child: Reactive<TerminalBruhChild>): any => {\n let node = terminalBruhChildToNode(child.value)\n\n const stopReacting = child.addReaction(() => {\n // Stop swapping if no longer possible\n if (!node.parentNode) {\n stopReacting()\n return\n }\n\n const oldNode = node as typeof node & ChildNode\n const child_ = child as Reactive<BruhChild>\n\n // If an iterable now, stop swapping, then switch to reactive iterable swapping\n if (\n child.value != null &&\n typeof child.value === \"object\" &&\n Symbol.iterator in child.value\n ) {\n stopReacting()\n oldNode.replaceWith(...reactiveIterableBruhChildToNodes(child_ as Reactive<Iterable<BruhChild>>))\n }\n // Normal swap\n else {\n node = terminalBruhChildToNode(child_.value as TerminalBruhChild)\n oldNode.replaceWith(node)\n }\n })\n\n return node\n}\n\n// Auto-swapping reactive iterable of nodes\nfunction * reactiveIterableBruhChildToNodes(child: Reactive<Iterable<BruhChild>>): IterableIterator<Node> {\n // Markers owned by the swapper here itself, so that\n // the values in the iterable can be swapped separately\n const first = document.createComment(\"[\")\n const last = document.createComment(\"]\")\n\n const stopReacting = child.addReaction(() => {\n // Stop swapping if there is no parent to swap within\n if (!first.parentNode) {\n stopReacting()\n return\n }\n\n // Make a range starting after the first marker\n const range = document.createRange()\n range.setStartAfter(first)\n\n // Normal swap, replacing content between the first and last markers\n if (\n child.value != null &&\n typeof child.value === \"object\" &&\n Symbol.iterator in child.value\n ) {\n const child_ = child as Reactive<Iterable<BruhChild>>\n\n range.setEndBefore(last)\n range.deleteContents()\n first.after(...bruhChildrenToNodes(child_.value))\n }\n // Switch to single swapping node by replacing everything\n else {\n const child_ = child as unknown as Reactive<TerminalBruhChild>\n\n stopReacting()\n range.setEndAfter(last)\n range.deleteContents()\n first.replaceWith(reactiveTerminalBruhChildToNode(child_))\n }\n })\n\n yield first\n yield* bruhChildrenToNodes(child.value)\n yield last\n}\n\n// Processes bruh children into an iterable of DOM nodes\n// Reactive values are automatically replaced, so the output must be placed into a parent node\n// before any top level (after flattening iterables) reactions run\nexport function * bruhChildrenToNodes(children: Iterable<BruhChild>): IterableIterator<Node> {\n const partiallyFlattened =\n Array.isArray(children)\n ? children.flat<BruhChild, number>(Infinity)\n : children\n\n for (const child of partiallyFlattened) {\n if (!isReactive(child)) {\n if (\n child != null &&\n typeof child === \"object\" &&\n Symbol.iterator in child\n )\n yield* bruhChildrenToNodes(child)\n else\n yield terminalBruhChildToNode(child)\n }\n else {\n if (\n child.value != null &&\n typeof child.value === \"object\" &&\n Symbol.iterator in child.value\n )\n yield* reactiveIterableBruhChildToNodes(child as Reactive<Iterable<BruhChild>>)\n else\n yield reactiveTerminalBruhChildToNode(child as Reactive<TerminalBruhChild>)\n }\n }\n}\n\n//#endregion\n\n//#region Reactive-aware element helper functions e.g. applyAttributes()\n\ntype ElementWithStyle = HTMLElement | SVGElement | MathMLElement\n\n// https://w3c.github.io/csswg-drafts/cssom/#the-elementcssinlinestyle-mixin\nconst isElementWithStyle = <T extends Element>(element: T): element is (T & ElementWithStyle) =>\n // @ts-ignore\n element.style instanceof CSSStyleDeclaration\n\n/**\n * Style attribute rules from an object with\n * potentially reactive and/or set as absent values\n */\nexport const applyStyles = <E extends ElementWithStyle>(\n element: E,\n styles: StylesToApply\n) => {\n for (const property in styles) {\n const property_ = property as keyof StylesToApply\n reactiveDo(styles[property_], value => {\n if (value != null && typeof value !== \"boolean\")\n element.style.setProperty (property, value + \"\")\n else\n element.style.removeProperty(property)\n })\n }\n}\n\n/**\n * Class list from an object mapping from\n * class names to potentially reactive booleans\n */\nexport const applyClasses = (\n element: Element,\n classes: ClassesToApply\n) => {\n for (const name in classes)\n reactiveDo(classes[name], value => {\n // without coercing to a boolean, `undefined` would toggle instead of forcing removal\n element.classList.toggle(name, value === true)\n })\n}\n\n/**\n * Attributes from an object with\n * potentially reactive and/or set as absent values\n */\nexport const applyAttributes = <\n Name extends string,\n NS extends Namespace = HTMLNamespace\n>(\n element: ElementType<Name, NS>,\n attributes: AttributesToApply<Name, NS>\n) => {\n for (const name in attributes)\n reactiveDo<ElementToAttributes<Name, NS>[typeof name] | LikelyAsBoolean>(attributes[name], value => {\n if (typeof value === \"boolean\")\n element.toggleAttribute(name, value)\n else if (value != null)\n element.setAttribute (name, value + \"\")\n else\n element.removeAttribute(name)\n })\n}\n\n//#endregion\n\n//#region t()\n\n// Text nodes\nexport const t = (textContent: MaybeReactive<LikelyAsString>) => {\n // Non-reactive values are just text nodes\n if (!isReactive(textContent))\n return document.createTextNode(textContent + \"\")\n\n // Reactive values auto-update the node's text content\n const node = document.createTextNode(textContent.value + \"\")\n textContent.addReaction(() => {\n node.textContent = textContent.value + \"\"\n })\n return node\n}\n\n//#endregion\n\n//#region JSX integration\n\ndeclare global {\n interface String {\n startsWith<Prefix extends string>(\n prefix: Prefix,\n position?: 0\n ): this is `${Prefix}${string}`\n }\n}\n\nexport const jsx: {\n /**\n * Create an HTML element\n */\n <\n Name extends HTMLTag\n >(\n name: Name,\n props: HTMLTagToBruhProps[Name],\n key?: string\n ):\n HTMLElementTagNameMap[Name]\n\n /**\n * Create an SVG element\n */\n <\n Name extends SVGTag\n >(\n name: Name,\n props: SVGTagToBruhProps[Name],\n key?: string\n ):\n SVGElementTagNameMap[Name]\n\n /**\n * Create a MathML element\n */\n <\n Name extends MathMLTag\n >(\n name: Name,\n props: MathMLTagToBruhProps[Name],\n key?: string\n ):\n MathMLElementTagNameMap[Name]\n\n /**\n * Create an element\n */\n <\n Name extends string,\n NS extends Namespace = HTMLNamespace\n >(\n name: Name,\n props: BruhProps<Name, NS>,\n key?: string\n ):\n ElementType<Name, NS>\n\n /**\n * Call a function as a JSX component\n */\n <\n Props extends Record<any, unknown>,\n Result\n >(\n component: (props: Props) => Result,\n props: Props,\n key?: string\n ): Result\n} =\n<\n Name extends string,\n NS extends Namespace = HTMLNamespace\n>\n(\n nameOrComponent: Name | Function,\n props_: Record<any, unknown>,\n key?: string\n) => {\n if (key !== undefined)\n props_.key = key\n\n // It must be a component, as bruh components are just functions\n // Due to JSX, this would mean a function with only one parameter - props\n // This object includes all of the normal props and a \"children\" key\n if (typeof nameOrComponent !== \"string\") {\n const component = nameOrComponent\n const props = props_ as Record<any, unknown>\n\n return component(props)\n }\n\n const name = nameOrComponent\n const props = props_ as BruhProps<Name, NS>\n\n // Extract explicit options from the bruh prop\n let options: BruhOptions = {}\n if (typeof props.bruh === \"object\" && !isReactive(props.bruh)) {\n options = props.bruh\n delete props.bruh\n }\n const { namespace } = options\n\n // Make an element with optional namespace\n const element =\n namespace\n ? document.createElementNS(namespace, name) as ElementType<Name, NS>\n : document.createElement ( name) as ElementType<Name, NS>\n\n if (\"children\" in props) {\n element.append(\n ...bruhChildrenToNodes(\n (\n props.children != null &&\n typeof props.children === \"object\" &&\n Symbol.iterator in props.children\n )\n ? props.children\n : [props.children]\n )\n )\n\n delete props.children\n }\n\n // Apply overloaded props, if possible\n\n // Inline style object\n if (\n \"style\" in props &&\n props.style != null &&\n typeof props.style === \"object\" &&\n !isReactive(props.style) &&\n isElementWithStyle(element)\n ) {\n applyStyles(element, props.style)\n delete props.style\n }\n\n // Classes object\n if (\n \"class\" in props &&\n props.class != null &&\n typeof props.class === \"object\" &&\n !isReactive(props.class)\n ) {\n applyClasses(element, props.class)\n delete props.class\n }\n\n for (const name_ in props) {\n const name = name_ as string & (keyof typeof props)\n // Event listener functions\n if (typeof props[name] === \"function\" && name.startsWith(\"on\")) {\n element.addEventListener(name.slice(2), props[name] as any)\n delete props[name]\n }\n }\n\n // The rest of the props are attributes\n applyAttributes(element, props as AttributesToApply<Name, NS>)\n\n return element\n}\n\nexport const Fragment =\n <Children extends BruhChild>\n (props: { children: Children }) => props.children\n\n//#endregion\n\n\nexport class BruhText extends HTMLElement {\n static hydrated: { readonly [tag: string]: ReadonlySet<Text> } = {}\n\n constructor() {\n super()\n\n const textNode = document.createTextNode(this.textContent!)\n\n const tag = this.getAttribute(\"tag\")\n if (tag) {\n const set = (BruhText.hydrated as { [tag: string]: Set<Text> })[tag] ??= new Set()\n set.add(textNode)\n }\n\n this.replaceWith(textNode)\n }\n}\n\ncustomElements.define(\"bruh-text\", BruhText)\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"bruh-text\": BruhText\n }\n}\ndeclare module \"html-info\" {\n interface HTMLTagToAttributes {\n \"bruh-text\": {\n \"tag\"?: string\n }\n }\n}\n"],"names":["props","name"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import { processImages } from '../media/images/node.mjs';
3
+ import { join } from 'node:path';
4
+ import { cac } from 'cac';
5
+
6
+ const cli = cac("bruh");
7
+ cli.command(
8
+ "process-images <directory>",
9
+ "Processes the images in the given directory for the optimized-picture component"
10
+ ).action(async (directory, options) => {
11
+ const imagesDirectory = join(process.cwd(), directory);
12
+ await processImages(imagesDirectory);
13
+ });
14
+ cli.help();
15
+ cli.parse();
16
+ //# sourceMappingURL=node.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.mjs","sources":["../../src/cli/index.mts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { processImages } from \"../media/images.node.mts\"\nimport { join } from \"path\"\n\nimport { cac } from \"cac\"\nconst cli = cac(\"bruh\")\n\ncli\n .command(\n \"process-images <directory>\",\n \"Processes the images in the given directory for the optimized-picture component\"\n )\n .action(async (directory: string, options) => {\n const imagesDirectory = join(process.cwd(), directory)\n await processImages(imagesDirectory)\n })\n\ncli.help()\ncli.parse()\n"],"names":[],"mappings":";;;;;AAMA,MAAM,GAAA,GAAM,IAAI,MAAM,CAAA;AAEtB,GACG,CAAA,OAAA;AAAA,EACC,4BAAA;AAAA,EACA;AACF,CACC,CAAA,MAAA,CAAO,OAAO,SAAA,EAAmB,OAAY,KAAA;AAC5C,EAAA,MAAM,eAAkB,GAAA,IAAA,CAAK,OAAQ,CAAA,GAAA,IAAO,SAAS,CAAA;AACrD,EAAA,MAAM,cAAc,eAAe,CAAA;AACrC,CAAC,CAAA;AAEH,GAAA,CAAI,IAAK,EAAA;AACT,GAAA,CAAI,KAAM,EAAA"}
@@ -0,0 +1,162 @@
1
+ import { jsx, bruhChildrenToNodes } from '../browser.mjs';
2
+ import { r } from '../reactive.mjs';
3
+ import { spaceSeparated } from './utils.mjs';
4
+ import { BruhCustomElementBase } from './custom-elements.mjs';
5
+
6
+ const clamp = (min, x, max) => Math.min(Math.max(min, x), max);
7
+ const getHeadingLevel = (heading) => parseInt(heading.localName[1]);
8
+ const getSectionMetrics = (headings, container) => {
9
+ const metrics = /* @__PURE__ */ new Map();
10
+ for (let i = 0; i < headings.length; i++) {
11
+ const heading = headings[i];
12
+ const currentLevel = getHeadingLevel(heading);
13
+ let nextHeading;
14
+ for (let j = i + 1; j < headings.length; j++) {
15
+ const candidate = headings[j];
16
+ const candidateLevel = getHeadingLevel(candidate);
17
+ if (candidateLevel <= currentLevel) {
18
+ nextHeading = candidate;
19
+ break;
20
+ }
21
+ }
22
+ const contentTop = heading.getBoundingClientRect().top;
23
+ const contentBottom = nextHeading?.getBoundingClientRect().top ?? (heading.parentElement)?.getBoundingClientRect().bottom ?? innerHeight;
24
+ const visibleContentTop = clamp(0, contentTop, innerHeight);
25
+ const visibleContentBottom = clamp(0, contentBottom, innerHeight);
26
+ metrics.set(heading, {
27
+ contentTop,
28
+ contentBottom,
29
+ visibleContentTop,
30
+ visibleContentBottom
31
+ });
32
+ }
33
+ return metrics;
34
+ };
35
+ const getProportionalPromience = ({
36
+ contentTop,
37
+ contentBottom,
38
+ visibleContentTop,
39
+ visibleContentBottom
40
+ }) => {
41
+ const contentHeight = contentBottom - contentTop;
42
+ const visibleContentHeight = visibleContentBottom - visibleContentTop;
43
+ if (visibleContentHeight === 0)
44
+ return 0;
45
+ const visibleContentOverScreen = visibleContentHeight / innerHeight;
46
+ const proportionOfContentVisible = visibleContentHeight / contentHeight;
47
+ return Math.max(visibleContentOverScreen, proportionOfContentVisible);
48
+ };
49
+ const kumaraswamyCDF = (a2, b2, x) => 1 - (1 - x ** a2) ** b2;
50
+ const a = 1.4;
51
+ const b = 3;
52
+ const getProbabilisticProminence = ({
53
+ visibleContentTop,
54
+ visibleContentBottom
55
+ }) => kumaraswamyCDF(a, b, visibleContentBottom / innerHeight) - kumaraswamyCDF(a, b, visibleContentTop / innerHeight);
56
+ const getProminences = ({
57
+ headings,
58
+ probabilisticInfluence = 1 / 10
59
+ }) => {
60
+ const metrics = getSectionMetrics(headings);
61
+ const prominences = /* @__PURE__ */ new Map();
62
+ for (const [heading, sectionMetrics] of metrics) {
63
+ let prominence;
64
+ const proportionalProminence = probabilisticInfluence !== 1 ? getProportionalPromience(sectionMetrics) : void 0;
65
+ const probabilisticProminence = probabilisticInfluence !== 0 ? getProbabilisticProminence(sectionMetrics) : void 0;
66
+ if (probabilisticInfluence === 0)
67
+ prominence = proportionalProminence;
68
+ else if (probabilisticInfluence === 1)
69
+ prominence = probabilisticProminence;
70
+ else
71
+ prominence = proportionalProminence ** (1 - probabilisticInfluence) * probabilisticProminence ** probabilisticInfluence;
72
+ prominences.set(heading, prominence);
73
+ }
74
+ return prominences;
75
+ };
76
+ class BruhAsideTOC extends BruhCustomElementBase {
77
+ static observedAttributes = [
78
+ "headings",
79
+ "container",
80
+ "max-level",
81
+ "probabilistic-influence"
82
+ ];
83
+ static bruh = {
84
+ parseAttributes: {
85
+ headings: (s) => [...new Set(spaceSeparated(s))],
86
+ container: (s) => s || void 0,
87
+ "max-level": (s) => {
88
+ const maxLevel = parseInt(s);
89
+ return isNaN(maxLevel) ? 3 : clamp(2, maxLevel, 6);
90
+ },
91
+ "probabilistic-influence": (s) => {
92
+ const probabilisticInfluence = parseFloat(s);
93
+ return isNaN(probabilisticInfluence) ? void 0 : clamp(0, probabilisticInfluence, 1);
94
+ }
95
+ }
96
+ };
97
+ #prominences;
98
+ #rendered;
99
+ constructor() {
100
+ super();
101
+ const headings = r(
102
+ [this.bruh.attributes.headings, this.bruh.attributes["max-level"]],
103
+ () => this.bruh.attributes.headings.value?.map((id) => this.ownerDocument.getElementById(id)).filter((e) => {
104
+ if (!(e instanceof HTMLHeadingElement))
105
+ return false;
106
+ const level = getHeadingLevel(e);
107
+ return level > 1 && level <= (this.bruh.attributes["max-level"].value ?? 2);
108
+ })
109
+ );
110
+ const container = r(
111
+ [this.bruh.attributes.container],
112
+ () => this.bruh.attributes.container.value ? this.ownerDocument.getElementById(this.bruh.attributes.container.value) ?? void 0 : void 0
113
+ );
114
+ const resizeOrScroll = r({ innerHeight, innerWidth, scrollY });
115
+ const onResizeOrScroll = () => {
116
+ resizeOrScroll.value = { innerHeight, innerWidth, scrollY };
117
+ };
118
+ addEventListener("resize", onResizeOrScroll, { passive: true });
119
+ addEventListener("scroll", onResizeOrScroll, { passive: true });
120
+ this.#prominences = r([headings, container, this.bruh.attributes["probabilistic-influence"], resizeOrScroll], () => {
121
+ if (!headings.value?.length)
122
+ return;
123
+ const prominences = getProminences({
124
+ headings: headings.value,
125
+ probabilisticInfluence: this.bruh.attributes["probabilistic-influence"].value
126
+ });
127
+ const oldValue = this.#prominences.value;
128
+ if (oldValue) {
129
+ const oldHeadings = new Set(oldValue.keys());
130
+ const newHeadings = new Set(prominences.keys());
131
+ const didChange = [...newHeadings].some((h) => !oldHeadings.has(h)) || [...oldHeadings].some((h) => !newHeadings.has(h));
132
+ if (!didChange) {
133
+ for (const [heading, prominence] of prominences)
134
+ oldValue.get(heading).value = prominence;
135
+ return oldValue;
136
+ }
137
+ }
138
+ return new Map([...prominences].map(([heading, prominence]) => [heading, r(prominence)]));
139
+ });
140
+ this.#rendered = r([this.#prominences], () => {
141
+ const prominences = this.#prominences.value;
142
+ if (!prominences)
143
+ return;
144
+ return /* @__PURE__ */ jsx("ol", { children: [...prominences].map(([heading, prominence]) => /* @__PURE__ */ jsx(
145
+ "li",
146
+ {
147
+ class: `bruh-aside-toc--level-${getHeadingLevel(heading)}`,
148
+ style: { "--prominence": prominence },
149
+ children: /* @__PURE__ */ jsx("a", { href: `#${heading.id}`, children: heading.textContent })
150
+ }
151
+ )) });
152
+ });
153
+ }
154
+ mountedCallback() {
155
+ const children = bruhChildrenToNodes([this.#rendered]);
156
+ this.replaceChildren(...children);
157
+ }
158
+ }
159
+ customElements.define("bruh-aside-toc", BruhAsideTOC);
160
+
161
+ export { BruhAsideTOC };
162
+ //# sourceMappingURL=aside-toc.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aside-toc.mjs","sources":["../../src/components/aside-toc/index.tsx"],"sourcesContent":["/** @jsxImportSource bruh/browser */\nimport { bruhChildrenToNodes } from \"bruh/browser\"\nimport { FunctionalReactive, r } from \"../../reactive/index.mts\"\nimport { spaceSeparated } from \"../utils.mts\"\nimport { BruhCustomElementBase } from \"../custom-elements.mts\"\n\nconst clamp = (min: number, x: number, max: number) =>\n Math.min(Math.max(min, x), max)\n\nconst getHeadingLevel = (heading: HTMLHeadingElement) =>\n parseInt(heading.localName[1])\n\ntype SectionMetrics = {\n contentTop: number,\n contentBottom: number,\n visibleContentTop: number,\n visibleContentBottom: number\n}\n\nconst getSectionMetrics = (\n headings: ReadonlyArray<HTMLHeadingElement>,\n container?: HTMLElement\n) => {\n const metrics = new Map<HTMLHeadingElement, SectionMetrics>()\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i]\n const currentLevel = getHeadingLevel(heading)\n\n let nextHeading: HTMLHeadingElement | undefined\n for (let j = i + 1; j < headings.length; j++) {\n const candidate = headings[j]\n const candidateLevel = getHeadingLevel(candidate)\n\n if (candidateLevel <= currentLevel) {\n nextHeading = candidate\n break\n }\n }\n\n const contentTop = heading.getBoundingClientRect().top\n const contentBottom =\n nextHeading?.getBoundingClientRect().top\n ?? (container ?? heading.parentElement)?.getBoundingClientRect().bottom\n ?? innerHeight\n\n const visibleContentTop = clamp(0, contentTop, innerHeight)\n const visibleContentBottom = clamp(0, contentBottom, innerHeight)\n\n metrics.set(heading, {\n contentTop,\n contentBottom,\n visibleContentTop,\n visibleContentBottom,\n })\n }\n\n return metrics\n}\n\nconst getProportionalPromience = (\n {\n contentTop,\n contentBottom,\n visibleContentTop,\n visibleContentBottom\n }: SectionMetrics\n) => {\n const contentHeight = contentBottom - contentTop\n const visibleContentHeight = visibleContentBottom - visibleContentTop\n\n if (visibleContentHeight === 0)\n return 0\n\n const visibleContentOverScreen = visibleContentHeight / innerHeight\n const proportionOfContentVisible = visibleContentHeight / contentHeight\n\n return Math.max(visibleContentOverScreen, proportionOfContentVisible)\n}\n\n/**\n * Cumulative Distribution Function over Kumaraswamy distribution (cheap and similar to beta)\n *\n * Corresponding PDF is `a * b * x ** (a - 1) * (1 - x ** a) ** (b - 1)`\n */\nconst kumaraswamyCDF = (\n a: number,\n b: number,\n /** Up to this point */\n x: number\n) => 1 - (1 - x ** a) ** b\n\n// We could have an e.g. 256 entry Float32Array of evenly split cached values\n// for expensive CDFs, but this one is very fast\n\n// I manually tuned these parameters to match what I thought looked accurate\n// The center of attention is ~22.5% of the way down the screen\nconst a = 1.4\nconst b = 3\n\nconst getProbabilisticProminence = (\n {\n visibleContentTop,\n visibleContentBottom\n }: SectionMetrics\n) =>\n kumaraswamyCDF(a, b, visibleContentBottom / innerHeight) -\n kumaraswamyCDF(a, b, visibleContentTop / innerHeight)\n\nconst getProminences = ({\n headings,\n probabilisticInfluence = 1/10\n}: {\n headings: ReadonlyArray<HTMLHeadingElement>,\n probabilisticInfluence?: number\n}) => {\n const metrics = getSectionMetrics(headings)\n\n const prominences = new Map<HTMLHeadingElement, number>()\n\n let i = 0\n for (const [heading, sectionMetrics] of metrics) {\n let prominence: number\n\n const proportionalProminence = probabilisticInfluence !== 1\n ? getProportionalPromience(sectionMetrics)\n : undefined\n\n const probabilisticProminence = probabilisticInfluence !== 0\n ? getProbabilisticProminence(sectionMetrics)\n : undefined\n\n if (probabilisticInfluence === 0)\n prominence = proportionalProminence!\n else if (probabilisticInfluence === 1)\n prominence = probabilisticProminence!\n else\n prominence = (\n proportionalProminence! ** (1 - probabilisticInfluence) *\n probabilisticProminence! ** probabilisticInfluence\n )\n\n prominences.set(heading, prominence)\n i++\n }\n\n return prominences\n}\n\n\ntype BruhAsideTOCAttributes = {\n \"headings\"?: ReadonlyArray<string>,\n \"container\"?: string,\n \"max-level\": 2 | 3 |4 | 5 | 6\n \"probabilistic-influence\"?: number\n}\n\nexport class BruhAsideTOC extends BruhCustomElementBase<BruhAsideTOCAttributes> {\n static observedAttributes = [\n \"headings\",\n \"container\",\n \"max-level\",\n \"probabilistic-influence\"\n ] as const\n\n static bruh = {\n parseAttributes: {\n headings: (s: string | null) => [...new Set(spaceSeparated(s))],\n\n container: (s: string | null) => s || undefined,\n\n \"max-level\": (s: string | null) => {\n const maxLevel = parseInt(s as string)\n return isNaN(maxLevel)\n ? 3\n : clamp(2, maxLevel, 6)\n },\n\n \"probabilistic-influence\": (s: string | null) => {\n const probabilisticInfluence = parseFloat(s as string)\n return isNaN(probabilisticInfluence)\n ? undefined\n : clamp(0, probabilisticInfluence, 1)\n }\n }\n }\n\n #prominences: FunctionalReactive<Map<HTMLHeadingElement, FunctionalReactive<number>> | undefined>\n #rendered\n\n constructor() {\n super()\n\n const headings = r([this.bruh.attributes.headings, this.bruh.attributes[\"max-level\"]], () =>\n this.bruh.attributes.headings.value\n ?.map(id => this.ownerDocument.getElementById(id))\n .filter((e): e is HTMLHeadingElement => {\n if (!(e instanceof HTMLHeadingElement))\n return false\n\n const level = getHeadingLevel(e)\n return level > 1 && level <= (this.bruh.attributes[\"max-level\"].value ?? 2)\n })\n )\n\n const container = r([this.bruh.attributes.container], () =>\n this.bruh.attributes.container.value\n ? this.ownerDocument.getElementById(this.bruh.attributes.container.value) ?? undefined\n : undefined\n )\n\n const resizeOrScroll = r({ innerHeight, innerWidth, scrollY })\n const onResizeOrScroll = () => {\n resizeOrScroll.value = { innerHeight, innerWidth, scrollY }\n }\n addEventListener(\"resize\", onResizeOrScroll, { passive: true })\n addEventListener(\"scroll\", onResizeOrScroll, { passive: true })\n\n this.#prominences = r([headings, container, this.bruh.attributes[\"probabilistic-influence\"], resizeOrScroll], () => {\n if (!headings.value?.length)\n return\n\n const prominences = getProminences({\n headings: headings.value,\n probabilisticInfluence: this.bruh.attributes[\"probabilistic-influence\"].value\n })\n\n const oldValue = this.#prominences.value\n if (oldValue) {\n const oldHeadings = new Set(oldValue.keys())\n const newHeadings = new Set(prominences.keys())\n const didChange =\n [...newHeadings].some(h => !oldHeadings.has(h)) ||\n [...oldHeadings].some(h => !newHeadings.has(h))\n\n if (!didChange) {\n for (const [heading, prominence] of prominences)\n oldValue.get(heading)!.value = prominence\n\n return oldValue\n }\n }\n\n return new Map([...prominences].map(([heading, prominence]) => [heading, r(prominence)]))\n })\n\n this.#rendered = r([this.#prominences], () => {\n const prominences = this.#prominences.value\n if (!prominences)\n return\n\n return (\n <ol>\n {[...prominences].map(([heading, prominence]) => (\n <li\n class={`bruh-aside-toc--level-${getHeadingLevel(heading)}`}\n style={{ \"--prominence\": prominence }}\n >\n <a href={`#${heading.id}`}>\n {heading.textContent}\n </a>\n </li>\n ))}\n </ol>\n )\n })\n }\n\n mountedCallback() {\n const children = bruhChildrenToNodes([this.#rendered])\n this.replaceChildren(...children)\n }\n}\n\ncustomElements.define(\"bruh-aside-toc\", BruhAsideTOC)\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"bruh-aside-toc\": BruhAsideTOC\n }\n}\ndeclare module \"html-info\" {\n interface HTMLTagToAttributes {\n \"bruh-aside-toc\": {\n /**\n * Space separated list of heading ids\n */\n \"headings\"?: ReadonlyArray<string>,\n /** Content container id */\n \"container\"?: string,\n \"max-level\"?: `${2 | 3 | 4 | 5 | 6}`\n }\n }\n}\ndeclare module \"csstype\" {\n interface PropertiesHyphen {\n \"--prominence\"?: number\n }\n}\n"],"names":["a","b"],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { r } from '../reactive.mjs';
2
+ import { attempt } from '../utils.mjs';
3
+
4
+ class CustomElement extends HTMLElement {
5
+ // https://html.spec.whatwg.org/multipage/custom-elements.html#element-definition
6
+ /**
7
+ * Which attributes to observe for `attributeChangedCallback()`
8
+ */
9
+ static observedAttributes;
10
+ /**
11
+ * Disable `attachInternals()` and/or `attachShadow()`
12
+ */
13
+ static disabledFeatures;
14
+ /**
15
+ * Whether the element is form-associated
16
+ */
17
+ static formAssociated;
18
+ }
19
+ class BruhCustomElementBase extends CustomElement {
20
+ static bruh;
21
+ bruh = {
22
+ attributes: {}
23
+ };
24
+ #setBruhAttribute(name, value = this.getAttribute(name)) {
25
+ const constructor = this.constructor;
26
+ const parse = constructor.bruh?.parseAttributes?.[name];
27
+ this.bruh.attributes[name] ??= r();
28
+ this.bruh.attributes[name].value = parse ? attempt(() => parse(value)) : value ?? void 0;
29
+ }
30
+ constructor() {
31
+ super();
32
+ const { observedAttributes } = this.constructor;
33
+ if (observedAttributes)
34
+ for (const name of observedAttributes)
35
+ this.#setBruhAttribute(name);
36
+ }
37
+ attributeChangedCallback(name, oldValue, newValue, namespace) {
38
+ this.#setBruhAttribute(name, newValue);
39
+ }
40
+ #mounted = false;
41
+ /**
42
+ * Overrides must call `super.connectedCallback()`
43
+ */
44
+ connectedCallback() {
45
+ if (this.#mounted) return;
46
+ this.mountedCallback?.();
47
+ this.#mounted = true;
48
+ }
49
+ }
50
+
51
+ export { BruhCustomElementBase, CustomElement };
52
+ //# sourceMappingURL=custom-elements.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-elements.mjs","sources":["../../src/components/custom-elements.mts"],"sourcesContent":["import { type SourceNode, r } from \"../reactive/index.mts\";\nimport { attempt } from \"../utils/index.mts\";\n\nexport class CustomElement extends HTMLElement {\n // https://html.spec.whatwg.org/multipage/custom-elements.html#element-definition\n /**\n * Which attributes to observe for `attributeChangedCallback()`\n */\n static observedAttributes?: ReadonlyArray<string>\n\n /**\n * Disable `attachInternals()` and/or `attachShadow()`\n */\n static disabledFeatures?: ReadonlyArray<\"internals\" | \"shadow\">\n\n /**\n * Whether the element is form-associated\n */\n static formAssociated?: boolean\n\n // https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reactions\n /**\n * Called whenever the element is connected to a document\n * @see https://html.spec.whatwg.org/multipage/infrastructure.html#becomes-connected\n */\n connectedCallback?(): void\n\n /**\n * Called whenever the element is disconnected from a document\n * @see https://html.spec.whatwg.org/multipage/infrastructure.html#becomes-disconnected\n */\n disconnectedCallback?(): void\n\n /**\n * Called whenever the element is moved to a new document\n * @see https://dom.spec.whatwg.org/#concept-node-move-ext\n */\n connectedMoveCallback?(): void\n\n /**\n * Called whenever the element is adopted by a new document\n * @see https://dom.spec.whatwg.org/#concept-node-adopt\n */\n adoptedCallback?(oldDocument: Document, newDocument: Document): void\n\n /**\n * Called whenever an attribute is changed, appended, removed, or replaced\n * @see https://dom.spec.whatwg.org/#concept-element-attributes-change-ext\n */\n attributeChangedCallback?(name: string, oldValue: string | null, newValue: string | null, namespace: string | null): void\n\n /**\n * Called (if the element is form-associated) whenever the form \"owner\" of the element is reset and doing so changes the form that owns the element\n * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#reset-the-form-owner\n */\n formAssociatedCallback?(formOwner: HTMLFormElement | null): void\n\n /**\n * Called (if the element is form-associated) whenever the form \"owner\" of the element is reset\n * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-form-reset\n */\n formResetCallback?(): void\n\n /**\n * Called (if the element is form-associated) whenever the element is disabled or enabled\n * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-disabled\n */\n formDisabledCallback?(isDisabled: boolean): void\n\n /**\n * Called (if the element is form-associated) whenever the element's value is restored\n * @see https://html.spec.whatwg.org/multipage/browsing-the-web.html#restore-persisted-state\n */\n formStateRestoreCallback?(\n state: FormDataEntryValue | FormDataIterator<[string, FormDataEntryValue]> | null,\n reason: \"autocomplete\" | \"restore\"\n ): void\n}\n\ntype ThisConstructor<BaseClass extends BruhCustomElementBase> = BaseClass extends BruhCustomElementBase<infer Attributes> ? typeof BruhCustomElementBase & {\n observedAttributes?: ReadonlyArray<keyof Attributes>\n bruh?: {\n parseAttributes?: {\n [A in keyof Attributes]?: (raw: string | null) => Attributes[A]\n }\n }\n} : never\n\nexport class BruhCustomElementBase<\n Attributes extends { [attribute: string]: any} = {}\n> extends CustomElement {\n static bruh?: {\n parseAttributes?: Partial<{\n [attribute: string]: (raw: string | null) => any\n }>\n }\n\n bruh = {\n attributes: {} as {\n [A in (keyof Attributes & string)]: SourceNode<Attributes[A] | undefined>\n }\n };\n\n #setBruhAttribute<A extends keyof Attributes & string>(\n name: A,\n value = this.getAttribute(name)\n ) {\n const constructor = this.constructor as ThisConstructor<this>\n const parse = constructor.bruh?.parseAttributes?.[name]\n\n this.bruh.attributes[name] ??= r()\n this.bruh.attributes[name].value =\n parse\n ? attempt(() => parse(value))\n : value ?? undefined\n }\n\n constructor() {\n super()\n\n const { observedAttributes } = this.constructor as ThisConstructor<this>\n\n if (observedAttributes)\n for (const name of observedAttributes)\n this.#setBruhAttribute(name)\n }\n\n attributeChangedCallback<A extends keyof Attributes & string>(\n name: A,\n oldValue: string | null,\n newValue: string | null,\n namespace: string | null\n ) {\n this.#setBruhAttribute(name, newValue)\n }\n\n #mounted = false;\n /**\n * Overrides must call `super.connectedCallback()`\n */\n connectedCallback() {\n if (this.#mounted) return\n this.mountedCallback?.()\n this.#mounted = true\n }\n\n /**\n * Called when the element is first connected to a document\n */\n mountedCallback?(): void\n}\n"],"names":[],"mappings":";;;AAGO,MAAM,sBAAsB,WAAY,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAK7C,OAAO,kBAAA;AAAA;AAAA;AAAA;AAAA,EAKP,OAAO,gBAAA;AAAA;AAAA;AAAA;AAAA,EAKP,OAAO,cAAA;AA2DT;AAWO,MAAM,8BAEH,aAAc,CAAA;AAAA,EACtB,OAAO,IAAA;AAAA,EAMP,IAAO,GAAA;AAAA,IACL,YAAY;AAAC,GAGf;AAAA,EAEA,kBACE,IACA,EAAA,KAAA,GAAQ,IAAK,CAAA,YAAA,CAAa,IAAI,CAC9B,EAAA;AACA,IAAA,MAAM,cAAc,IAAK,CAAA,WAAA;AACzB,IAAA,MAAM,KAAQ,GAAA,WAAA,CAAY,IAAM,EAAA,eAAA,GAAkB,IAAI,CAAA;AAEtD,IAAA,IAAA,CAAK,IAAK,CAAA,UAAA,CAAW,IAAI,CAAA,KAAM,CAAE,EAAA;AACjC,IAAA,IAAA,CAAK,IAAK,CAAA,UAAA,CAAW,IAAI,CAAA,CAAE,KACzB,GAAA,KAAA,GACI,OAAQ,CAAA,MAAM,KAAM,CAAA,KAAK,CAAC,CAAA,GAC1B,KAAS,IAAA,MAAA;AAAA;AACjB,EAEA,WAAc,GAAA;AACZ,IAAM,KAAA,EAAA;AAEN,IAAM,MAAA,EAAE,kBAAmB,EAAA,GAAI,IAAK,CAAA,WAAA;AAEpC,IAAI,IAAA,kBAAA;AACF,MAAA,KAAA,MAAW,IAAQ,IAAA,kBAAA;AACjB,QAAA,IAAA,CAAK,kBAAkB,IAAI,CAAA;AAAA;AACjC,EAEA,wBACE,CAAA,IAAA,EACA,QACA,EAAA,QAAA,EACA,SACA,EAAA;AACA,IAAK,IAAA,CAAA,iBAAA,CAAkB,MAAM,QAAQ,CAAA;AAAA;AACvC,EAEA,QAAW,GAAA,KAAA;AAAA;AAAA;AAAA;AAAA,EAIX,iBAAoB,GAAA;AAClB,IAAA,IAAI,KAAK,QAAU,EAAA;AACnB,IAAA,IAAA,CAAK,eAAkB,IAAA;AACvB,IAAA,IAAA,CAAK,QAAW,GAAA,IAAA;AAAA;AAOpB;;;;"}