@f-ewald/components 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +34 -0
  2. package/custom-elements.json +424 -1
  3. package/dist/dropdown-button.d.ts +37 -0
  4. package/dist/dropdown-button.d.ts.map +1 -0
  5. package/dist/dropdown-button.js +219 -0
  6. package/dist/dropdown-button.js.map +1 -0
  7. package/dist/form-select.d.ts +6 -0
  8. package/dist/form-select.d.ts.map +1 -1
  9. package/dist/form-select.js +9 -0
  10. package/dist/form-select.js.map +1 -1
  11. package/dist/frame-box.d.ts +22 -0
  12. package/dist/frame-box.d.ts.map +1 -0
  13. package/dist/frame-box.js +68 -0
  14. package/dist/frame-box.js.map +1 -0
  15. package/dist/icon-button.d.ts +27 -0
  16. package/dist/icon-button.d.ts.map +1 -0
  17. package/dist/icon-button.js +83 -0
  18. package/dist/icon-button.js.map +1 -0
  19. package/dist/icons.d.ts +1 -0
  20. package/dist/icons.d.ts.map +1 -1
  21. package/dist/icons.js +1 -0
  22. package/dist/icons.js.map +1 -1
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +3 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/mcp-server.d.ts +3 -0
  28. package/dist/mcp-server.d.ts.map +1 -0
  29. package/dist/mcp-server.js +82 -0
  30. package/dist/mcp-server.js.map +1 -0
  31. package/dist/popover-panel.d.ts +3 -0
  32. package/dist/popover-panel.d.ts.map +1 -1
  33. package/dist/popover-panel.js +11 -0
  34. package/dist/popover-panel.js.map +1 -1
  35. package/docs/dropdown-button.md +61 -0
  36. package/docs/form-select.md +6 -0
  37. package/docs/frame-box.md +43 -0
  38. package/docs/icon-button.md +52 -0
  39. package/docs/mcp-evaluation.md +18 -11
  40. package/docs/popover-panel.md +5 -1
  41. package/llms.txt +77 -0
  42. package/package.json +10 -3
package/README.md CHANGED
@@ -50,10 +50,13 @@ import "@f-ewald/components/roman-numeral.js";
50
50
  | `<data-table>` | [docs/data-table.md](./docs/data-table.md) |
51
51
  | `<distance-value>` | [docs/distance-value.md](./docs/distance-value.md) |
52
52
  | `<distribution-chart>` | [docs/distribution-chart.md](./docs/distribution-chart.md) |
53
+ | `<dropdown-button>` | [docs/dropdown-button.md](./docs/dropdown-button.md) |
53
54
  | `<editable-text>` | [docs/editable-text.md](./docs/editable-text.md) |
54
55
  | `<form-select>` | [docs/form-select.md](./docs/form-select.md) |
56
+ | `<frame-box>` | [docs/frame-box.md](./docs/frame-box.md) |
55
57
  | `<gallery-item>` | [docs/gallery-item.md](./docs/gallery-item.md) |
56
58
  | `<gallery-item-variant>` | [docs/gallery-item-variant.md](./docs/gallery-item-variant.md) |
59
+ | `<icon-button>` | [docs/icon-button.md](./docs/icon-button.md) |
57
60
  | `<live-timer>` | [docs/live-timer.md](./docs/live-timer.md) |
58
61
  | `<map-circle>` | [docs/map-circle.md](./docs/map-circle.md) |
59
62
  | `<map-pin>` | [docs/map-pin.md](./docs/map-pin.md) |
@@ -120,6 +123,36 @@ set. Don't reintroduce that pattern.)
120
123
 
121
124
  The full token set is defined in [`src/tokens.ts`](./src/tokens.ts).
122
125
 
126
+ ## MCP server
127
+
128
+ `npm run mcp` (or `node dist/mcp-server.js` after `npm run build`) starts a
129
+ stdio [MCP](https://modelcontextprotocol.io) server exposing the component
130
+ catalog to AI coding assistants, with two tools:
131
+
132
+ - `list_components` — every tag + one-line description.
133
+ - `get_component_docs(tag)` — the full generated Markdown doc for one tag
134
+ (install snippet, usage example, attributes/properties, events, slots,
135
+ CSS custom properties).
136
+
137
+ It's read-only over the same `custom-elements.json`/`docs/*.md` this package
138
+ already generates via `npm run docs` — no separate data source to maintain.
139
+ A consuming project wires it up with a `.mcp.json` at its repo root:
140
+
141
+ ```json
142
+ {
143
+ "mcpServers": {
144
+ "f-ewald-components": {
145
+ "command": "node",
146
+ "args": ["/absolute/path/to/components/dist/mcp-server.js"]
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
152
+ See the "MCP server" section in [`CLAUDE.md`](./CLAUDE.md) for more, and
153
+ [`docs/mcp-evaluation.md`](./docs/mcp-evaluation.md) for why this was built
154
+ now rather than earlier.
155
+
123
156
  ## Playground / development
124
157
 
125
158
  ```bash
@@ -145,6 +178,7 @@ npm run build:demo # static build of the playground, into demo-dist/
145
178
  | `npm run icons` | Regenerate `src/icons.ts` from the Heroicons package. |
146
179
  | `npm run analyze` | Regenerate `custom-elements.json` via the custom-elements-manifest analyzer. |
147
180
  | `npm run docs` | Regenerate the manifest, `docs/*.md`, and `llms.txt`. |
181
+ | `npm run mcp` | Run the MCP server (`dist/mcp-server.js`) directly, for manual testing. |
148
182
  | `npm run test` | Run the Playwright suite against the playground. |
149
183
 
150
184
  ## Contributing
@@ -2008,6 +2008,203 @@
2008
2008
  }
2009
2009
  ]
2010
2010
  },
2011
+ {
2012
+ "kind": "javascript-module",
2013
+ "path": "src/dropdown-button.ts",
2014
+ "declarations": [
2015
+ {
2016
+ "kind": "class",
2017
+ "description": "A primary-styled button with a label and chevron that opens an anchored\nmenu of actions — essentially `form-select` minus \"current value\"\nsemantics: a menu, not a select. Use for a set of mutually exclusive\nnext-step actions (e.g. a failed task's Retry / Close / Backlog).",
2018
+ "name": "DropdownButton",
2019
+ "members": [
2020
+ {
2021
+ "kind": "field",
2022
+ "name": "label",
2023
+ "type": {
2024
+ "text": "string"
2025
+ },
2026
+ "default": "\"\"",
2027
+ "description": "The trigger button's label.",
2028
+ "attribute": "label"
2029
+ },
2030
+ {
2031
+ "kind": "field",
2032
+ "name": "options",
2033
+ "type": {
2034
+ "text": "DropdownOption[]"
2035
+ },
2036
+ "default": "[]",
2037
+ "description": "The menu's actions."
2038
+ },
2039
+ {
2040
+ "kind": "field",
2041
+ "name": "disabled",
2042
+ "type": {
2043
+ "text": "boolean"
2044
+ },
2045
+ "default": "false",
2046
+ "description": "Disables the trigger, preventing the menu from opening.",
2047
+ "attribute": "disabled"
2048
+ },
2049
+ {
2050
+ "kind": "field",
2051
+ "name": "_open",
2052
+ "type": {
2053
+ "text": "boolean"
2054
+ },
2055
+ "privacy": "private",
2056
+ "default": "false"
2057
+ },
2058
+ {
2059
+ "kind": "field",
2060
+ "name": "_activeIndex",
2061
+ "type": {
2062
+ "text": "number"
2063
+ },
2064
+ "privacy": "private",
2065
+ "default": "-1"
2066
+ },
2067
+ {
2068
+ "kind": "field",
2069
+ "name": "#onWindowMousedown",
2070
+ "privacy": "private"
2071
+ },
2072
+ {
2073
+ "kind": "method",
2074
+ "name": "#toggle",
2075
+ "privacy": "private",
2076
+ "return": {
2077
+ "type": {
2078
+ "text": "void"
2079
+ }
2080
+ }
2081
+ },
2082
+ {
2083
+ "kind": "method",
2084
+ "name": "#select",
2085
+ "privacy": "private",
2086
+ "return": {
2087
+ "type": {
2088
+ "text": "void"
2089
+ }
2090
+ },
2091
+ "parameters": [
2092
+ {
2093
+ "name": "option",
2094
+ "type": {
2095
+ "text": "DropdownOption"
2096
+ }
2097
+ }
2098
+ ]
2099
+ },
2100
+ {
2101
+ "kind": "method",
2102
+ "name": "#onTriggerKeydown",
2103
+ "privacy": "private",
2104
+ "return": {
2105
+ "type": {
2106
+ "text": "void"
2107
+ }
2108
+ },
2109
+ "parameters": [
2110
+ {
2111
+ "name": "e",
2112
+ "type": {
2113
+ "text": "KeyboardEvent"
2114
+ }
2115
+ }
2116
+ ]
2117
+ },
2118
+ {
2119
+ "kind": "method",
2120
+ "name": "#moveActive",
2121
+ "privacy": "private",
2122
+ "return": {
2123
+ "type": {
2124
+ "text": "void"
2125
+ }
2126
+ },
2127
+ "parameters": [
2128
+ {
2129
+ "name": "delta",
2130
+ "type": {
2131
+ "text": "number"
2132
+ }
2133
+ }
2134
+ ]
2135
+ },
2136
+ {
2137
+ "kind": "method",
2138
+ "name": "#confirmActive",
2139
+ "privacy": "private",
2140
+ "return": {
2141
+ "type": {
2142
+ "text": "void"
2143
+ }
2144
+ }
2145
+ },
2146
+ {
2147
+ "kind": "method",
2148
+ "name": "renderMenu",
2149
+ "privacy": "private"
2150
+ }
2151
+ ],
2152
+ "events": [
2153
+ {
2154
+ "name": "select",
2155
+ "type": {
2156
+ "text": "CustomEvent"
2157
+ },
2158
+ "description": "Fired with `{ value: string }` when a menu item is picked."
2159
+ }
2160
+ ],
2161
+ "attributes": [
2162
+ {
2163
+ "name": "label",
2164
+ "type": {
2165
+ "text": "string"
2166
+ },
2167
+ "default": "\"\"",
2168
+ "description": "The trigger button's label.",
2169
+ "fieldName": "label"
2170
+ },
2171
+ {
2172
+ "name": "disabled",
2173
+ "type": {
2174
+ "text": "boolean"
2175
+ },
2176
+ "default": "false",
2177
+ "description": "Disables the trigger, preventing the menu from opening.",
2178
+ "fieldName": "disabled"
2179
+ }
2180
+ ],
2181
+ "superclass": {
2182
+ "name": "LitElement",
2183
+ "package": "lit"
2184
+ },
2185
+ "tagName": "dropdown-button",
2186
+ "customElement": true
2187
+ }
2188
+ ],
2189
+ "exports": [
2190
+ {
2191
+ "kind": "js",
2192
+ "name": "DropdownButton",
2193
+ "declaration": {
2194
+ "name": "DropdownButton",
2195
+ "module": "src/dropdown-button.ts"
2196
+ }
2197
+ },
2198
+ {
2199
+ "kind": "custom-element-definition",
2200
+ "name": "dropdown-button",
2201
+ "declaration": {
2202
+ "name": "DropdownButton",
2203
+ "module": "src/dropdown-button.ts"
2204
+ }
2205
+ }
2206
+ ]
2207
+ },
2011
2208
  {
2012
2209
  "kind": "javascript-module",
2013
2210
  "path": "src/editable-text.ts",
@@ -2246,7 +2443,7 @@
2246
2443
  "declarations": [
2247
2444
  {
2248
2445
  "kind": "class",
2249
- "description": "A styled dropdown select: a trigger button showing the current option's\nlabel, opening a listbox popover on click. Drop-in generic replacement for\na native `<select>` wherever consistent cross-browser styling and a\n`change` event carrying `{ value }` are wanted (e.g. a task's status\npicker).",
2446
+ "description": "A styled dropdown select: a trigger button showing the current option's\nlabel, opening a listbox popover on click. Drop-in generic replacement for\na native `<select>` wherever consistent cross-browser styling and a\n`change` event carrying `{ value }` are wanted (e.g. a task's status\npicker).\n\nThe trigger fills its host's width (`justify-content: space-between`\npushes the chevron to the far edge), but the host itself stays\n`display: inline-block` — so usages that never size the host (a filter\nbar, a status picker) keep shrink-to-fit auto-width unchanged. To make an\ninstance full-width, size the host itself: `form-select { width: 100%; }`.",
2250
2447
  "name": "FormSelect",
2251
2448
  "members": [
2252
2449
  {
@@ -2456,6 +2653,70 @@
2456
2653
  }
2457
2654
  ]
2458
2655
  },
2656
+ {
2657
+ "kind": "javascript-module",
2658
+ "path": "src/frame-box.ts",
2659
+ "declarations": [
2660
+ {
2661
+ "kind": "class",
2662
+ "description": "A titled frame around a slot: a gray border with a small uppercase,\nmuted label overlapping the top edge (fieldset/legend-style). Generic —\nthe label text is entirely up to the consumer (e.g. \"Debug\" to visually\nfence off dev-only chrome from the product UI).",
2663
+ "name": "FrameBox",
2664
+ "slots": [
2665
+ {
2666
+ "description": "Framed content.",
2667
+ "name": ""
2668
+ }
2669
+ ],
2670
+ "members": [
2671
+ {
2672
+ "kind": "field",
2673
+ "name": "label",
2674
+ "type": {
2675
+ "text": "string"
2676
+ },
2677
+ "default": "\"\"",
2678
+ "description": "The overlapping title label, e.g. \"Debug\".",
2679
+ "attribute": "label"
2680
+ }
2681
+ ],
2682
+ "attributes": [
2683
+ {
2684
+ "name": "label",
2685
+ "type": {
2686
+ "text": "string"
2687
+ },
2688
+ "default": "\"\"",
2689
+ "description": "The overlapping title label, e.g. \"Debug\".",
2690
+ "fieldName": "label"
2691
+ }
2692
+ ],
2693
+ "superclass": {
2694
+ "name": "LitElement",
2695
+ "package": "lit"
2696
+ },
2697
+ "tagName": "frame-box",
2698
+ "customElement": true
2699
+ }
2700
+ ],
2701
+ "exports": [
2702
+ {
2703
+ "kind": "js",
2704
+ "name": "FrameBox",
2705
+ "declaration": {
2706
+ "name": "FrameBox",
2707
+ "module": "src/frame-box.ts"
2708
+ }
2709
+ },
2710
+ {
2711
+ "kind": "custom-element-definition",
2712
+ "name": "frame-box",
2713
+ "declaration": {
2714
+ "name": "FrameBox",
2715
+ "module": "src/frame-box.ts"
2716
+ }
2717
+ }
2718
+ ]
2719
+ },
2459
2720
  {
2460
2721
  "kind": "javascript-module",
2461
2722
  "path": "src/gallery-item-variant.ts",
@@ -2645,6 +2906,98 @@
2645
2906
  }
2646
2907
  ]
2647
2908
  },
2909
+ {
2910
+ "kind": "javascript-module",
2911
+ "path": "src/icon-button.ts",
2912
+ "declarations": [
2913
+ {
2914
+ "kind": "class",
2915
+ "description": "A borderless button wrapping a passed-in icon, with a rounded\nhover-highlight background. Use for a low-emphasis affordance next to\ncontent it acts on (e.g. an \"Edit\" pencil at the end of a table row)\nwhere a bordered `ui-button` would be too heavy.",
2916
+ "name": "IconButton",
2917
+ "members": [
2918
+ {
2919
+ "kind": "field",
2920
+ "name": "icon",
2921
+ "type": {
2922
+ "text": "TemplateResult | null"
2923
+ },
2924
+ "default": "null",
2925
+ "description": "Pre-rendered icon template, e.g. `iconPencil(16)` from this package's icon set."
2926
+ },
2927
+ {
2928
+ "kind": "field",
2929
+ "name": "label",
2930
+ "type": {
2931
+ "text": "string"
2932
+ },
2933
+ "default": "\"\"",
2934
+ "description": "Required accessible label, applied as `aria-label`/`title`.",
2935
+ "attribute": "label"
2936
+ },
2937
+ {
2938
+ "kind": "field",
2939
+ "name": "disabled",
2940
+ "type": {
2941
+ "text": "boolean"
2942
+ },
2943
+ "default": "false",
2944
+ "description": "Disables the button and dims it.",
2945
+ "attribute": "disabled"
2946
+ }
2947
+ ],
2948
+ "events": [
2949
+ {
2950
+ "description": "Native click, bubbling as usual — listen on the element itself.",
2951
+ "name": "click"
2952
+ }
2953
+ ],
2954
+ "attributes": [
2955
+ {
2956
+ "name": "label",
2957
+ "type": {
2958
+ "text": "string"
2959
+ },
2960
+ "default": "\"\"",
2961
+ "description": "Required accessible label, applied as `aria-label`/`title`.",
2962
+ "fieldName": "label"
2963
+ },
2964
+ {
2965
+ "name": "disabled",
2966
+ "type": {
2967
+ "text": "boolean"
2968
+ },
2969
+ "default": "false",
2970
+ "description": "Disables the button and dims it.",
2971
+ "fieldName": "disabled"
2972
+ }
2973
+ ],
2974
+ "superclass": {
2975
+ "name": "LitElement",
2976
+ "package": "lit"
2977
+ },
2978
+ "tagName": "icon-button",
2979
+ "customElement": true
2980
+ }
2981
+ ],
2982
+ "exports": [
2983
+ {
2984
+ "kind": "js",
2985
+ "name": "IconButton",
2986
+ "declaration": {
2987
+ "name": "IconButton",
2988
+ "module": "src/icon-button.ts"
2989
+ }
2990
+ },
2991
+ {
2992
+ "kind": "custom-element-definition",
2993
+ "name": "icon-button",
2994
+ "declaration": {
2995
+ "name": "IconButton",
2996
+ "module": "src/icon-button.ts"
2997
+ }
2998
+ }
2999
+ ]
3000
+ },
2648
3001
  {
2649
3002
  "kind": "javascript-module",
2650
3003
  "path": "src/icons.ts",
@@ -3028,6 +3381,16 @@
3028
3381
  "default": "18"
3029
3382
  }
3030
3383
  ]
3384
+ },
3385
+ {
3386
+ "kind": "function",
3387
+ "name": "iconArrowTopRightOnSquare",
3388
+ "parameters": [
3389
+ {
3390
+ "name": "size",
3391
+ "default": "16"
3392
+ }
3393
+ ]
3031
3394
  }
3032
3395
  ],
3033
3396
  "exports": [
@@ -3334,6 +3697,14 @@
3334
3697
  "name": "iconChatBubbleLeftRight",
3335
3698
  "module": "src/icons.ts"
3336
3699
  }
3700
+ },
3701
+ {
3702
+ "kind": "js",
3703
+ "name": "iconArrowTopRightOnSquare",
3704
+ "declaration": {
3705
+ "name": "iconArrowTopRightOnSquare",
3706
+ "module": "src/icons.ts"
3707
+ }
3337
3708
  }
3338
3709
  ]
3339
3710
  },
@@ -3782,6 +4153,38 @@
3782
4153
  "module": "./popover-panel.js"
3783
4154
  }
3784
4155
  },
4156
+ {
4157
+ "kind": "js",
4158
+ "name": "DropdownButton",
4159
+ "declaration": {
4160
+ "name": "DropdownButton",
4161
+ "module": "./dropdown-button.js"
4162
+ }
4163
+ },
4164
+ {
4165
+ "kind": "js",
4166
+ "name": "DropdownOption",
4167
+ "declaration": {
4168
+ "name": "DropdownOption",
4169
+ "module": "./dropdown-button.js"
4170
+ }
4171
+ },
4172
+ {
4173
+ "kind": "js",
4174
+ "name": "IconButton",
4175
+ "declaration": {
4176
+ "name": "IconButton",
4177
+ "module": "./icon-button.js"
4178
+ }
4179
+ },
4180
+ {
4181
+ "kind": "js",
4182
+ "name": "FrameBox",
4183
+ "declaration": {
4184
+ "name": "FrameBox",
4185
+ "module": "./frame-box.js"
4186
+ }
4187
+ },
3785
4188
  {
3786
4189
  "kind": "js",
3787
4190
  "name": "formatDuration",
@@ -4303,6 +4706,12 @@
4303
4706
  }
4304
4707
  ]
4305
4708
  },
4709
+ {
4710
+ "kind": "javascript-module",
4711
+ "path": "src/mcp-server.ts",
4712
+ "declarations": [],
4713
+ "exports": []
4714
+ },
4306
4715
  {
4307
4716
  "kind": "javascript-module",
4308
4717
  "path": "src/percent-bar-chart.ts",
@@ -5066,6 +5475,20 @@
5066
5475
  "kind": "class",
5067
5476
  "description": "Generic anchored popover shell: a floating card positioned relative to its\nnearest `position: relative` ancestor (place it next to its trigger button\ninside such a wrapper), as opposed to `slide-panel`'s fixed screen-edge\ndrawer. Closes on outside click or Escape. Header chrome and close button\nmatch `slide-panel`'s API (`heading`, `panel-close`) so either can be\nswapped in for the other with no consumer-side changes beyond the wrapper.\n\nSet `centered` to render as a screen-centered modal with a translucent\nbackdrop instead of the default anchored placement.",
5068
5477
  "name": "PopoverPanel",
5478
+ "slots": [
5479
+ {
5480
+ "description": "Overrides the plain `heading` text with custom markup.",
5481
+ "name": "title"
5482
+ },
5483
+ {
5484
+ "description": "Extra header controls (e.g. an icon+label link) rendered between the title and the close button.",
5485
+ "name": "actions"
5486
+ },
5487
+ {
5488
+ "description": "Popover body content.",
5489
+ "name": ""
5490
+ }
5491
+ ],
5069
5492
  "members": [
5070
5493
  {
5071
5494
  "kind": "field",
@@ -0,0 +1,37 @@
1
+ import { LitElement, type PropertyValues } from "lit";
2
+ /** A single menu action. */
3
+ export interface DropdownOption {
4
+ value: string;
5
+ label: string;
6
+ }
7
+ /**
8
+ * A primary-styled button with a label and chevron that opens an anchored
9
+ * menu of actions — essentially `form-select` minus "current value"
10
+ * semantics: a menu, not a select. Use for a set of mutually exclusive
11
+ * next-step actions (e.g. a failed task's Retry / Close / Backlog).
12
+ *
13
+ * @element dropdown-button
14
+ * @fires select - Fired with `{ value: string }` when a menu item is picked.
15
+ */
16
+ export declare class DropdownButton extends LitElement {
17
+ #private;
18
+ static styles: import("lit").CSSResult[];
19
+ /** The trigger button's label. */
20
+ label: string;
21
+ /** The menu's actions. */
22
+ options: DropdownOption[];
23
+ /** Disables the trigger, preventing the menu from opening. */
24
+ disabled: boolean;
25
+ private _open;
26
+ private _activeIndex;
27
+ disconnectedCallback(): void;
28
+ protected updated(changed: PropertyValues): void;
29
+ private renderMenu;
30
+ render(): import("lit-html").TemplateResult<1>;
31
+ }
32
+ declare global {
33
+ interface HTMLElementTagNameMap {
34
+ "dropdown-button": DropdownButton;
35
+ }
36
+ }
37
+ //# sourceMappingURL=dropdown-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dropdown-button.d.ts","sourceRoot":"","sources":["../src/dropdown-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAK1E,4BAA4B;AAC5B,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,qBACa,cAAe,SAAQ,UAAU;;IAC5C,OAAgB,MAAM,4BAoEpB;IAEF,kCAAkC;IACtB,KAAK,SAAM;IACvB,0BAA0B;IACM,OAAO,EAAE,cAAc,EAAE,CAAM;IAC/D,8DAA8D;IACjC,QAAQ,UAAS;IAErC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAAM;IAE1B,oBAAoB,IAAI,IAAI,CAGpC;IAED,UAAmB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAQxD;IA4CD,OAAO,CAAC,UAAU;IAsBT,MAAM,yCAgBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,cAAc,CAAC;KACnC;CACF"}